@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintAgent.integration.test.ts"],"sourcesContent":["import fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintAgent.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 ClaudePrintAgentService,\n DurableAgentRepository,\n type ProcessInspector,\n} from '../../index.js';\n\nconst roots: string[] = [];\n\nafterEach(() => {\n for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });\n});\n\ndescribe('Claude durable-agent fake-provider journey', () => {\n it('creates without invocation, then starts and resumes the same session through stdin', async () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'durable-agent-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({\n dbPath: path.join(root, 'state', 'agents.db'),\n processInspector,\n });\n const runner = {\n run: vi.fn().mockImplementation(async (request) => {\n await request.onSpawn({ pid: 42, startedAt: 'process-42' });\n return { sessionId: request.agent.providerSessionId, result: `answer:${request.prompt}`, exitCode: 0 };\n }),\n };\n const service = new ClaudePrintAgentService({\n repository,\n probe: { validate: vi.fn() },\n runner,\n });\n\n const created = await service.create({ name: 'reviewer', cwd });\n\n await expect(service.send(created.id, 'first secret')).resolves.toMatchObject({ result: 'answer:first secret' });\n await expect(service.send(created.id, 'follow up')).resolves.toMatchObject({ result: 'answer:follow up' });\n\n expect(runner.run.mock.calls[0][0]).toMatchObject({ firstRun: true, prompt: 'first secret' });\n expect(runner.run.mock.calls[1][0]).toMatchObject({ firstRun: false, prompt: 'follow up' });\n\n const persisted = await repository.getById(created.id);\n expect(persisted).toMatchObject({ state: 'ready', sessionHealth: 'healthy' });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","vi","ClaudePrintAgentService","DurableAgentRepository","roots","root","splice","rmSync","recursive","force","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","processInspector","getIdentity","pid","startedAt","repository","dbPath","runner","run","fn","mockImplementation","request","onSpawn","sessionId","agent","providerSessionId","result","prompt","exitCode","service","probe","validate","created","create","name","send","id","resolves","toMatchObject","mock","calls","firstRun","persisted","getById","state","sessionHealth"],"mappings":"AAAA,OAAOA,QAAQ,UAAU;AACzB,OAAOC,QAAQ,UAAU;AACzB,OAAOC,UAAU,YAAY;AAC7B,SAASC,SAAS,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAS;AAC7D,SACIC,uBAAuB,EACvBC,sBAAsB,QAEnB,iBAAiB;AAExB,MAAMC,QAAkB,EAAE;AAE1BP,UAAU;IACN,KAAK,MAAMQ,QAAQD,MAAME,MAAM,CAAC,GAAIZ,GAAGa,MAAM,CAACF,MAAM;QAAEG,WAAW;QAAMC,OAAO;IAAK;AACvF;AAEAX,SAAS,8CAA8C;IACnDE,GAAG,sFAAsF;QACrF,MAAMK,OAAOX,GAAGgB,WAAW,CAACd,KAAKe,IAAI,CAAChB,GAAGiB,MAAM,IAAI;QACnDR,MAAMS,IAAI,CAACR;QACX,MAAMS,MAAMlB,KAAKe,IAAI,CAACN,MAAM;QAC5BX,GAAGqB,SAAS,CAACD;QACb,MAAME,mBAAqC;YACvCC,aAAa,CAACC,MAAS,CAAA;oBAAEA;oBAAKC,WAAW,CAAC,QAAQ,EAAED,KAAK;gBAAC,CAAA;QAC9D;QACA,MAAME,aAAa,IAAIjB,uBAAuB;YAC1CkB,QAAQzB,KAAKe,IAAI,CAACN,MAAM,SAAS;YACjCW;QACJ;QACA,MAAMM,SAAS;YACXC,KAAKtB,GAAGuB,EAAE,GAAGC,kBAAkB,CAAC,OAAOC;gBACnC,MAAMA,QAAQC,OAAO,CAAC;oBAAET,KAAK;oBAAIC,WAAW;gBAAa;gBACzD,OAAO;oBAAES,WAAWF,QAAQG,KAAK,CAACC,iBAAiB;oBAAEC,QAAQ,CAAC,OAAO,EAAEL,QAAQM,MAAM,EAAE;oBAAEC,UAAU;gBAAE;YACzG;QACJ;QACA,MAAMC,UAAU,IAAIhC,wBAAwB;YACxCkB;YACAe,OAAO;gBAAEC,UAAUnC,GAAGuB,EAAE;YAAG;YAC3BF;QACJ;QAEA,MAAMe,UAAU,MAAMH,QAAQI,MAAM,CAAC;YAAEC,MAAM;YAAYzB;QAAI;QAE7D,MAAMf,OAAOmC,QAAQM,IAAI,CAACH,QAAQI,EAAE,EAAE,iBAAiBC,QAAQ,CAACC,aAAa,CAAC;YAAEZ,QAAQ;QAAsB;QAC9G,MAAMhC,OAAOmC,QAAQM,IAAI,CAACH,QAAQI,EAAE,EAAE,cAAcC,QAAQ,CAACC,aAAa,CAAC;YAAEZ,QAAQ;QAAmB;QAExGhC,OAAOuB,OAAOC,GAAG,CAACqB,IAAI,CAACC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAEF,aAAa,CAAC;YAAEG,UAAU;YAAMd,QAAQ;QAAe;QAC3FjC,OAAOuB,OAAOC,GAAG,CAACqB,IAAI,CAACC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAEF,aAAa,CAAC;YAAEG,UAAU;YAAOd,QAAQ;QAAY;QAEzF,MAAMe,YAAY,MAAM3B,WAAW4B,OAAO,CAACX,QAAQI,EAAE;QACrD1C,OAAOgD,WAAWJ,aAAa,CAAC;YAAEM,OAAO;YAASC,eAAe;QAAU;IAC/E;AACJ"}
|
|
@@ -41,6 +41,7 @@ describe('ClaudePrintAgentService', ()=>{
|
|
|
41
41
|
const base = {
|
|
42
42
|
id: 'id',
|
|
43
43
|
name: 'reviewer',
|
|
44
|
+
provider: 'claude',
|
|
44
45
|
providerSessionId: 'session',
|
|
45
46
|
sessionHealth: 'uninitialized'
|
|
46
47
|
};
|
|
@@ -103,6 +104,70 @@ describe('ClaudePrintAgentService', ()=>{
|
|
|
103
104
|
sessionHealth: 'healthy'
|
|
104
105
|
}));
|
|
105
106
|
});
|
|
107
|
+
it('rejects a non-Claude target without acquiring or mutating it', async ()=>{
|
|
108
|
+
const api = await import('../../index.js');
|
|
109
|
+
const Service = api.ClaudePrintAgentService;
|
|
110
|
+
const target = {
|
|
111
|
+
id: 'id',
|
|
112
|
+
name: 'reviewer',
|
|
113
|
+
provider: 'pi'
|
|
114
|
+
};
|
|
115
|
+
const repository = {
|
|
116
|
+
resolve: vi.fn().mockResolvedValue(target),
|
|
117
|
+
acquireRun: vi.fn(),
|
|
118
|
+
recordProviderProcess: vi.fn(),
|
|
119
|
+
completeRun: vi.fn()
|
|
120
|
+
};
|
|
121
|
+
await expect(new Service({
|
|
122
|
+
repository,
|
|
123
|
+
probe: {
|
|
124
|
+
validate: vi.fn()
|
|
125
|
+
},
|
|
126
|
+
runner: {
|
|
127
|
+
run: vi.fn()
|
|
128
|
+
}
|
|
129
|
+
}).send('reviewer', 'x')).rejects.toMatchObject({
|
|
130
|
+
code: 'CLAUDE_PRINT_UNSUPPORTED'
|
|
131
|
+
});
|
|
132
|
+
expect(repository.acquireRun).not.toHaveBeenCalled();
|
|
133
|
+
expect(repository.completeRun).not.toHaveBeenCalled();
|
|
134
|
+
});
|
|
135
|
+
it('does not turn a successful completion write failure into a second completion', async ()=>{
|
|
136
|
+
const api = await import('../../index.js');
|
|
137
|
+
const Service = api.ClaudePrintAgentService;
|
|
138
|
+
const target = {
|
|
139
|
+
id: 'id',
|
|
140
|
+
name: 'reviewer',
|
|
141
|
+
provider: 'claude',
|
|
142
|
+
providerSessionId: 'session',
|
|
143
|
+
sessionHealth: 'healthy'
|
|
144
|
+
};
|
|
145
|
+
const completionFailure = new Error('completion failed');
|
|
146
|
+
const repository = {
|
|
147
|
+
resolve: vi.fn().mockResolvedValue(target),
|
|
148
|
+
acquireRun: vi.fn().mockResolvedValue({
|
|
149
|
+
agent: target,
|
|
150
|
+
token: 'one'
|
|
151
|
+
}),
|
|
152
|
+
recordProviderProcess: vi.fn(),
|
|
153
|
+
completeRun: vi.fn().mockRejectedValue(completionFailure)
|
|
154
|
+
};
|
|
155
|
+
const runner = {
|
|
156
|
+
run: vi.fn().mockResolvedValue({
|
|
157
|
+
sessionId: 'session',
|
|
158
|
+
result: 'answer',
|
|
159
|
+
exitCode: 0
|
|
160
|
+
})
|
|
161
|
+
};
|
|
162
|
+
await expect(new Service({
|
|
163
|
+
repository,
|
|
164
|
+
probe: {
|
|
165
|
+
validate: vi.fn()
|
|
166
|
+
},
|
|
167
|
+
runner
|
|
168
|
+
}).send('reviewer', 'x')).rejects.toBe(completionFailure);
|
|
169
|
+
expect(repository.completeRun).toHaveBeenCalledOnce();
|
|
170
|
+
});
|
|
106
171
|
});
|
|
107
172
|
|
|
108
173
|
//# sourceMappingURL=ClaudePrintAgentService.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintAgentService.test.ts"],"sourcesContent":["import { describe, expect, it, vi } from 'vitest';\n\ndescribe('ClaudePrintAgentService', () => {\n it('validates before create and does not run Claude', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n expect(api).toHaveProperty('ClaudePrintAgentService');\n const probe = { validate: vi.fn().mockResolvedValue({ executable: 'claude', version: '2.1.220' }) };\n const repository = { create: vi.fn().mockResolvedValue({ id: 'agent-id', name: 'reviewer' }) };\n const runner = { run: vi.fn() };\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n\n await expect(new Service({ repository, probe, runner }).create({ name: 'reviewer', cwd: '/project' }))\n .resolves.toMatchObject({ id: 'agent-id' });\n expect(probe.validate).toHaveBeenCalledOnce();\n expect(repository.create).toHaveBeenCalledWith({ name: 'reviewer', cwd: '/project' });\n expect(runner.run).not.toHaveBeenCalled();\n });\n\n it('runs first and resumed sends and records provider identity/results', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const base = { id: 'id', name: 'reviewer', providerSessionId: 'session', sessionHealth: 'uninitialized' };\n const repository = {\n resolve: vi.fn().mockResolvedValue(base),\n acquireRun: vi.fn()\n .mockResolvedValueOnce({ agent: base, token: 'one' })\n .mockResolvedValueOnce({ agent: { ...base, sessionHealth: 'healthy' }, token: 'two' }),\n recordProviderProcess: vi.fn(), completeRun: vi.fn().mockResolvedValue({}),\n };\n const runner = { run: vi.fn().mockImplementation(async (request) => {\n await request.onSpawn({ pid: 42, startedAt: 'start' });\n return { sessionId: 'session', result: 'answer', exitCode: 0 };\n }) };\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n const service = new Service({ repository, probe: { validate: vi.fn() }, runner, executable: 'fake-claude' });\n\n await service.send('reviewer', 'first');\n await service.send('id', 'later');\n\n expect(runner.run.mock.calls[0][0]).toMatchObject({ prompt: 'first', firstRun: true, executable: 'fake-claude' });\n expect(runner.run.mock.calls[1][0]).toMatchObject({ prompt: 'later', firstRun: false, executable: 'fake-claude' });\n expect(repository.recordProviderProcess).toHaveBeenCalledWith('id', 'one', { pid: 42, startedAt: 'start' });\n expect(repository.completeRun).toHaveBeenCalledWith('id', 'one', expect.objectContaining({\n status: 'succeeded', exitCode: 0, sessionHealth: 'healthy',\n }));\n });\n});\n"],"names":["describe","expect","it","vi","api","toHaveProperty","probe","validate","fn","mockResolvedValue","executable","version","repository","create","id","name","runner","run","Service","ClaudePrintAgentService","cwd","resolves","toMatchObject","toHaveBeenCalledOnce","toHaveBeenCalledWith","not","toHaveBeenCalled","base","providerSessionId","sessionHealth","resolve","acquireRun","mockResolvedValueOnce","agent","token","recordProviderProcess","completeRun","mockImplementation","request","onSpawn","pid","startedAt","sessionId","result","exitCode","service","send","mock","calls","prompt","firstRun","objectContaining","status"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAS;AAElDH,SAAS,2BAA2B;IAChCE,GAAG,mDAAmD;QAClD,MAAME,MAAM,MAAM,MAAM,CAAC;QACzBH,OAAOG,KAAKC,cAAc,CAAC;QAC3B,MAAMC,QAAQ;YAAEC,UAAUJ,GAAGK,EAAE,GAAGC,iBAAiB,CAAC;gBAAEC,YAAY;gBAAUC,SAAS;YAAU;QAAG;QAClG,MAAMC,aAAa;YAAEC,QAAQV,GAAGK,EAAE,GAAGC,iBAAiB,CAAC;gBAAEK,IAAI;gBAAYC,MAAM;YAAW;QAAG;QAC7F,MAAMC,SAAS;YAAEC,KAAKd,GAAGK,EAAE;QAAG;QAC9B,MAAMU,UAAUd,IAAIe,uBAAuB;QAE3C,MAAMlB,OAAO,IAAIiB,QAAQ;YAAEN;YAAYN;YAAOU;QAAO,GAAGH,MAAM,CAAC;YAAEE,MAAM;YAAYK,KAAK;QAAW,IAC9FC,QAAQ,CAACC,aAAa,CAAC;YAAER,IAAI;QAAW;QAC7Cb,OAAOK,MAAMC,QAAQ,EAAEgB,oBAAoB;QAC3CtB,OAAOW,WAAWC,MAAM,EAAEW,oBAAoB,CAAC;YAAET,MAAM;YAAYK,KAAK;QAAW;QACnFnB,OAAOe,OAAOC,GAAG,EAAEQ,GAAG,CAACC,gBAAgB;IAC3C;IAEAxB,GAAG,sEAAsE;QACrE,MAAME,MAAM,MAAM,MAAM,CAAC;QACzB,MAAMuB,OAAO;YAAEb,IAAI;YAAMC,MAAM;YAAYa,mBAAmB;YAAWC,eAAe;QAAgB;
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintAgentService.test.ts"],"sourcesContent":["import { describe, expect, it, vi } from 'vitest';\n\ndescribe('ClaudePrintAgentService', () => {\n it('validates before create and does not run Claude', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n expect(api).toHaveProperty('ClaudePrintAgentService');\n const probe = { validate: vi.fn().mockResolvedValue({ executable: 'claude', version: '2.1.220' }) };\n const repository = { create: vi.fn().mockResolvedValue({ id: 'agent-id', name: 'reviewer' }) };\n const runner = { run: vi.fn() };\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n\n await expect(new Service({ repository, probe, runner }).create({ name: 'reviewer', cwd: '/project' }))\n .resolves.toMatchObject({ id: 'agent-id' });\n expect(probe.validate).toHaveBeenCalledOnce();\n expect(repository.create).toHaveBeenCalledWith({ name: 'reviewer', cwd: '/project' });\n expect(runner.run).not.toHaveBeenCalled();\n });\n\n it('runs first and resumed sends and records provider identity/results', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const base = { id: 'id', name: 'reviewer', provider: 'claude', providerSessionId: 'session', sessionHealth: 'uninitialized' };\n const repository = {\n resolve: vi.fn().mockResolvedValue(base),\n acquireRun: vi.fn()\n .mockResolvedValueOnce({ agent: base, token: 'one' })\n .mockResolvedValueOnce({ agent: { ...base, sessionHealth: 'healthy' }, token: 'two' }),\n recordProviderProcess: vi.fn(), completeRun: vi.fn().mockResolvedValue({}),\n };\n const runner = { run: vi.fn().mockImplementation(async (request) => {\n await request.onSpawn({ pid: 42, startedAt: 'start' });\n return { sessionId: 'session', result: 'answer', exitCode: 0 };\n }) };\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n const service = new Service({ repository, probe: { validate: vi.fn() }, runner, executable: 'fake-claude' });\n\n await service.send('reviewer', 'first');\n await service.send('id', 'later');\n\n expect(runner.run.mock.calls[0][0]).toMatchObject({ prompt: 'first', firstRun: true, executable: 'fake-claude' });\n expect(runner.run.mock.calls[1][0]).toMatchObject({ prompt: 'later', firstRun: false, executable: 'fake-claude' });\n expect(repository.recordProviderProcess).toHaveBeenCalledWith('id', 'one', { pid: 42, startedAt: 'start' });\n expect(repository.completeRun).toHaveBeenCalledWith('id', 'one', expect.objectContaining({\n status: 'succeeded', exitCode: 0, sessionHealth: 'healthy',\n }));\n });\n\n it('rejects a non-Claude target without acquiring or mutating it', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n const target = { id: 'id', name: 'reviewer', provider: 'pi' };\n const repository = {\n resolve: vi.fn().mockResolvedValue(target),\n acquireRun: vi.fn(), recordProviderProcess: vi.fn(), completeRun: vi.fn(),\n };\n\n await expect(new Service({ repository, probe: { validate: vi.fn() }, runner: { run: vi.fn() } })\n .send('reviewer', 'x')).rejects.toMatchObject({ code: 'CLAUDE_PRINT_UNSUPPORTED' });\n expect(repository.acquireRun).not.toHaveBeenCalled();\n expect(repository.completeRun).not.toHaveBeenCalled();\n });\n\n it('does not turn a successful completion write failure into a second completion', async () => {\n const api = await import('../../index.js') as Record<string, unknown>;\n const Service = api.ClaudePrintAgentService as new (options: unknown) => any;\n const target = { id: 'id', name: 'reviewer', provider: 'claude', providerSessionId: 'session', sessionHealth: 'healthy' };\n const completionFailure = new Error('completion failed');\n const repository = {\n resolve: vi.fn().mockResolvedValue(target),\n acquireRun: vi.fn().mockResolvedValue({ agent: target, token: 'one' }),\n recordProviderProcess: vi.fn(), completeRun: vi.fn().mockRejectedValue(completionFailure),\n };\n const runner = { run: vi.fn().mockResolvedValue({ sessionId: 'session', result: 'answer', exitCode: 0 }) };\n\n await expect(new Service({ repository, probe: { validate: vi.fn() }, runner })\n .send('reviewer', 'x')).rejects.toBe(completionFailure);\n expect(repository.completeRun).toHaveBeenCalledOnce();\n });\n});\n"],"names":["describe","expect","it","vi","api","toHaveProperty","probe","validate","fn","mockResolvedValue","executable","version","repository","create","id","name","runner","run","Service","ClaudePrintAgentService","cwd","resolves","toMatchObject","toHaveBeenCalledOnce","toHaveBeenCalledWith","not","toHaveBeenCalled","base","provider","providerSessionId","sessionHealth","resolve","acquireRun","mockResolvedValueOnce","agent","token","recordProviderProcess","completeRun","mockImplementation","request","onSpawn","pid","startedAt","sessionId","result","exitCode","service","send","mock","calls","prompt","firstRun","objectContaining","status","target","rejects","code","completionFailure","Error","mockRejectedValue","toBe"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import { PassThrough, Writable } from 'node:stream';
|
|
3
3
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { ClaudePrintRunner } from '../../providers/claude/durable/ClaudePrintRunner.js';
|
|
4
5
|
function agent() {
|
|
5
6
|
return {
|
|
6
7
|
id: '11111111-1111-4111-8111-111111111111',
|
|
@@ -49,8 +50,6 @@ function fakeSpawn(events, exitCode = 0) {
|
|
|
49
50
|
}
|
|
50
51
|
describe('ClaudePrintRunner', ()=>{
|
|
51
52
|
it('starts a caller-assigned session and persists provider identity before stdin', async ()=>{
|
|
52
|
-
const api = await import('../../index.js');
|
|
53
|
-
expect(api).toHaveProperty('ClaudePrintRunner');
|
|
54
53
|
const fixture = fakeSpawn([
|
|
55
54
|
{
|
|
56
55
|
type: 'system',
|
|
@@ -64,8 +63,7 @@ describe('ClaudePrintRunner', ()=>{
|
|
|
64
63
|
}
|
|
65
64
|
]);
|
|
66
65
|
let persisted = false;
|
|
67
|
-
const
|
|
68
|
-
const runner = new Runner({
|
|
66
|
+
const runner = new ClaudePrintRunner({
|
|
69
67
|
spawn: fixture.spawn,
|
|
70
68
|
processInspector: {
|
|
71
69
|
getIdentity: ()=>({
|
|
@@ -114,7 +112,6 @@ describe('ClaudePrintRunner', ()=>{
|
|
|
114
112
|
});
|
|
115
113
|
});
|
|
116
114
|
it('uses exact resume and rejects a mismatched result session', async ()=>{
|
|
117
|
-
const api = await import('../../index.js');
|
|
118
115
|
const fixture = fakeSpawn([
|
|
119
116
|
{
|
|
120
117
|
type: 'result',
|
|
@@ -122,8 +119,7 @@ describe('ClaudePrintRunner', ()=>{
|
|
|
122
119
|
result: 'nope'
|
|
123
120
|
}
|
|
124
121
|
]);
|
|
125
|
-
const
|
|
126
|
-
const runner = new Runner({
|
|
122
|
+
const runner = new ClaudePrintRunner({
|
|
127
123
|
spawn: fixture.spawn,
|
|
128
124
|
processInspector: {
|
|
129
125
|
getIdentity: ()=>({
|
|
@@ -151,10 +147,8 @@ describe('ClaudePrintRunner', ()=>{
|
|
|
151
147
|
]);
|
|
152
148
|
});
|
|
153
149
|
it('does not disclose provider stderr in a failed-run error', async ()=>{
|
|
154
|
-
const api = await import('../../index.js');
|
|
155
150
|
const fixture = fakeSpawn([], 1);
|
|
156
|
-
const
|
|
157
|
-
const runner = new Runner({
|
|
151
|
+
const runner = new ClaudePrintRunner({
|
|
158
152
|
spawn: fixture.spawn,
|
|
159
153
|
processInspector: {
|
|
160
154
|
getIdentity: ()=>({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintRunner.test.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { PassThrough, Writable } from 'node:stream';\nimport { describe, expect, it, vi } from 'vitest';\nimport type { DurableAgent } from '../../index.js';\n\nfunction agent(): DurableAgent {\n return {\n id: '11111111-1111-4111-8111-111111111111', name: 'reviewer', provider: 'claude', mode: 'durable',\n cwd: '/project', providerSessionId: '22222222-2222-4222-8222-222222222222', state: 'running',\n sessionHealth: 'uninitialized', createdAt: '', updatedAt: '', lastActiveAt: null, lastResult: null,\n activeRun: null,\n };\n}\n\nfunction fakeSpawn(events: object[], exitCode = 0) {\n const calls: unknown[][] = [];\n const promptChunks: Buffer[] = [];\n const child = new EventEmitter() as any;\n child.pid = 4242;\n child.stdout = new PassThrough();\n child.stderr = new PassThrough();\n child.stdin = new Writable({\n write(chunk, _encoding, callback) { promptChunks.push(Buffer.from(chunk)); callback(); },\n final(callback) {\n for (const event of events) child.stdout.write(`${JSON.stringify(event)}\\n`);\n child.stdout.end();\n queueMicrotask(() => child.emit('close', exitCode, null));\n callback();\n },\n });\n const spawn = vi.fn((...args: unknown[]) => { calls.push(args); return child; });\n return { spawn, calls, promptChunks };\n}\n\ndescribe('ClaudePrintRunner', () => {\n it('starts a caller-assigned session and persists provider identity before stdin', async () => {\n const
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/print/ClaudePrintRunner.test.ts"],"sourcesContent":["import { EventEmitter } from 'node:events';\nimport { PassThrough, Writable } from 'node:stream';\nimport { describe, expect, it, vi } from 'vitest';\nimport type { DurableAgent } from '../../index.js';\nimport { ClaudePrintRunner } from '../../providers/claude/durable/ClaudePrintRunner.js';\n\nfunction agent(): DurableAgent {\n return {\n id: '11111111-1111-4111-8111-111111111111', name: 'reviewer', provider: 'claude', mode: 'durable',\n cwd: '/project', providerSessionId: '22222222-2222-4222-8222-222222222222', state: 'running',\n sessionHealth: 'uninitialized', createdAt: '', updatedAt: '', lastActiveAt: null, lastResult: null,\n activeRun: null,\n };\n}\n\nfunction fakeSpawn(events: object[], exitCode = 0) {\n const calls: unknown[][] = [];\n const promptChunks: Buffer[] = [];\n const child = new EventEmitter() as any;\n child.pid = 4242;\n child.stdout = new PassThrough();\n child.stderr = new PassThrough();\n child.stdin = new Writable({\n write(chunk, _encoding, callback) { promptChunks.push(Buffer.from(chunk)); callback(); },\n final(callback) {\n for (const event of events) child.stdout.write(`${JSON.stringify(event)}\\n`);\n child.stdout.end();\n queueMicrotask(() => child.emit('close', exitCode, null));\n callback();\n },\n });\n const spawn = vi.fn((...args: unknown[]) => { calls.push(args); return child; });\n return { spawn, calls, promptChunks };\n}\n\ndescribe('ClaudePrintRunner', () => {\n it('starts a caller-assigned session and persists provider identity before stdin', async () => {\n const fixture = fakeSpawn([\n { type: 'system', subtype: 'init', session_id: agent().providerSessionId },\n { type: 'result', session_id: agent().providerSessionId, result: 'done' },\n ]);\n let persisted = false;\n const runner = new ClaudePrintRunner({ spawn: fixture.spawn, processInspector: {\n getIdentity: () => ({ pid: 4242, startedAt: 'provider-start' }),\n } });\n\n const result = await runner.run({\n agent: agent(), prompt: 'secret prompt', executable: 'claude-test', firstRun: true,\n onSpawn: async () => { expect(fixture.promptChunks).toHaveLength(0); persisted = true; },\n });\n\n expect(persisted).toBe(true);\n expect(fixture.calls[0]).toEqual([\n 'claude-test',\n ['-p', '--session-id', agent().providerSessionId, '--output-format', 'stream-json', '--verbose'],\n expect.objectContaining({ cwd: '/project', shell: false, stdio: ['pipe', 'pipe', 'pipe'] }),\n ]);\n expect(JSON.stringify(fixture.calls)).not.toContain('secret prompt');\n expect(Buffer.concat(fixture.promptChunks).toString()).toBe('secret prompt');\n expect(result).toEqual({ sessionId: agent().providerSessionId, result: 'done', exitCode: 0 });\n });\n\n it('uses exact resume and rejects a mismatched result session', async () => {\n const fixture = fakeSpawn([{ type: 'result', session_id: 'wrong', result: 'nope' }]);\n const runner = new ClaudePrintRunner({ spawn: fixture.spawn, processInspector: {\n getIdentity: () => ({ pid: 4242, startedAt: 'provider-start' }),\n } });\n\n await expect(runner.run({\n agent: agent(), prompt: 'followup', executable: 'claude', firstRun: false, onSpawn: vi.fn(),\n })).rejects.toMatchObject({ code: 'CLAUDE_SESSION_MISMATCH' });\n expect(fixture.calls[0]![1]).toEqual([\n '-p', '--resume', agent().providerSessionId, '--output-format', 'stream-json', '--verbose',\n ]);\n });\n\n it('does not disclose provider stderr in a failed-run error', async () => {\n const fixture = fakeSpawn([], 1);\n const runner = new ClaudePrintRunner({ spawn: fixture.spawn, processInspector: {\n getIdentity: () => ({ pid: 4242, startedAt: 'provider-start' }),\n } });\n fixture.spawn.mockImplementationOnce((...args: unknown[]) => {\n const child = (fakeSpawn([], 1).spawn as any)(...args);\n child.stdin = new Writable({\n final(callback) {\n child.stderr.write('secret prompt echoed by provider');\n child.stderr.end();\n queueMicrotask(() => child.emit('close', 1, null));\n callback();\n },\n });\n return child;\n });\n\n await expect(runner.run({\n agent: agent(), prompt: 'secret prompt', firstRun: true, onSpawn: vi.fn(),\n })).rejects.not.toThrow(/secret prompt/);\n });\n});\n"],"names":["EventEmitter","PassThrough","Writable","describe","expect","it","vi","ClaudePrintRunner","agent","id","name","provider","mode","cwd","providerSessionId","state","sessionHealth","createdAt","updatedAt","lastActiveAt","lastResult","activeRun","fakeSpawn","events","exitCode","calls","promptChunks","child","pid","stdout","stderr","stdin","write","chunk","_encoding","callback","push","Buffer","from","final","event","JSON","stringify","end","queueMicrotask","emit","spawn","fn","args","fixture","type","subtype","session_id","result","persisted","runner","processInspector","getIdentity","startedAt","run","prompt","executable","firstRun","onSpawn","toHaveLength","toBe","toEqual","objectContaining","shell","stdio","not","toContain","concat","toString","sessionId","rejects","toMatchObject","code","mockImplementationOnce","toThrow"],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { AgentStatus } from '../../../adapters/AgentAdapter.js';
|
|
3
|
+
import { ClaudeAgentMapper } from '../../../providers/claude/ClaudeAgentMapper.js';
|
|
4
|
+
function makeProcess(overrides = {}) {
|
|
5
|
+
return {
|
|
6
|
+
pid: 123,
|
|
7
|
+
command: 'claude',
|
|
8
|
+
cwd: '/repo/my-app',
|
|
9
|
+
tty: 'ttys001',
|
|
10
|
+
...overrides
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function makeSession(overrides = {}) {
|
|
14
|
+
return {
|
|
15
|
+
sessionId: 'session-1',
|
|
16
|
+
projectPath: '/repo/my-app',
|
|
17
|
+
sessionStart: new Date('2026-08-23T10:00:00.000Z'),
|
|
18
|
+
lastActive: new Date('2026-08-23T10:05:00.000Z'),
|
|
19
|
+
lastEntryType: 'assistant',
|
|
20
|
+
isInterrupted: false,
|
|
21
|
+
lastUserMessage: 'Review this change',
|
|
22
|
+
...overrides
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function makeSessionFile(overrides = {}) {
|
|
26
|
+
return {
|
|
27
|
+
sessionId: 'session-1',
|
|
28
|
+
filePath: '/home/.claude/projects/-repo-my-app/session-1.jsonl',
|
|
29
|
+
projectDir: '/home/.claude/projects/-repo-my-app',
|
|
30
|
+
birthtimeMs: new Date('2026-08-23T10:00:00.000Z').getTime(),
|
|
31
|
+
resolvedCwd: '/repo/my-app',
|
|
32
|
+
...overrides
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
describe('ClaudeAgentMapper', ()=>{
|
|
36
|
+
it('prefers live PID-file status and waiting reason over JSONL-derived status', ()=>{
|
|
37
|
+
const mapper = new ClaudeAgentMapper();
|
|
38
|
+
const agent = mapper.mapSessionToAgent({
|
|
39
|
+
session: makeSession({
|
|
40
|
+
lastEntryType: 'assistant'
|
|
41
|
+
}),
|
|
42
|
+
processInfo: makeProcess(),
|
|
43
|
+
sessionFile: makeSessionFile(),
|
|
44
|
+
liveInfo: {
|
|
45
|
+
pidStatus: AgentStatus.WAITING,
|
|
46
|
+
waitingFor: 'approve Read'
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
expect(agent).toMatchObject({
|
|
50
|
+
name: 'my-app-123',
|
|
51
|
+
type: 'claude',
|
|
52
|
+
status: AgentStatus.WAITING,
|
|
53
|
+
summary: 'Review this change — waiting for approve Read',
|
|
54
|
+
pid: 123,
|
|
55
|
+
projectPath: '/repo/my-app',
|
|
56
|
+
sessionId: 'session-1',
|
|
57
|
+
sessionFilePath: '/home/.claude/projects/-repo-my-app/session-1.jsonl'
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
it('maps unmatched processes to the existing process-only fallback shape', ()=>{
|
|
61
|
+
const mapper = new ClaudeAgentMapper();
|
|
62
|
+
const agent = mapper.mapProcessOnlyAgent(makeProcess({
|
|
63
|
+
pid: 456,
|
|
64
|
+
cwd: '/repo/tooling'
|
|
65
|
+
}));
|
|
66
|
+
expect(agent).toMatchObject({
|
|
67
|
+
name: 'tooling-456',
|
|
68
|
+
type: 'claude',
|
|
69
|
+
status: AgentStatus.IDLE,
|
|
70
|
+
summary: 'Unknown',
|
|
71
|
+
pid: 456,
|
|
72
|
+
projectPath: '/repo/tooling',
|
|
73
|
+
sessionId: 'pid-456'
|
|
74
|
+
});
|
|
75
|
+
expect(agent.lastActive).toBeInstanceOf(Date);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
//# sourceMappingURL=ClaudeAgentMapper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/__tests__/providers/claude/ClaudeAgentMapper.test.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest';\n\nimport { AgentStatus, type ProcessInfo } from '../../../adapters/AgentAdapter.js';\nimport { ClaudeAgentMapper } from '../../../providers/claude/ClaudeAgentMapper.js';\nimport type { ClaudeSession } from '../../../providers/claude/ClaudeSessionParser.js';\nimport type { SessionFile } from '../../../utils/session.js';\n\nfunction makeProcess(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 123,\n command: 'claude',\n cwd: '/repo/my-app',\n tty: 'ttys001',\n ...overrides,\n };\n}\n\nfunction makeSession(overrides: Partial<ClaudeSession> = {}): ClaudeSession {\n return {\n sessionId: 'session-1',\n projectPath: '/repo/my-app',\n sessionStart: new Date('2026-08-23T10:00:00.000Z'),\n lastActive: new Date('2026-08-23T10:05:00.000Z'),\n lastEntryType: 'assistant',\n isInterrupted: false,\n lastUserMessage: 'Review this change',\n ...overrides,\n };\n}\n\nfunction makeSessionFile(overrides: Partial<SessionFile> = {}): SessionFile {\n return {\n sessionId: 'session-1',\n filePath: '/home/.claude/projects/-repo-my-app/session-1.jsonl',\n projectDir: '/home/.claude/projects/-repo-my-app',\n birthtimeMs: new Date('2026-08-23T10:00:00.000Z').getTime(),\n resolvedCwd: '/repo/my-app',\n ...overrides,\n };\n}\n\ndescribe('ClaudeAgentMapper', () => {\n it('prefers live PID-file status and waiting reason over JSONL-derived status', () => {\n const mapper = new ClaudeAgentMapper();\n\n const agent = mapper.mapSessionToAgent({\n session: makeSession({ lastEntryType: 'assistant' }),\n processInfo: makeProcess(),\n sessionFile: makeSessionFile(),\n liveInfo: {\n pidStatus: AgentStatus.WAITING,\n waitingFor: 'approve Read',\n },\n });\n\n expect(agent).toMatchObject({\n name: 'my-app-123',\n type: 'claude',\n status: AgentStatus.WAITING,\n summary: 'Review this change — waiting for approve Read',\n pid: 123,\n projectPath: '/repo/my-app',\n sessionId: 'session-1',\n sessionFilePath: '/home/.claude/projects/-repo-my-app/session-1.jsonl',\n });\n });\n\n it('maps unmatched processes to the existing process-only fallback shape', () => {\n const mapper = new ClaudeAgentMapper();\n\n const agent = mapper.mapProcessOnlyAgent(makeProcess({ pid: 456, cwd: '/repo/tooling' }));\n\n expect(agent).toMatchObject({\n name: 'tooling-456',\n type: 'claude',\n status: AgentStatus.IDLE,\n summary: 'Unknown',\n pid: 456,\n projectPath: '/repo/tooling',\n sessionId: 'pid-456',\n });\n expect(agent.lastActive).toBeInstanceOf(Date);\n });\n});\n"],"names":["describe","expect","it","AgentStatus","ClaudeAgentMapper","makeProcess","overrides","pid","command","cwd","tty","makeSession","sessionId","projectPath","sessionStart","Date","lastActive","lastEntryType","isInterrupted","lastUserMessage","makeSessionFile","filePath","projectDir","birthtimeMs","getTime","resolvedCwd","mapper","agent","mapSessionToAgent","session","processInfo","sessionFile","liveInfo","pidStatus","WAITING","waitingFor","toMatchObject","name","type","status","summary","sessionFilePath","mapProcessOnlyAgent","IDLE","toBeInstanceOf"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AAE9C,SAASC,WAAW,QAA0B,oCAAoC;AAClF,SAASC,iBAAiB,QAAQ,iDAAiD;AAInF,SAASC,YAAYC,YAAkC,CAAC,CAAC;IACrD,OAAO;QACHC,KAAK;QACLC,SAAS;QACTC,KAAK;QACLC,KAAK;QACL,GAAGJ,SAAS;IAChB;AACJ;AAEA,SAASK,YAAYL,YAAoC,CAAC,CAAC;IACvD,OAAO;QACHM,WAAW;QACXC,aAAa;QACbC,cAAc,IAAIC,KAAK;QACvBC,YAAY,IAAID,KAAK;QACrBE,eAAe;QACfC,eAAe;QACfC,iBAAiB;QACjB,GAAGb,SAAS;IAChB;AACJ;AAEA,SAASc,gBAAgBd,YAAkC,CAAC,CAAC;IACzD,OAAO;QACHM,WAAW;QACXS,UAAU;QACVC,YAAY;QACZC,aAAa,IAAIR,KAAK,4BAA4BS,OAAO;QACzDC,aAAa;QACb,GAAGnB,SAAS;IAChB;AACJ;AAEAN,SAAS,qBAAqB;IAC1BE,GAAG,6EAA6E;QAC5E,MAAMwB,SAAS,IAAItB;QAEnB,MAAMuB,QAAQD,OAAOE,iBAAiB,CAAC;YACnCC,SAASlB,YAAY;gBAAEM,eAAe;YAAY;YAClDa,aAAazB;YACb0B,aAAaX;YACbY,UAAU;gBACNC,WAAW9B,YAAY+B,OAAO;gBAC9BC,YAAY;YAChB;QACJ;QAEAlC,OAAO0B,OAAOS,aAAa,CAAC;YACxBC,MAAM;YACNC,MAAM;YACNC,QAAQpC,YAAY+B,OAAO;YAC3BM,SAAS;YACTjC,KAAK;YACLM,aAAa;YACbD,WAAW;YACX6B,iBAAiB;QACrB;IACJ;IAEAvC,GAAG,wEAAwE;QACvE,MAAMwB,SAAS,IAAItB;QAEnB,MAAMuB,QAAQD,OAAOgB,mBAAmB,CAACrC,YAAY;YAAEE,KAAK;YAAKE,KAAK;QAAgB;QAEtFR,OAAO0B,OAAOS,aAAa,CAAC;YACxBC,MAAM;YACNC,MAAM;YACNC,QAAQpC,YAAYwC,IAAI;YACxBH,SAAS;YACTjC,KAAK;YACLM,aAAa;YACbD,WAAW;QACf;QACAX,OAAO0B,MAAMX,UAAU,EAAE4B,cAAc,CAAC7B;IAC5C;AACJ"}
|