mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 10:59:32 +01:00
fix(agent-inbox): review round 1
- codeman agent post: accept text that starts with "-" (markdown from a file), --json and -h stay options. - DELETE /api/sessions/:id on a persisted-only row drops the inbox a detach kept. - inbox --wait: wait.ended is exit 3 only when the session list no longer has the session; a restart or detach ending the wait is exit 2 (wait again). - A read whose client hung up during ?wait= marks nothing seen. - InboxPostSchema bound is 4x the byte cap, so every oversize message gets the store's "post a file path" answer. - Store: restore sorts oldest first; the TTL sweep checks every message, not only the first. - Docs: admins can act as any session of the receiver's owner (now tested for admin and non-admin); a peek with ?wait= does not block; exit codes. - Tests: partial PUT /api/settings keeps persistence on. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
c6dfaa2cac
commit
a1a33cf050
15 files changed
+209
-31
No files matched your search
+43
-3
@@ -714,12 +714,32 @@ describe('agent inbox verbs', () => {
|
||||
expect(deps.err.join('')).toMatch(/peek: nothing was marked seen/);
|
||||
});
|
||||
|
||||
it('inbox --wait passes the budget and maps timeout to exit 2, a vanished session to exit 3', async () => {
|
||||
it('inbox --wait passes the budget and maps timeout to exit 2', async () => {
|
||||
const timedOut = fakeDeps([ok({ receiver: true, messages: [], pending: 0, unseen: 0, wait: { timedOut: true } })]);
|
||||
expect(await agentInboxRead(timedOut, { waitMs: 30_000 })).toBe(EXIT.timeout);
|
||||
expect(timedOut.calls[0]).toMatchObject({ query: { wait: 30_000 }, timeoutMs: 40_000 });
|
||||
const ended = fakeDeps([ok({ receiver: true, messages: [], pending: 0, unseen: 0, wait: { ended: true } })]);
|
||||
expect(await agentInboxRead(ended, { waitMs: 30_000 })).toBe(EXIT.dead);
|
||||
});
|
||||
|
||||
describe('a wait the server ended', () => {
|
||||
const ended = ok({ receiver: true, messages: [], pending: 0, unseen: 0, wait: { ended: true } });
|
||||
|
||||
it('is exit 3 only when the session list confirms the session is gone', async () => {
|
||||
const deps = fakeDeps([ended, ok([{ id: OTHER }])]);
|
||||
expect(await agentInboxRead(deps, { waitMs: 30_000 })).toBe(EXIT.dead);
|
||||
expect(deps.calls[1]).toMatchObject({ method: 'GET', path: '/api/v1/sessions' });
|
||||
expect(deps.err.join('')).toMatch(/went away/);
|
||||
});
|
||||
|
||||
it('is exit 2 (wait again) while the session is still listed: a restart or detach', async () => {
|
||||
const deps = fakeDeps([ended, ok([{ id: SELF }])]);
|
||||
expect(await agentInboxRead(deps, { waitMs: 30_000 })).toBe(EXIT.timeout);
|
||||
expect(deps.err.join('')).toMatch(/ended the wait early/);
|
||||
});
|
||||
|
||||
it('is exit 2 when the list cannot be had (the server is still coming back)', async () => {
|
||||
const deps = fakeDeps([ended, apiError(503, 'INTERNAL_ERROR', 'restarting')]);
|
||||
expect(await agentInboxRead(deps, { waitMs: 30_000 })).toBe(EXIT.timeout);
|
||||
});
|
||||
});
|
||||
|
||||
it('ack posts the ids to this session’s own inbox', async () => {
|
||||
@@ -767,6 +787,26 @@ describe('help texts carry the traps the skill documents', () => {
|
||||
expect(sub('send').description()).toContain('send <id> -- "- fix the bug"');
|
||||
});
|
||||
|
||||
it('post takes text that starts with "-" (markdown from a file) without --', async () => {
|
||||
const program = new Command();
|
||||
program.exitOverride();
|
||||
const post = registerAgentCommands(program).commands.find((c) => c.name() === 'post')!;
|
||||
const got: Array<{ words: string[]; json: boolean }> = [];
|
||||
post.action((_id: string, words: string[], o: { json?: boolean }) => {
|
||||
got.push({ words, json: Boolean(o.json) });
|
||||
});
|
||||
for (const text of ['- [ ] item\nnext', '---\ntitle: a', '-v is great']) {
|
||||
await program.parseAsync(['node', 'codeman', 'agent', 'post', 'abcdefgh', text]);
|
||||
}
|
||||
await program.parseAsync(['node', 'codeman', 'agent', 'post', 'abcdefgh', 'hi', '--json']);
|
||||
expect(got).toEqual([
|
||||
{ words: ['- [ ] item\nnext'], json: false },
|
||||
{ words: ['---\ntitle: a'], json: false },
|
||||
{ words: ['-v is great'], json: false },
|
||||
{ words: ['hi'], json: true },
|
||||
]);
|
||||
});
|
||||
|
||||
it('rm does not claim a lineage check it does not make', () => {
|
||||
expect(sub('rm').description()).toMatch(/^Delete any session except this one/);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user