@ai-devkit/agent-manager 0.29.0 → 0.31.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__/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 +25 -28
- 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/database/connection.d.ts.map +1 -1
- package/dist/database/connection.js +5 -1
- package/dist/database/connection.js.map +1 -1
- 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 +17 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -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__/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 +11 -21
- 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/database/connection.ts +3 -1
- 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 +31 -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
|
@@ -18,11 +18,11 @@ function dbPath() {
|
|
|
18
18
|
return path.join(root, 'state', 'agents.db');
|
|
19
19
|
}
|
|
20
20
|
describe('durable agents schema', ()=>{
|
|
21
|
-
it('migrates to version
|
|
21
|
+
it('migrates to version 4 with durable constraints and indexes', ()=>{
|
|
22
22
|
const connection = new DatabaseConnection({
|
|
23
23
|
dbPath: dbPath()
|
|
24
24
|
});
|
|
25
|
-
expect(getSchemaVersion(connection)).toBe(
|
|
25
|
+
expect(getSchemaVersion(connection)).toBe(4);
|
|
26
26
|
const table = connection.queryOne("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'durable_agents'");
|
|
27
27
|
expect(table?.sql).toContain("DEFAULT 'durable'");
|
|
28
28
|
expect(table?.sql).toContain("state IN ('ready','running','degraded')");
|
|
@@ -32,6 +32,34 @@ describe('durable agents schema', ()=>{
|
|
|
32
32
|
]));
|
|
33
33
|
connection.close();
|
|
34
34
|
});
|
|
35
|
+
it('upgrades a version 3 database to nullable, unique provider sessions', ()=>{
|
|
36
|
+
const file = dbPath();
|
|
37
|
+
fs.mkdirSync(path.dirname(file), {
|
|
38
|
+
recursive: true
|
|
39
|
+
});
|
|
40
|
+
const raw = new Database(file);
|
|
41
|
+
raw.exec(`
|
|
42
|
+
CREATE TABLE durable_agents (
|
|
43
|
+
id TEXT PRIMARY KEY,
|
|
44
|
+
provider_session_id TEXT NOT NULL UNIQUE
|
|
45
|
+
);
|
|
46
|
+
INSERT INTO durable_agents (id, provider_session_id) VALUES ('existing', 'existing-session');
|
|
47
|
+
PRAGMA user_version = 3;
|
|
48
|
+
`);
|
|
49
|
+
raw.close();
|
|
50
|
+
const connection = new DatabaseConnection({
|
|
51
|
+
dbPath: file
|
|
52
|
+
});
|
|
53
|
+
expect(getSchemaVersion(connection)).toBe(4);
|
|
54
|
+
expect(()=>connection.execute('INSERT INTO durable_agents (id, provider_session_id) VALUES (?, NULL)', [
|
|
55
|
+
'codex'
|
|
56
|
+
])).not.toThrow();
|
|
57
|
+
expect(()=>connection.execute('INSERT INTO durable_agents (id, provider_session_id) VALUES (?, ?)', [
|
|
58
|
+
'duplicate',
|
|
59
|
+
'existing-session'
|
|
60
|
+
])).toThrow(/UNIQUE/i);
|
|
61
|
+
connection.close();
|
|
62
|
+
});
|
|
35
63
|
it('enforces case-insensitive names and active-run consistency but permits new providers', ()=>{
|
|
36
64
|
const connection = new DatabaseConnection({
|
|
37
65
|
dbPath: dbPath()
|
|
@@ -68,7 +96,7 @@ describe('readonly DatabaseConnection', ()=>{
|
|
|
68
96
|
dbPath: file,
|
|
69
97
|
readonly: true
|
|
70
98
|
});
|
|
71
|
-
expect(readonly.queryOne('PRAGMA user_version')?.user_version).toBe(
|
|
99
|
+
expect(readonly.queryOne('PRAGMA user_version')?.user_version).toBe(4);
|
|
72
100
|
readonly.close();
|
|
73
101
|
expect(fs.statSync(file).mtimeMs).toBe(before);
|
|
74
102
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/database/DurableAgentsDatabase.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport Database from 'better-sqlite3';\nimport { afterEach, describe, expect, it } from 'vitest';\nimport { DatabaseConnection } from '../../database/connection.js';\nimport { getSchemaVersion } from '../../database/schema.js';\n\nconst roots: string[] = [];\n\nafterEach(() => {\n for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });\n});\n\nfunction dbPath(): string {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'durable-agent-db-'));\n roots.push(root);\n return path.join(root, 'state', 'agents.db');\n}\n\ndescribe('durable agents schema', () => {\n it('migrates to version
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/database/DurableAgentsDatabase.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport Database from 'better-sqlite3';\nimport { afterEach, describe, expect, it } from 'vitest';\nimport { DatabaseConnection } from '../../database/connection.js';\nimport { getSchemaVersion } from '../../database/schema.js';\n\nconst roots: string[] = [];\n\nafterEach(() => {\n for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });\n});\n\nfunction dbPath(): string {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'durable-agent-db-'));\n roots.push(root);\n return path.join(root, 'state', 'agents.db');\n}\n\ndescribe('durable agents schema', () => {\n it('migrates to version 4 with durable constraints and indexes', () => {\n const connection = new DatabaseConnection({ dbPath: dbPath() });\n expect(getSchemaVersion(connection)).toBe(4);\n const table = connection.queryOne<{ sql: string }>(\n \"SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'durable_agents'\",\n );\n expect(table?.sql).toContain(\"DEFAULT 'durable'\");\n expect(table?.sql).toContain(\"state IN ('ready','running','degraded')\");\n expect(connection.query<{ name: string }>(\n \"SELECT name FROM sqlite_master WHERE type = 'index' AND tbl_name = 'durable_agents'\",\n ).map(({ name }) => name)).toEqual(expect.arrayContaining([\n 'idx_durable_agents_state', 'idx_durable_agents_list',\n ]));\n connection.close();\n });\n\n it('upgrades a version 3 database to nullable, unique provider sessions', () => {\n const file = dbPath();\n fs.mkdirSync(path.dirname(file), { recursive: true });\n const raw = new Database(file);\n raw.exec(`\n CREATE TABLE durable_agents (\n id TEXT PRIMARY KEY,\n provider_session_id TEXT NOT NULL UNIQUE\n );\n INSERT INTO durable_agents (id, provider_session_id) VALUES ('existing', 'existing-session');\n PRAGMA user_version = 3;\n `);\n raw.close();\n\n const connection = new DatabaseConnection({ dbPath: file });\n expect(getSchemaVersion(connection)).toBe(4);\n expect(() => connection.execute(\n 'INSERT INTO durable_agents (id, provider_session_id) VALUES (?, NULL)', ['codex'],\n )).not.toThrow();\n expect(() => connection.execute(\n 'INSERT INTO durable_agents (id, provider_session_id) VALUES (?, ?)', ['duplicate', 'existing-session'],\n )).toThrow(/UNIQUE/i);\n connection.close();\n });\n\n it('enforces case-insensitive names and active-run consistency but permits new providers', () => {\n const connection = new DatabaseConnection({ dbPath: dbPath() });\n const insert = (name: string, provider: string, state = 'ready') => connection.execute(`\n INSERT INTO durable_agents (\n id, name, provider, mode, cwd, provider_session_id, state, session_health,\n created_at, updated_at\n ) VALUES (?, ?, ?, 'durable', '/tmp', ?, ?, 'uninitialized', ?, ?)\n `, [crypto.randomUUID(), name, provider, crypto.randomUUID(), state, new Date().toISOString(), new Date().toISOString()]);\n expect(() => insert('Alpha', 'future-provider')).not.toThrow();\n expect(() => insert('alpha', 'claude')).toThrow(/UNIQUE/i);\n expect(() => insert('Broken', 'claude', 'running')).toThrow(/CHECK/i);\n connection.close();\n });\n});\n\ndescribe('readonly DatabaseConnection', () => {\n it('opens an already migrated database without changing it', () => {\n const file = dbPath();\n const writable = new DatabaseConnection({ dbPath: file });\n writable.close();\n const before = fs.statSync(file).mtimeMs;\n const readonly = new DatabaseConnection({ dbPath: file, readonly: true });\n expect(readonly.queryOne<{ user_version: number }>('PRAGMA user_version')?.user_version).toBe(4);\n readonly.close();\n expect(fs.statSync(file).mtimeMs).toBe(before);\n });\n\n it('does not create a missing database or migrate an old one', () => {\n const missing = dbPath();\n expect(() => new DatabaseConnection({ dbPath: missing, readonly: true })).toThrow(/readonly.*exist/i);\n expect(fs.existsSync(missing)).toBe(false);\n\n fs.mkdirSync(path.dirname(missing), { recursive: true });\n const raw = new Database(missing);\n raw.pragma('user_version = 2');\n raw.close();\n expect(() => new DatabaseConnection({ dbPath: missing, readonly: true })).toThrow(/schema version 3/i);\n expect(new Database(missing, { readonly: true }).pragma('user_version', { simple: true })).toBe(2);\n });\n});\n"],"names":["fs","os","path","Database","afterEach","describe","expect","it","DatabaseConnection","getSchemaVersion","roots","root","splice","rmSync","recursive","force","dbPath","mkdtempSync","join","tmpdir","push","connection","toBe","table","queryOne","sql","toContain","query","map","name","toEqual","arrayContaining","close","file","mkdirSync","dirname","raw","exec","execute","not","toThrow","insert","provider","state","crypto","randomUUID","Date","toISOString","writable","before","statSync","mtimeMs","readonly","user_version","missing","existsSync","pragma","simple"],"mappings":"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"}
|
|
@@ -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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"}
|