@ai-devkit/agent-manager 0.28.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +1 -342
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +343 -0
- package/dist/__tests__/capacity/codex.test.js.map +1 -0
- package/dist/__tests__/capacity/index.test.js +50 -0
- package/dist/__tests__/capacity/index.test.js.map +1 -0
- package/dist/__tests__/database/DurableAgentsDatabase.test.js +31 -3
- package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +1 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js +129 -0
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -0
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +84 -0
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +126 -0
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintAgentService.test.js +271 -0
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/durable/CodexPrintRunner.test.js +393 -0
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -0
- package/dist/__tests__/print/ClaudeCliProbe.test.js +3 -7
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +33 -27
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +65 -0
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +4 -10
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +79 -0
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +436 -0
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +76 -0
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +43 -0
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +202 -0
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +119 -0
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +386 -0
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -0
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +34 -0
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -0
- package/dist/__tests__/utils/ClaudeSessionParser.test.js +2 -2
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/capacity/codex.d.ts +36 -0
- package/dist/capacity/codex.d.ts.map +1 -0
- package/dist/capacity/codex.js +317 -0
- package/dist/capacity/codex.js.map +1 -0
- package/dist/capacity/index.d.ts +11 -0
- package/dist/capacity/index.d.ts.map +1 -0
- package/dist/capacity/index.js +49 -0
- package/dist/capacity/index.js.map +1 -0
- package/dist/capacity/types.d.ts +17 -0
- package/dist/capacity/types.d.ts.map +1 -0
- package/dist/capacity/types.js +3 -0
- package/dist/capacity/types.js.map +1 -0
- package/dist/database/migrations/004_codex_durable_sessions.sql +1 -0
- package/dist/durable/DurableAgent.d.ts +23 -3
- package/dist/durable/DurableAgent.d.ts.map +1 -1
- package/dist/durable/DurableAgent.js +12 -0
- package/dist/durable/DurableAgent.js.map +1 -1
- package/dist/durable/DurableAgentRepository.d.ts +6 -7
- package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
- package/dist/durable/DurableAgentRepository.js +73 -42
- package/dist/durable/DurableAgentRepository.js.map +1 -1
- package/dist/durable/process.d.ts +8 -0
- package/dist/durable/process.d.ts.map +1 -0
- package/dist/durable/process.js +40 -0
- package/dist/durable/process.js.map +1 -0
- package/dist/durable/run.d.ts +32 -0
- package/dist/durable/run.d.ts.map +1 -0
- package/dist/durable/run.js +46 -0
- package/dist/durable/run.js.map +1 -0
- package/dist/durable/utils.d.ts +19 -0
- package/dist/durable/utils.d.ts.map +1 -0
- package/dist/durable/utils.js +52 -0
- package/dist/durable/utils.js.map +1 -0
- package/dist/index.d.ts +19 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -8
- package/dist/index.js.map +1 -1
- package/dist/providers/claude/ClaudeAgentMapper.d.ts +21 -0
- package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -0
- package/dist/providers/claude/ClaudeAgentMapper.js +42 -0
- package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -0
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts +29 -0
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -0
- package/dist/providers/claude/ClaudeCodeAdapter.js +129 -0
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -0
- package/dist/{adapters/ClaudeCodeAdapter.d.ts → providers/claude/ClaudeSessionLocator.d.ts} +68 -52
- package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -0
- package/dist/{adapters/ClaudeCodeAdapter.js → providers/claude/ClaudeSessionLocator.js} +71 -189
- package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -0
- package/dist/{utils → providers/claude}/ClaudeSessionParser.d.ts +2 -2
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -0
- package/dist/{utils → providers/claude}/ClaudeSessionParser.js +1 -1
- package/dist/providers/claude/ClaudeSessionParser.js.map +1 -0
- package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudeCliProbe.js +4 -9
- package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudePrintAgentService.d.ts +4 -9
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudePrintAgentService.js +45 -0
- package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -0
- package/dist/{durable → providers/claude/durable}/ClaudePrintRunner.d.ts +3 -3
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudePrintRunner.js +75 -0
- package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +17 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.js +69 -0
- package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts +20 -0
- package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexCliProbe.js +61 -0
- package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +40 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.js +50 -0
- package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -0
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts +34 -0
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexPrintRunner.js +78 -0
- package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -0
- package/dist/providers/codex/durable/CodexStreamParser.d.ts +21 -0
- package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -0
- package/dist/providers/codex/durable/CodexStreamParser.js +86 -0
- package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts +20 -0
- package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiCliProbe.js +51 -0
- package/dist/providers/pi/durable/PiCliProbe.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts +39 -0
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintAgentService.js +47 -0
- package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts +4 -0
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintProtocol.js +44 -0
- package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -0
- package/dist/providers/pi/durable/PiPrintRunner.d.ts +32 -0
- package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiPrintRunner.js +61 -0
- package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -0
- package/dist/providers/pi/durable/PiStreamParser.d.ts +21 -0
- package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -0
- package/dist/providers/pi/durable/PiStreamParser.js +71 -0
- package/dist/providers/pi/durable/PiStreamParser.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1 -307
- package/src/__tests__/capacity/codex.test.ts +184 -0
- package/src/__tests__/capacity/index.test.ts +38 -0
- package/src/__tests__/database/DurableAgentsDatabase.test.ts +28 -3
- package/src/__tests__/durable/CodexCliProbe.test.ts +63 -0
- package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +54 -0
- package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +79 -0
- package/src/__tests__/durable/CodexPrintAgentService.test.ts +139 -0
- package/src/__tests__/durable/CodexPrintRunner.test.ts +189 -0
- package/src/__tests__/fixtures/fake-codex.cjs +45 -0
- package/src/__tests__/print/ClaudeCliProbe.test.ts +3 -7
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +19 -22
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +33 -1
- package/src/__tests__/print/ClaudePrintRunner.test.ts +4 -10
- package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +84 -0
- package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +411 -0
- package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +38 -0
- package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +32 -0
- package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +69 -0
- package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +33 -0
- package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +107 -0
- package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +24 -0
- package/src/__tests__/utils/ClaudeSessionParser.test.ts +2 -2
- package/src/adapters/index.ts +1 -1
- package/src/capacity/codex.ts +320 -0
- package/src/capacity/index.ts +57 -0
- package/src/capacity/types.ts +18 -0
- package/src/database/migrations/004_codex_durable_sessions.sql +1 -0
- package/src/durable/DurableAgent.ts +51 -3
- package/src/durable/DurableAgentRepository.ts +60 -31
- package/src/durable/process.ts +28 -0
- package/src/durable/run.ts +74 -0
- package/src/durable/utils.ts +61 -0
- package/src/index.ts +37 -15
- package/src/providers/claude/ClaudeAgentMapper.ts +62 -0
- package/src/providers/claude/ClaudeCodeAdapter.ts +160 -0
- package/src/{adapters/ClaudeCodeAdapter.ts → providers/claude/ClaudeSessionLocator.ts} +97 -239
- package/src/{utils → providers/claude}/ClaudeSessionParser.ts +2 -2
- package/src/{durable → providers/claude/durable}/ClaudeCliProbe.ts +4 -10
- package/src/providers/claude/durable/ClaudePrintAgentService.ts +66 -0
- package/src/providers/claude/durable/ClaudePrintRunner.ts +92 -0
- package/src/providers/claude/durable/ClaudeStreamParser.ts +79 -0
- package/src/providers/codex/durable/CodexCliProbe.ts +60 -0
- package/src/providers/codex/durable/CodexPrintAgentService.ts +65 -0
- package/src/providers/codex/durable/CodexPrintRunner.ts +94 -0
- package/src/providers/codex/durable/CodexStreamParser.ts +104 -0
- package/src/providers/pi/durable/PiCliProbe.ts +48 -0
- package/src/providers/pi/durable/PiPrintAgentService.ts +69 -0
- package/src/providers/pi/durable/PiPrintProtocol.ts +39 -0
- package/src/providers/pi/durable/PiPrintRunner.ts +88 -0
- package/src/providers/pi/durable/PiStreamParser.ts +84 -0
- package/dist/adapters/ClaudeCodeAdapter.d.ts.map +0 -1
- package/dist/adapters/ClaudeCodeAdapter.js.map +0 -1
- package/dist/durable/ClaudeCliProbe.d.ts.map +0 -1
- package/dist/durable/ClaudeCliProbe.js.map +0 -1
- package/dist/durable/ClaudePrintAgentService.d.ts.map +0 -1
- package/dist/durable/ClaudePrintAgentService.js +0 -66
- package/dist/durable/ClaudePrintAgentService.js.map +0 -1
- package/dist/durable/ClaudePrintRunner.d.ts.map +0 -1
- package/dist/durable/ClaudePrintRunner.js +0 -128
- package/dist/durable/ClaudePrintRunner.js.map +0 -1
- package/dist/utils/ClaudeSessionParser.d.ts.map +0 -1
- package/dist/utils/ClaudeSessionParser.js.map +0 -1
- package/src/durable/ClaudePrintAgentService.ts +0 -94
- package/src/durable/ClaudePrintRunner.ts +0 -139
- /package/dist/{durable → providers/claude/durable}/ClaudeCliProbe.d.ts +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
describe('CodexCliProbe', ()=>{
|
|
3
|
+
it('validates version, exec JSON/stdin, and resume capabilities without a model call', async ()=>{
|
|
4
|
+
const api = await import('../../index.js');
|
|
5
|
+
expect(api).toHaveProperty('CodexCliProbe');
|
|
6
|
+
const exec = vi.fn().mockResolvedValueOnce({
|
|
7
|
+
stdout: 'codex-cli 0.147.0',
|
|
8
|
+
stderr: ''
|
|
9
|
+
}).mockResolvedValueOnce({
|
|
10
|
+
stdout: 'Usage: codex exec [PROMPT]\n--json\n- read from stdin\nresume',
|
|
11
|
+
stderr: ''
|
|
12
|
+
}).mockResolvedValueOnce({
|
|
13
|
+
stdout: 'Usage: codex exec resume [SESSION_ID] [PROMPT]\n--json\n- stdin',
|
|
14
|
+
stderr: ''
|
|
15
|
+
});
|
|
16
|
+
const Probe = api.CodexCliProbe;
|
|
17
|
+
await expect(new Probe({
|
|
18
|
+
executable: 'fake-codex',
|
|
19
|
+
exec
|
|
20
|
+
}).validate()).resolves.toEqual({
|
|
21
|
+
executable: 'fake-codex',
|
|
22
|
+
version: 'codex-cli 0.147.0'
|
|
23
|
+
});
|
|
24
|
+
expect(exec.mock.calls).toEqual([
|
|
25
|
+
[
|
|
26
|
+
'fake-codex',
|
|
27
|
+
[
|
|
28
|
+
'--version'
|
|
29
|
+
]
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
'fake-codex',
|
|
33
|
+
[
|
|
34
|
+
'exec',
|
|
35
|
+
'--help'
|
|
36
|
+
]
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
'fake-codex',
|
|
40
|
+
[
|
|
41
|
+
'exec',
|
|
42
|
+
'resume',
|
|
43
|
+
'--help'
|
|
44
|
+
]
|
|
45
|
+
]
|
|
46
|
+
]);
|
|
47
|
+
});
|
|
48
|
+
it('rejects unsupported and unavailable CLIs with bounded sanitized errors', async ()=>{
|
|
49
|
+
const api = await import('../../index.js');
|
|
50
|
+
const Probe = api.CodexCliProbe;
|
|
51
|
+
const unsupported = new Probe({
|
|
52
|
+
exec: vi.fn().mockResolvedValueOnce({
|
|
53
|
+
stdout: 'version',
|
|
54
|
+
stderr: ''
|
|
55
|
+
}).mockResolvedValueOnce({
|
|
56
|
+
stdout: 'exec',
|
|
57
|
+
stderr: ''
|
|
58
|
+
}).mockResolvedValueOnce({
|
|
59
|
+
stdout: 'resume',
|
|
60
|
+
stderr: ''
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
await expect(unsupported.validate()).rejects.toMatchObject({
|
|
64
|
+
code: 'CODEX_CLI_UNSUPPORTED'
|
|
65
|
+
});
|
|
66
|
+
const missingCommands = new Probe({
|
|
67
|
+
exec: vi.fn().mockResolvedValueOnce({
|
|
68
|
+
stdout: 'version',
|
|
69
|
+
stderr: ''
|
|
70
|
+
}).mockResolvedValueOnce({
|
|
71
|
+
stdout: '',
|
|
72
|
+
stderr: ''
|
|
73
|
+
}).mockResolvedValueOnce({
|
|
74
|
+
stdout: '',
|
|
75
|
+
stderr: ''
|
|
76
|
+
})
|
|
77
|
+
});
|
|
78
|
+
await expect(missingCommands.validate()).rejects.toMatchObject({
|
|
79
|
+
code: 'CODEX_CLI_UNSUPPORTED'
|
|
80
|
+
});
|
|
81
|
+
const unavailable = new Probe({
|
|
82
|
+
exec: vi.fn().mockRejectedValue(new Error(`bad\0${'x'.repeat(1000)}`))
|
|
83
|
+
});
|
|
84
|
+
const error = await unavailable.validate().catch((value)=>value);
|
|
85
|
+
expect(error.code).toBe('CODEX_CLI_UNAVAILABLE');
|
|
86
|
+
expect(error.message).not.toContain('\0');
|
|
87
|
+
expect(error.message.length).toBeLessThan(600);
|
|
88
|
+
});
|
|
89
|
+
it('reports an empty version response as unknown', async ()=>{
|
|
90
|
+
const api = await import('../../index.js');
|
|
91
|
+
const Probe = api.CodexCliProbe;
|
|
92
|
+
const exec = vi.fn().mockResolvedValueOnce({
|
|
93
|
+
stdout: ' \n',
|
|
94
|
+
stderr: ''
|
|
95
|
+
}).mockResolvedValueOnce({
|
|
96
|
+
stdout: 'exec --json -',
|
|
97
|
+
stderr: ''
|
|
98
|
+
}).mockResolvedValueOnce({
|
|
99
|
+
stdout: 'resume --json -',
|
|
100
|
+
stderr: ''
|
|
101
|
+
});
|
|
102
|
+
await expect(new Probe({
|
|
103
|
+
exec
|
|
104
|
+
}).validate()).resolves.toMatchObject({
|
|
105
|
+
version: 'unknown'
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
it('requires a standalone stdin dash rather than accepting flag hyphens', async ()=>{
|
|
109
|
+
const api = await import('../../index.js');
|
|
110
|
+
const Probe = api.CodexCliProbe;
|
|
111
|
+
const exec = vi.fn().mockResolvedValueOnce({
|
|
112
|
+
stdout: 'version',
|
|
113
|
+
stderr: ''
|
|
114
|
+
}).mockResolvedValueOnce({
|
|
115
|
+
stdout: 'exec --json',
|
|
116
|
+
stderr: ''
|
|
117
|
+
}).mockResolvedValueOnce({
|
|
118
|
+
stdout: 'resume --json',
|
|
119
|
+
stderr: ''
|
|
120
|
+
});
|
|
121
|
+
await expect(new Probe({
|
|
122
|
+
exec
|
|
123
|
+
}).validate()).rejects.toMatchObject({
|
|
124
|
+
code: 'CODEX_CLI_UNSUPPORTED'
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=CodexCliProbe.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/durable/CodexCliProbe.test.ts"],"sourcesContent":["import { describe, expect, it, vi } from 'vitest';\n\ndescribe('CodexCliProbe', () => {\n it('validates version, exec JSON/stdin, and resume capabilities without a model call', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n expect(api).toHaveProperty('CodexCliProbe');\n const exec = vi.fn()\n .mockResolvedValueOnce({ stdout: 'codex-cli 0.147.0', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'Usage: codex exec [PROMPT]\\n--json\\n- read from stdin\\nresume', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'Usage: codex exec resume [SESSION_ID] [PROMPT]\\n--json\\n- stdin', stderr: '' });\n const Probe = api.CodexCliProbe as new (options: unknown) => any;\n\n await expect(new Probe({ executable: 'fake-codex', exec }).validate()).resolves.toEqual({\n executable: 'fake-codex', version: 'codex-cli 0.147.0',\n });\n expect(exec.mock.calls).toEqual([\n ['fake-codex', ['--version']],\n ['fake-codex', ['exec', '--help']],\n ['fake-codex', ['exec', 'resume', '--help']],\n ]);\n });\n\n it('rejects unsupported and unavailable CLIs with bounded sanitized errors', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const Probe = api.CodexCliProbe as new (options: unknown) => any;\n const unsupported = new Probe({ exec: vi.fn()\n .mockResolvedValueOnce({ stdout: 'version', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'exec', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'resume', stderr: '' }) });\n await expect(unsupported.validate()).rejects.toMatchObject({ code: 'CODEX_CLI_UNSUPPORTED' });\n const missingCommands = new Probe({ exec: vi.fn()\n .mockResolvedValueOnce({ stdout: 'version', stderr: '' })\n .mockResolvedValueOnce({ stdout: '', stderr: '' })\n .mockResolvedValueOnce({ stdout: '', stderr: '' }) });\n await expect(missingCommands.validate()).rejects.toMatchObject({ code: 'CODEX_CLI_UNSUPPORTED' });\n\n const unavailable = new Probe({ exec: vi.fn().mockRejectedValue(new Error(`bad\\0${'x'.repeat(1000)}`)) });\n const error = await unavailable.validate().catch((value: Error & { code: string }) => value);\n expect(error.code).toBe('CODEX_CLI_UNAVAILABLE');\n expect(error.message).not.toContain('\\0');\n expect(error.message.length).toBeLessThan(600);\n });\n\n it('reports an empty version response as unknown', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const Probe = api.CodexCliProbe as new (options: unknown) => any;\n const exec = vi.fn()\n .mockResolvedValueOnce({ stdout: ' \\n', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'exec --json -', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'resume --json -', stderr: '' });\n await expect(new Probe({ exec }).validate()).resolves.toMatchObject({ version: 'unknown' });\n });\n\n it('requires a standalone stdin dash rather than accepting flag hyphens', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const Probe = api.CodexCliProbe as new (options: unknown) => any;\n const exec = vi.fn()\n .mockResolvedValueOnce({ stdout: 'version', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'exec --json', stderr: '' })\n .mockResolvedValueOnce({ stdout: 'resume --json', stderr: '' });\n await expect(new Probe({ exec }).validate()).rejects.toMatchObject({ code: 'CODEX_CLI_UNSUPPORTED' });\n });\n});\n"],"names":["describe","expect","it","vi","api","toHaveProperty","exec","fn","mockResolvedValueOnce","stdout","stderr","Probe","CodexCliProbe","executable","validate","resolves","toEqual","version","mock","calls","unsupported","rejects","toMatchObject","code","missingCommands","unavailable","mockRejectedValue","Error","repeat","error","catch","value","toBe","message","not","toContain","length","toBeLessThan"],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { DurableAgentRepository } from '../../durable/DurableAgentRepository.js';
|
|
6
|
+
const SESSION = '22222222-2222-4222-8222-222222222222';
|
|
7
|
+
const OTHER_SESSION = '33333333-3333-4333-8333-333333333333';
|
|
8
|
+
const roots = [];
|
|
9
|
+
afterEach(()=>{
|
|
10
|
+
for (const root of roots.splice(0))fs.rmSync(root, {
|
|
11
|
+
recursive: true,
|
|
12
|
+
force: true
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
function fixture() {
|
|
16
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-durable-repository-'));
|
|
17
|
+
roots.push(root);
|
|
18
|
+
const cwd = path.join(root, 'project');
|
|
19
|
+
fs.mkdirSync(cwd);
|
|
20
|
+
const processInspector = {
|
|
21
|
+
getIdentity: (pid)=>({
|
|
22
|
+
pid,
|
|
23
|
+
startedAt: 'owner-start'
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
cwd,
|
|
28
|
+
repository: new DurableAgentRepository({
|
|
29
|
+
dbPath: path.join(root, 'agents.db'),
|
|
30
|
+
processInspector
|
|
31
|
+
})
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
describe('Codex durable-agent repository binding', ()=>{
|
|
35
|
+
it('creates Codex agents unbound and binds during the owned run', async ()=>{
|
|
36
|
+
const { cwd, repository } = fixture();
|
|
37
|
+
const agent = await repository.create({
|
|
38
|
+
name: 'reviewer',
|
|
39
|
+
cwd,
|
|
40
|
+
provider: 'codex'
|
|
41
|
+
});
|
|
42
|
+
expect(agent).toMatchObject({
|
|
43
|
+
provider: 'codex',
|
|
44
|
+
mode: 'durable',
|
|
45
|
+
providerSessionId: null
|
|
46
|
+
});
|
|
47
|
+
const run = await repository.acquireRun(agent.id);
|
|
48
|
+
const bound = await repository.bindProviderSession(agent.id, run.token, SESSION);
|
|
49
|
+
expect(bound.providerSessionId).toBe(SESSION);
|
|
50
|
+
await expect(repository.bindProviderSession(agent.id, run.token, SESSION)).resolves.toMatchObject({
|
|
51
|
+
providerSessionId: SESSION
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
it('rejects invalid, stale, replacement, and duplicate bindings', async ()=>{
|
|
55
|
+
const { cwd, repository } = fixture();
|
|
56
|
+
const first = await repository.create({
|
|
57
|
+
name: 'first',
|
|
58
|
+
cwd,
|
|
59
|
+
provider: 'codex'
|
|
60
|
+
});
|
|
61
|
+
const second = await repository.create({
|
|
62
|
+
name: 'second',
|
|
63
|
+
cwd,
|
|
64
|
+
provider: 'codex'
|
|
65
|
+
});
|
|
66
|
+
const firstRun = await repository.acquireRun(first.id);
|
|
67
|
+
const secondRun = await repository.acquireRun(second.id);
|
|
68
|
+
await expect(repository.bindProviderSession(first.id, 'stale', SESSION)).rejects.toMatchObject({
|
|
69
|
+
code: 'DURABLE_AGENT_REPOSITORY'
|
|
70
|
+
});
|
|
71
|
+
await expect(repository.bindProviderSession(first.id, firstRun.token, 'invalid')).rejects.toMatchObject({
|
|
72
|
+
code: 'DURABLE_AGENT_REPOSITORY'
|
|
73
|
+
});
|
|
74
|
+
await repository.bindProviderSession(first.id, firstRun.token, SESSION);
|
|
75
|
+
await expect(repository.bindProviderSession(first.id, firstRun.token, OTHER_SESSION)).rejects.toMatchObject({
|
|
76
|
+
code: 'CODEX_SESSION_MISMATCH'
|
|
77
|
+
});
|
|
78
|
+
await expect(repository.bindProviderSession(second.id, secondRun.token, SESSION)).rejects.toMatchObject({
|
|
79
|
+
code: 'CODEX_SESSION_MISMATCH'
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=CodexDurableAgentRepository.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/durable/CodexDurableAgentRepository.test.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { afterEach, describe, expect, it } from 'vitest';\nimport { DurableAgentRepository } from '../../durable/DurableAgentRepository.js';\n\nconst SESSION = '22222222-2222-4222-8222-222222222222';\nconst OTHER_SESSION = '33333333-3333-4333-8333-333333333333';\nconst roots: string[] = [];\n\nafterEach(() => {\n for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });\n});\n\nfunction fixture() {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-durable-repository-'));\n roots.push(root);\n const cwd = path.join(root, 'project');\n fs.mkdirSync(cwd);\n const processInspector = { getIdentity: (pid: number) => ({ pid, startedAt: 'owner-start' }) };\n return { cwd, repository: new DurableAgentRepository({ dbPath: path.join(root, 'agents.db'), processInspector }) };\n}\n\ndescribe('Codex durable-agent repository binding', () => {\n it('creates Codex agents unbound and binds during the owned run', async () => {\n const { cwd, repository } = fixture();\n const agent = await repository.create({ name: 'reviewer', cwd, provider: 'codex' });\n expect(agent).toMatchObject({ provider: 'codex', mode: 'durable', providerSessionId: null });\n\n const run = await repository.acquireRun(agent.id);\n const bound = await repository.bindProviderSession(agent.id, run.token, SESSION);\n expect(bound.providerSessionId).toBe(SESSION);\n await expect(repository.bindProviderSession(agent.id, run.token, SESSION))\n .resolves.toMatchObject({ providerSessionId: SESSION });\n });\n\n it('rejects invalid, stale, replacement, and duplicate bindings', async () => {\n const { cwd, repository } = fixture();\n const first = await repository.create({ name: 'first', cwd, provider: 'codex' });\n const second = await repository.create({ name: 'second', cwd, provider: 'codex' });\n const firstRun = await repository.acquireRun(first.id);\n const secondRun = await repository.acquireRun(second.id);\n\n await expect(repository.bindProviderSession(first.id, 'stale', SESSION))\n .rejects.toMatchObject({ code: 'DURABLE_AGENT_REPOSITORY' });\n await expect(repository.bindProviderSession(first.id, firstRun.token, 'invalid'))\n .rejects.toMatchObject({ code: 'DURABLE_AGENT_REPOSITORY' });\n await repository.bindProviderSession(first.id, firstRun.token, SESSION);\n await expect(repository.bindProviderSession(first.id, firstRun.token, OTHER_SESSION))\n .rejects.toMatchObject({ code: 'CODEX_SESSION_MISMATCH' });\n await expect(repository.bindProviderSession(second.id, secondRun.token, SESSION))\n .rejects.toMatchObject({ code: 'CODEX_SESSION_MISMATCH' });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","DurableAgentRepository","SESSION","OTHER_SESSION","roots","root","splice","rmSync","recursive","force","fixture","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","processInspector","getIdentity","pid","startedAt","repository","dbPath","agent","create","name","provider","toMatchObject","mode","providerSessionId","run","acquireRun","id","bound","bindProviderSession","token","toBe","resolves","first","second","firstRun","secondRun","rejects","code"],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { CodexPrintError, CodexPrintAgentService, DurableAgentRepository } from '../../index.js';
|
|
6
|
+
const SESSION = '22222222-2222-4222-8222-222222222222';
|
|
7
|
+
const roots = [];
|
|
8
|
+
afterEach(()=>{
|
|
9
|
+
for (const root of roots.splice(0))fs.rmSync(root, {
|
|
10
|
+
recursive: true,
|
|
11
|
+
force: true
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe('Codex print-agent fake-provider journey', ()=>{
|
|
15
|
+
it('creates unbound, then binds and explicitly resumes the provider-minted session', async ()=>{
|
|
16
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-print-integration-'));
|
|
17
|
+
roots.push(root);
|
|
18
|
+
const cwd = path.join(root, 'project');
|
|
19
|
+
fs.mkdirSync(cwd);
|
|
20
|
+
const processInspector = {
|
|
21
|
+
getIdentity: (pid)=>({
|
|
22
|
+
pid,
|
|
23
|
+
startedAt: `process-${pid}`
|
|
24
|
+
})
|
|
25
|
+
};
|
|
26
|
+
const repository = new DurableAgentRepository({
|
|
27
|
+
dbPath: path.join(root, 'agents.db'),
|
|
28
|
+
processInspector
|
|
29
|
+
});
|
|
30
|
+
const runner = {
|
|
31
|
+
run: vi.fn().mockImplementation(async (request)=>{
|
|
32
|
+
await request.onSpawn({
|
|
33
|
+
pid: 42,
|
|
34
|
+
startedAt: 'process-42'
|
|
35
|
+
});
|
|
36
|
+
await request.onSession(SESSION);
|
|
37
|
+
return {
|
|
38
|
+
sessionId: SESSION,
|
|
39
|
+
result: `answer:${request.prompt}`,
|
|
40
|
+
messages: [
|
|
41
|
+
`answer:${request.prompt}`
|
|
42
|
+
],
|
|
43
|
+
exitCode: 0
|
|
44
|
+
};
|
|
45
|
+
})
|
|
46
|
+
};
|
|
47
|
+
const service = new CodexPrintAgentService({
|
|
48
|
+
repository,
|
|
49
|
+
probe: {
|
|
50
|
+
validate: vi.fn()
|
|
51
|
+
},
|
|
52
|
+
runner
|
|
53
|
+
});
|
|
54
|
+
const created = await service.create({
|
|
55
|
+
name: 'reviewer',
|
|
56
|
+
cwd
|
|
57
|
+
});
|
|
58
|
+
expect(created).toMatchObject({
|
|
59
|
+
provider: 'codex',
|
|
60
|
+
providerSessionId: null,
|
|
61
|
+
sessionHealth: 'uninitialized'
|
|
62
|
+
});
|
|
63
|
+
const first = await service.send(created.id, 'first secret');
|
|
64
|
+
expect(first).toMatchObject({
|
|
65
|
+
result: 'answer:first secret'
|
|
66
|
+
});
|
|
67
|
+
const bound = await repository.getById(created.id);
|
|
68
|
+
expect(bound?.providerSessionId).toBe(first.sessionId);
|
|
69
|
+
await expect(service.send(created.id, 'follow up')).resolves.toMatchObject({
|
|
70
|
+
result: 'answer:follow up'
|
|
71
|
+
});
|
|
72
|
+
expect(runner.run.mock.calls[0][0].agent).toMatchObject({
|
|
73
|
+
providerSessionId: null
|
|
74
|
+
});
|
|
75
|
+
expect(runner.run.mock.calls[1][0].agent).toMatchObject({
|
|
76
|
+
providerSessionId: SESSION
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it('retains a first-run binding when the provider fails after thread start', async ()=>{
|
|
80
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-print-bind-failure-'));
|
|
81
|
+
roots.push(root);
|
|
82
|
+
const cwd = path.join(root, 'project');
|
|
83
|
+
fs.mkdirSync(cwd);
|
|
84
|
+
const processInspector = {
|
|
85
|
+
getIdentity: (pid)=>({
|
|
86
|
+
pid,
|
|
87
|
+
startedAt: `process-${pid}`
|
|
88
|
+
})
|
|
89
|
+
};
|
|
90
|
+
const repository = new DurableAgentRepository({
|
|
91
|
+
dbPath: path.join(root, 'agents.db'),
|
|
92
|
+
processInspector
|
|
93
|
+
});
|
|
94
|
+
const runner = {
|
|
95
|
+
run: vi.fn().mockImplementation(async (request)=>{
|
|
96
|
+
await request.onSpawn({
|
|
97
|
+
pid: 42,
|
|
98
|
+
startedAt: 'process-42'
|
|
99
|
+
});
|
|
100
|
+
await request.onSession(SESSION);
|
|
101
|
+
throw new CodexPrintError('Codex print run failed.', 'CODEX_PROCESS');
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
const service = new CodexPrintAgentService({
|
|
105
|
+
repository,
|
|
106
|
+
probe: {
|
|
107
|
+
validate: vi.fn()
|
|
108
|
+
},
|
|
109
|
+
runner
|
|
110
|
+
});
|
|
111
|
+
const created = await service.create({
|
|
112
|
+
name: 'reviewer',
|
|
113
|
+
cwd
|
|
114
|
+
});
|
|
115
|
+
await expect(service.send(created.id, 'secret')).rejects.toMatchObject({
|
|
116
|
+
code: 'CODEX_PROCESS'
|
|
117
|
+
});
|
|
118
|
+
expect(await repository.getById(created.id)).toMatchObject({
|
|
119
|
+
providerSessionId: SESSION,
|
|
120
|
+
state: 'degraded',
|
|
121
|
+
sessionHealth: 'unknown'
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
//# sourceMappingURL=CodexPrintAgent.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/durable/CodexPrintAgent.integration.test.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { afterEach, describe, expect, it, vi } from 'vitest';\nimport {\n CodexPrintError,\n CodexPrintAgentService,\n DurableAgentRepository,\n type ProcessInspector,\n} from '../../index.js';\n\nconst SESSION = '22222222-2222-4222-8222-222222222222';\nconst roots: string[] = [];\n\nafterEach(() => {\n for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });\n});\n\ndescribe('Codex print-agent fake-provider journey', () => {\n it('creates unbound, then binds and explicitly resumes the provider-minted session', async () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-print-integration-'));\n roots.push(root);\n const cwd = path.join(root, 'project');\n fs.mkdirSync(cwd);\n const processInspector: ProcessInspector = {\n getIdentity: (pid) => ({ pid, startedAt: `process-${pid}` }),\n };\n const repository = new DurableAgentRepository({ dbPath: path.join(root, 'agents.db'), processInspector });\n const runner = {\n run: vi.fn().mockImplementation(async (request) => {\n await request.onSpawn({ pid: 42, startedAt: 'process-42' });\n await request.onSession(SESSION);\n return { sessionId: SESSION, result: `answer:${request.prompt}`, messages: [`answer:${request.prompt}`], exitCode: 0 };\n }),\n };\n const service = new CodexPrintAgentService({\n repository, probe: { validate: vi.fn() }, runner,\n });\n\n const created = await service.create({ name: 'reviewer', cwd });\n expect(created).toMatchObject({ provider: 'codex', providerSessionId: null, sessionHealth: 'uninitialized' });\n\n const first = await service.send(created.id, 'first secret');\n expect(first).toMatchObject({ result: 'answer:first secret' });\n const bound = await repository.getById(created.id);\n expect(bound?.providerSessionId).toBe(first.sessionId);\n await expect(service.send(created.id, 'follow up')).resolves.toMatchObject({ result: 'answer:follow up' });\n\n expect(runner.run.mock.calls[0][0].agent).toMatchObject({ providerSessionId: null });\n expect(runner.run.mock.calls[1][0].agent).toMatchObject({ providerSessionId: SESSION });\n });\n\n it('retains a first-run binding when the provider fails after thread start', async () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'codex-print-bind-failure-'));\n roots.push(root);\n const cwd = path.join(root, 'project');\n fs.mkdirSync(cwd);\n const processInspector: ProcessInspector = {\n getIdentity: (pid) => ({ pid, startedAt: `process-${pid}` }),\n };\n const repository = new DurableAgentRepository({ dbPath: path.join(root, 'agents.db'), processInspector });\n const runner = {\n run: vi.fn().mockImplementation(async (request) => {\n await request.onSpawn({ pid: 42, startedAt: 'process-42' });\n await request.onSession(SESSION);\n throw new CodexPrintError('Codex print run failed.', 'CODEX_PROCESS');\n }),\n };\n const service = new CodexPrintAgentService({\n repository, probe: { validate: vi.fn() }, runner,\n });\n const created = await service.create({ name: 'reviewer', cwd });\n\n await expect(service.send(created.id, 'secret')).rejects.toMatchObject({ code: 'CODEX_PROCESS' });\n expect((await repository.getById(created.id))).toMatchObject({\n providerSessionId: SESSION, state: 'degraded', sessionHealth: 'unknown',\n });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","vi","CodexPrintError","CodexPrintAgentService","DurableAgentRepository","SESSION","roots","root","splice","rmSync","recursive","force","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","processInspector","getIdentity","pid","startedAt","repository","dbPath","runner","run","fn","mockImplementation","request","onSpawn","onSession","sessionId","result","prompt","messages","exitCode","service","probe","validate","created","create","name","toMatchObject","provider","providerSessionId","sessionHealth","first","send","id","bound","getById","toBe","resolves","mock","calls","agent","rejects","code","state"],"mappings":"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"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
const SESSION = '22222222-2222-4222-8222-222222222222';
|
|
3
|
+
const base = {
|
|
4
|
+
id: 'id',
|
|
5
|
+
name: 'reviewer',
|
|
6
|
+
provider: 'codex',
|
|
7
|
+
providerSessionId: null,
|
|
8
|
+
sessionHealth: 'uninitialized'
|
|
9
|
+
};
|
|
10
|
+
describe('CodexPrintAgentService', ()=>{
|
|
11
|
+
it('constructs default non-billable dependencies without invoking them', async ()=>{
|
|
12
|
+
const api = await import('../../index.js');
|
|
13
|
+
const Service = api.CodexPrintAgentService;
|
|
14
|
+
expect(new Service().repository).toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
it('validates before provider-aware create and never runs Codex', async ()=>{
|
|
17
|
+
const api = await import('../../index.js');
|
|
18
|
+
expect(api).toHaveProperty('CodexPrintAgentService');
|
|
19
|
+
const probe = {
|
|
20
|
+
validate: vi.fn().mockResolvedValue({
|
|
21
|
+
executable: 'codex',
|
|
22
|
+
version: '0.147.0'
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
const repository = {
|
|
26
|
+
create: vi.fn().mockResolvedValue(base),
|
|
27
|
+
list: vi.fn()
|
|
28
|
+
};
|
|
29
|
+
const runner = {
|
|
30
|
+
run: vi.fn()
|
|
31
|
+
};
|
|
32
|
+
const Service = api.CodexPrintAgentService;
|
|
33
|
+
await new Service({
|
|
34
|
+
repository,
|
|
35
|
+
probe,
|
|
36
|
+
runner
|
|
37
|
+
}).create({
|
|
38
|
+
name: 'reviewer',
|
|
39
|
+
cwd: '/project'
|
|
40
|
+
});
|
|
41
|
+
expect(repository.create).toHaveBeenCalledWith({
|
|
42
|
+
name: 'reviewer',
|
|
43
|
+
cwd: '/project',
|
|
44
|
+
provider: 'codex'
|
|
45
|
+
});
|
|
46
|
+
expect(runner.run).not.toHaveBeenCalled();
|
|
47
|
+
});
|
|
48
|
+
it('binds during first send and explicitly resumes later sends', async ()=>{
|
|
49
|
+
const api = await import('../../index.js');
|
|
50
|
+
const repository = {
|
|
51
|
+
list: vi.fn(),
|
|
52
|
+
resolve: vi.fn().mockResolvedValue(base),
|
|
53
|
+
acquireRun: vi.fn().mockResolvedValueOnce({
|
|
54
|
+
agent: base,
|
|
55
|
+
token: 'one'
|
|
56
|
+
}).mockResolvedValueOnce({
|
|
57
|
+
agent: {
|
|
58
|
+
...base,
|
|
59
|
+
providerSessionId: SESSION,
|
|
60
|
+
sessionHealth: 'healthy'
|
|
61
|
+
},
|
|
62
|
+
token: 'two'
|
|
63
|
+
}),
|
|
64
|
+
recordProviderProcess: vi.fn(),
|
|
65
|
+
bindProviderSession: vi.fn(),
|
|
66
|
+
completeRun: vi.fn()
|
|
67
|
+
};
|
|
68
|
+
const runner = {
|
|
69
|
+
run: vi.fn().mockImplementation(async (request)=>{
|
|
70
|
+
await request.onSpawn({
|
|
71
|
+
pid: 42,
|
|
72
|
+
startedAt: 'start'
|
|
73
|
+
});
|
|
74
|
+
await request.onSession(SESSION);
|
|
75
|
+
return {
|
|
76
|
+
sessionId: SESSION,
|
|
77
|
+
result: 'answer',
|
|
78
|
+
messages: [
|
|
79
|
+
'answer'
|
|
80
|
+
],
|
|
81
|
+
exitCode: 0
|
|
82
|
+
};
|
|
83
|
+
})
|
|
84
|
+
};
|
|
85
|
+
const Service = api.CodexPrintAgentService;
|
|
86
|
+
const service = new Service({
|
|
87
|
+
repository,
|
|
88
|
+
probe: {
|
|
89
|
+
validate: vi.fn()
|
|
90
|
+
},
|
|
91
|
+
runner,
|
|
92
|
+
executable: 'fake-codex'
|
|
93
|
+
});
|
|
94
|
+
await service.send('reviewer', 'first');
|
|
95
|
+
await service.send('reviewer', 'later');
|
|
96
|
+
expect(repository.bindProviderSession).toHaveBeenNthCalledWith(1, 'id', 'one', SESSION);
|
|
97
|
+
expect(repository.bindProviderSession).toHaveBeenNthCalledWith(2, 'id', 'two', SESSION);
|
|
98
|
+
expect(repository.completeRun).toHaveBeenCalledWith('id', 'one', expect.objectContaining({
|
|
99
|
+
status: 'succeeded',
|
|
100
|
+
sessionHealth: 'healthy'
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
it('records mismatch separately from unknown failures', async ()=>{
|
|
104
|
+
const api = await import('../../index.js');
|
|
105
|
+
const ErrorType = api.CodexPrintError;
|
|
106
|
+
const completeRun = vi.fn();
|
|
107
|
+
const repository = {
|
|
108
|
+
list: vi.fn(),
|
|
109
|
+
resolve: vi.fn().mockResolvedValue(base),
|
|
110
|
+
acquireRun: vi.fn().mockResolvedValue({
|
|
111
|
+
agent: base,
|
|
112
|
+
token: 'one'
|
|
113
|
+
}),
|
|
114
|
+
recordProviderProcess: vi.fn(),
|
|
115
|
+
bindProviderSession: vi.fn(),
|
|
116
|
+
completeRun
|
|
117
|
+
};
|
|
118
|
+
const Service = api.CodexPrintAgentService;
|
|
119
|
+
const service = new Service({
|
|
120
|
+
repository,
|
|
121
|
+
probe: {
|
|
122
|
+
validate: vi.fn()
|
|
123
|
+
},
|
|
124
|
+
runner: {
|
|
125
|
+
run: vi.fn().mockRejectedValue(new ErrorType('mismatch', 'CODEX_SESSION_MISMATCH'))
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
await expect(service.send('reviewer', 'x')).rejects.toMatchObject({
|
|
129
|
+
code: 'CODEX_SESSION_MISMATCH'
|
|
130
|
+
});
|
|
131
|
+
expect(completeRun).toHaveBeenCalledWith('id', 'one', expect.objectContaining({
|
|
132
|
+
sessionHealth: 'mismatch'
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
it('rejects a non-Codex target without acquiring or mutating it', async ()=>{
|
|
136
|
+
const api = await import('../../index.js');
|
|
137
|
+
const Service = api.CodexPrintAgentService;
|
|
138
|
+
const repository = {
|
|
139
|
+
resolve: vi.fn().mockResolvedValue({
|
|
140
|
+
...base,
|
|
141
|
+
provider: 'claude'
|
|
142
|
+
}),
|
|
143
|
+
acquireRun: vi.fn(),
|
|
144
|
+
recordProviderProcess: vi.fn(),
|
|
145
|
+
bindProviderSession: vi.fn(),
|
|
146
|
+
completeRun: vi.fn()
|
|
147
|
+
};
|
|
148
|
+
await expect(new Service({
|
|
149
|
+
repository,
|
|
150
|
+
probe: {
|
|
151
|
+
validate: vi.fn()
|
|
152
|
+
},
|
|
153
|
+
runner: {
|
|
154
|
+
run: vi.fn()
|
|
155
|
+
}
|
|
156
|
+
}).send('reviewer', 'x')).rejects.toMatchObject({
|
|
157
|
+
code: 'CODEX_UNSUPPORTED'
|
|
158
|
+
});
|
|
159
|
+
expect(repository.acquireRun).not.toHaveBeenCalled();
|
|
160
|
+
expect(repository.completeRun).not.toHaveBeenCalled();
|
|
161
|
+
});
|
|
162
|
+
it('does not turn a successful completion write failure into a second completion', async ()=>{
|
|
163
|
+
const api = await import('../../index.js');
|
|
164
|
+
const Service = api.CodexPrintAgentService;
|
|
165
|
+
const completionFailure = new Error('completion failed');
|
|
166
|
+
const repository = {
|
|
167
|
+
resolve: vi.fn().mockResolvedValue(base),
|
|
168
|
+
acquireRun: vi.fn().mockResolvedValue({
|
|
169
|
+
agent: base,
|
|
170
|
+
token: 'one'
|
|
171
|
+
}),
|
|
172
|
+
recordProviderProcess: vi.fn(),
|
|
173
|
+
bindProviderSession: vi.fn(),
|
|
174
|
+
completeRun: vi.fn().mockRejectedValue(completionFailure)
|
|
175
|
+
};
|
|
176
|
+
const runner = {
|
|
177
|
+
run: vi.fn().mockResolvedValue({
|
|
178
|
+
sessionId: SESSION,
|
|
179
|
+
result: 'answer',
|
|
180
|
+
messages: [
|
|
181
|
+
'answer'
|
|
182
|
+
],
|
|
183
|
+
exitCode: 0
|
|
184
|
+
})
|
|
185
|
+
};
|
|
186
|
+
await expect(new Service({
|
|
187
|
+
repository,
|
|
188
|
+
probe: {
|
|
189
|
+
validate: vi.fn()
|
|
190
|
+
},
|
|
191
|
+
runner
|
|
192
|
+
}).send('reviewer', 'x')).rejects.toBe(completionFailure);
|
|
193
|
+
expect(repository.completeRun).toHaveBeenCalledOnce();
|
|
194
|
+
});
|
|
195
|
+
it('records a repository binding conflict as a session mismatch', async ()=>{
|
|
196
|
+
const api = await import('../../index.js');
|
|
197
|
+
const BindingError = api.CodexPrintError;
|
|
198
|
+
const completeRun = vi.fn();
|
|
199
|
+
const repository = {
|
|
200
|
+
list: vi.fn(),
|
|
201
|
+
resolve: vi.fn().mockResolvedValue(base),
|
|
202
|
+
acquireRun: vi.fn().mockResolvedValue({
|
|
203
|
+
agent: base,
|
|
204
|
+
token: 'one'
|
|
205
|
+
}),
|
|
206
|
+
recordProviderProcess: vi.fn(),
|
|
207
|
+
bindProviderSession: vi.fn().mockRejectedValue(new BindingError('binding mismatch', 'CODEX_SESSION_MISMATCH')),
|
|
208
|
+
completeRun
|
|
209
|
+
};
|
|
210
|
+
const runner = {
|
|
211
|
+
run: vi.fn().mockImplementation(async (request)=>{
|
|
212
|
+
await request.onSession(SESSION);
|
|
213
|
+
return {
|
|
214
|
+
sessionId: SESSION,
|
|
215
|
+
result: 'x',
|
|
216
|
+
messages: [
|
|
217
|
+
'x'
|
|
218
|
+
],
|
|
219
|
+
exitCode: 0
|
|
220
|
+
};
|
|
221
|
+
})
|
|
222
|
+
};
|
|
223
|
+
const Service = api.CodexPrintAgentService;
|
|
224
|
+
await expect(new Service({
|
|
225
|
+
repository,
|
|
226
|
+
probe: {
|
|
227
|
+
validate: vi.fn()
|
|
228
|
+
},
|
|
229
|
+
runner
|
|
230
|
+
}).send('reviewer', 'x')).rejects.toMatchObject({
|
|
231
|
+
code: 'CODEX_SESSION_MISMATCH'
|
|
232
|
+
});
|
|
233
|
+
expect(completeRun).toHaveBeenCalledWith('id', 'one', expect.objectContaining({
|
|
234
|
+
sessionHealth: 'mismatch'
|
|
235
|
+
}));
|
|
236
|
+
});
|
|
237
|
+
it('rejects missing and ambiguous records before acquiring a run', async ()=>{
|
|
238
|
+
const api = await import('../../index.js');
|
|
239
|
+
const Service = api.CodexPrintAgentService;
|
|
240
|
+
const repository = {
|
|
241
|
+
list: vi.fn(),
|
|
242
|
+
create: vi.fn(),
|
|
243
|
+
resolve: vi.fn().mockResolvedValueOnce(null).mockResolvedValueOnce([
|
|
244
|
+
base,
|
|
245
|
+
base
|
|
246
|
+
]),
|
|
247
|
+
acquireRun: vi.fn(),
|
|
248
|
+
recordProviderProcess: vi.fn(),
|
|
249
|
+
bindProviderSession: vi.fn(),
|
|
250
|
+
completeRun: vi.fn()
|
|
251
|
+
};
|
|
252
|
+
const service = new Service({
|
|
253
|
+
repository,
|
|
254
|
+
probe: {
|
|
255
|
+
validate: vi.fn()
|
|
256
|
+
},
|
|
257
|
+
runner: {
|
|
258
|
+
run: vi.fn()
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
await expect(service.send('missing', 'x')).rejects.toMatchObject({
|
|
262
|
+
code: 'DURABLE_AGENT_NOT_FOUND'
|
|
263
|
+
});
|
|
264
|
+
await expect(service.send('ambiguous', 'x')).rejects.toMatchObject({
|
|
265
|
+
code: 'CODEX_UNSUPPORTED'
|
|
266
|
+
});
|
|
267
|
+
expect(repository.acquireRun).not.toHaveBeenCalled();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
//# sourceMappingURL=CodexPrintAgentService.test.js.map
|