mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 18:59:33 +01:00
fix: apply the review items for #690 at merge
Boot prune keeps the inboxes of sessions on the reboot-restore offer (their records are already pruned and a rebuild reuses the id), with a case in test/agent-inbox-server-wiring.test.ts. docs/wiki: post, inbox and ack in the codeman agent command block of Driving-Codeman-From-An-Agent, and "Keep agent inbox across restarts" in Settings-Reference. codeman agent inbox prints message text through terminalSafeText (ANSI stripped, other C0, DEL and C1 controls shown as \xHH); --json stays as stored. Shutdown flushes the inbox snapshot again after app.close(), for a post that lands after the first flush. POST /api/cleanup-state drops the inboxes of the records it removes. InboxPostSchema derives its fence from MAX_MESSAGE_BYTES instead of the literal. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
a1a33cf050
commit
9ba24a02df
11 files changed
+150
-10
No files matched your search
@@ -65,6 +65,7 @@ import { QR_AUTH_FAILURE_MAX } from '../../config/tunnel-config.js';
|
||||
import { AUTH_SESSION_TTL_MS } from '../../config/auth-config.js';
|
||||
import { resolveTerminalHistoryConfig } from '../../config/terminal-history.js';
|
||||
import { agentInboxPersistence } from '../agent-inbox-persistence.js';
|
||||
import { agentInbox } from '../agent-inbox.js';
|
||||
|
||||
/**
|
||||
* Defaults for `POST /api/deepseek/install-profile`.
|
||||
@@ -802,6 +803,9 @@ export function registerSystemRoutes(
|
||||
const lifecycleLog = getLifecycleLog();
|
||||
for (const s of result.cleaned) {
|
||||
lifecycleLog.log({ event: 'stale_cleaned', sessionId: s.id, name: s.name });
|
||||
// A detached session kept its agent inbox; removing its record is the delete,
|
||||
// so the mail goes with it (as on the persisted-only DELETE /api/sessions/:id).
|
||||
agentInbox.drop(s.id);
|
||||
}
|
||||
return { cleanedSessions: result.count };
|
||||
});
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ import { WEBHOOK_KINDS, WEBHOOK_SCOPES } from '../types/push.js';
|
||||
import { MIN_MATCH_LENGTH, MAX_MATCH_LENGTH } from '../config/agent-wait.js';
|
||||
import { MAX_WAKE_MACS } from '../config/remote-wake-limits.js';
|
||||
import { MAX_INPUT_LENGTH } from '../config/terminal-limits.js';
|
||||
import { MAX_MESSAGE_BYTES } from './agent-inbox.js';
|
||||
import { enabledCliIds, enabledClis } from '../config/cli-registry/registry.js';
|
||||
import type { SessionMode } from '../types.js';
|
||||
import { isAdvisorModel } from '../types/session.js';
|
||||
@@ -1857,7 +1858,7 @@ export const InboxPostSchema = z
|
||||
text: z
|
||||
.string()
|
||||
.min(1, 'text must not be empty')
|
||||
.max(4 * 16_384),
|
||||
.max(4 * MAX_MESSAGE_BYTES),
|
||||
})
|
||||
.strict();
|
||||
|
||||
|
||||
+18
-4
@@ -4036,8 +4036,15 @@ export class WebServer extends EventEmitter {
|
||||
// Same gate as the tab layouts: only a restore that succeeded may decide which
|
||||
// inboxes are orphans. A failed one returns above and leaves every message alone.
|
||||
// Kept: live sessions plus every record state.json still holds (a session that
|
||||
// was not re-adopted this boot but is kept for recovery keeps its mail).
|
||||
const keep = new Set([...this.sessions.keys(), ...Object.keys(this.store.getSessions())]);
|
||||
// was not re-adopted this boot but is kept for recovery keeps its mail), plus the
|
||||
// sessions on the reboot-restore offer. `cleanupStaleSessions()` above has already
|
||||
// pruned their records, and a rebuild reuses the old id, so without them a restored
|
||||
// session would come back to an empty inbox. The 12 h TTL bounds what is never rebuilt.
|
||||
const keep = new Set([
|
||||
...this.sessions.keys(),
|
||||
...Object.keys(this.store.getSessions()),
|
||||
...rebootRestoreRegistry.list(() => true).map((entry) => entry.sessionId),
|
||||
]);
|
||||
const pruned = agentInbox.pruneExcept(keep);
|
||||
if (pruned > 0) console.log(`[AgentInbox] dropped ${pruned} inbox(es) of sessions that did not come back`);
|
||||
}
|
||||
@@ -4217,9 +4224,10 @@ export class WebServer extends EventEmitter {
|
||||
approvalInbox.stop();
|
||||
this.keepWarmService.stop();
|
||||
// A post within the debounce window before shutdown would otherwise not reach disk.
|
||||
// Flushed again after `app.close()` below, for a post that lands in between.
|
||||
agentInboxPersistence.flush();
|
||||
// Same reason as `cancelEverything` above: an in-flight wake is awaited by a request,
|
||||
// and `app.close()` (the last line of this method) does not abort in-flight requests —
|
||||
// and `app.close()` (at the end of this method) does not abort in-flight requests,
|
||||
// so without this a restart during a wake waits out the readiness poll.
|
||||
this.remoteWake?.stop();
|
||||
|
||||
@@ -4360,7 +4368,13 @@ export class WebServer extends EventEmitter {
|
||||
// Dispose push store (flush pending saves)
|
||||
this.pushStore.dispose();
|
||||
|
||||
await this.app.close();
|
||||
try {
|
||||
await this.app.close();
|
||||
} finally {
|
||||
// The routes answer until `app.close()` returns, so a post after the flush above
|
||||
// would otherwise sit in an unref'd debounce timer and never reach disk.
|
||||
agentInboxPersistence.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user