@ai-devkit/agent-manager 0.27.0 → 0.28.1

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.
Files changed (87) hide show
  1. package/README.md +12 -4
  2. package/dist/__tests__/adapters/CodexAdapter.test.js +199 -0
  3. package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
  4. package/dist/__tests__/database/DurableAgentsDatabase.test.js +100 -0
  5. package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +1 -0
  6. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +7 -7
  7. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
  8. package/dist/__tests__/print/ClaudePrintAgentService.test.js +7 -7
  9. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
  10. package/dist/__tests__/print/ClaudePrintRunner.test.js +1 -1
  11. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
  12. package/dist/__tests__/print/DurableAgent.test.js +17 -0
  13. package/dist/__tests__/print/DurableAgent.test.js.map +1 -0
  14. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +186 -0
  15. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -0
  16. package/dist/__tests__/print/{PrintAgentStore.test.js → DurableAgentRepository.test.js} +63 -110
  17. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -0
  18. package/dist/adapters/CodexAdapter.d.ts +1 -0
  19. package/dist/adapters/CodexAdapter.d.ts.map +1 -1
  20. package/dist/adapters/CodexAdapter.js +16 -6
  21. package/dist/adapters/CodexAdapter.js.map +1 -1
  22. package/dist/database/connection.d.ts.map +1 -1
  23. package/dist/database/connection.js +17 -9
  24. package/dist/database/connection.js.map +1 -1
  25. package/dist/database/migrations/003_durable_agents.sql +43 -0
  26. package/dist/durable/ClaudeCliProbe.d.ts.map +1 -0
  27. package/dist/{print → durable}/ClaudeCliProbe.js +1 -1
  28. package/dist/durable/ClaudeCliProbe.js.map +1 -0
  29. package/dist/{print → durable}/ClaudePrintAgentService.d.ts +11 -11
  30. package/dist/durable/ClaudePrintAgentService.d.ts.map +1 -0
  31. package/dist/{print → durable}/ClaudePrintAgentService.js +12 -12
  32. package/dist/durable/ClaudePrintAgentService.js.map +1 -0
  33. package/dist/{print → durable}/ClaudePrintRunner.d.ts +3 -3
  34. package/dist/durable/ClaudePrintRunner.d.ts.map +1 -0
  35. package/dist/{print → durable}/ClaudePrintRunner.js +2 -2
  36. package/dist/durable/ClaudePrintRunner.js.map +1 -0
  37. package/dist/durable/DurableAgent.d.ts +61 -0
  38. package/dist/durable/DurableAgent.d.ts.map +1 -0
  39. package/dist/durable/DurableAgent.js +46 -0
  40. package/dist/durable/DurableAgent.js.map +1 -0
  41. package/dist/durable/DurableAgentRepository.d.ts +60 -0
  42. package/dist/durable/DurableAgentRepository.d.ts.map +1 -0
  43. package/dist/durable/DurableAgentRepository.js +325 -0
  44. package/dist/durable/DurableAgentRepository.js.map +1 -0
  45. package/dist/index.d.ts +11 -11
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +6 -6
  48. package/dist/index.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/__tests__/adapters/CodexAdapter.test.ts +132 -0
  51. package/src/__tests__/database/DurableAgentsDatabase.test.ts +77 -0
  52. package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +6 -6
  53. package/src/__tests__/print/ClaudePrintAgentService.test.ts +7 -7
  54. package/src/__tests__/print/ClaudePrintRunner.test.ts +3 -3
  55. package/src/__tests__/print/{PrintAgent.test.ts → DurableAgent.test.ts} +6 -6
  56. package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +105 -0
  57. package/src/__tests__/print/DurableAgentRepository.test.ts +163 -0
  58. package/src/adapters/CodexAdapter.ts +14 -11
  59. package/src/database/connection.ts +15 -9
  60. package/src/database/migrations/003_durable_agents.sql +43 -0
  61. package/src/{print → durable}/ClaudeCliProbe.ts +1 -1
  62. package/src/{print → durable}/ClaudePrintAgentService.ts +21 -21
  63. package/src/{print → durable}/ClaudePrintRunner.ts +4 -4
  64. package/src/durable/DurableAgent.ts +91 -0
  65. package/src/durable/DurableAgentRepository.ts +307 -0
  66. package/src/index.ts +26 -25
  67. package/dist/__tests__/print/PrintAgent.test.js +0 -17
  68. package/dist/__tests__/print/PrintAgent.test.js.map +0 -1
  69. package/dist/__tests__/print/PrintAgentStore.test.js.map +0 -1
  70. package/dist/print/ClaudeCliProbe.d.ts.map +0 -1
  71. package/dist/print/ClaudeCliProbe.js.map +0 -1
  72. package/dist/print/ClaudePrintAgentService.d.ts.map +0 -1
  73. package/dist/print/ClaudePrintAgentService.js.map +0 -1
  74. package/dist/print/ClaudePrintRunner.d.ts.map +0 -1
  75. package/dist/print/ClaudePrintRunner.js.map +0 -1
  76. package/dist/print/PrintAgent.d.ts +0 -57
  77. package/dist/print/PrintAgent.d.ts.map +0 -1
  78. package/dist/print/PrintAgent.js +0 -42
  79. package/dist/print/PrintAgent.js.map +0 -1
  80. package/dist/print/PrintAgentStore.d.ts +0 -69
  81. package/dist/print/PrintAgentStore.d.ts.map +0 -1
  82. package/dist/print/PrintAgentStore.js +0 -484
  83. package/dist/print/PrintAgentStore.js.map +0 -1
  84. package/src/__tests__/print/PrintAgentStore.test.ts +0 -192
  85. package/src/print/PrintAgent.ts +0 -86
  86. package/src/print/PrintAgentStore.ts +0 -503
  87. /package/dist/{print → durable}/ClaudeCliProbe.d.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/durable/ClaudePrintRunner.ts"],"sourcesContent":["import { spawn as nodeSpawn, type ChildProcessWithoutNullStreams, type SpawnOptionsWithoutStdio } from 'child_process';\nimport type { DurableAgent, ProcessIdentity } from './DurableAgent.js';\nimport { ClaudePrintError } from './DurableAgent.js';\nimport { LocalProcessInspector, type ProcessInspector } from './DurableAgentRepository.js';\n\ntype Spawn = (\n command: string,\n args: readonly string[],\n options: SpawnOptionsWithoutStdio & { stdio: ['pipe', 'pipe', 'pipe'] },\n) => ChildProcessWithoutNullStreams;\n\nexport interface ClaudePrintRunRequest {\n agent: DurableAgent;\n prompt: string;\n executable?: string;\n firstRun: boolean;\n onSpawn(identity: ProcessIdentity): Promise<void>;\n}\n\nexport interface ClaudePrintRunResult {\n sessionId: string;\n result: string;\n exitCode: number;\n}\n\nexport interface ClaudePrintRunnerOptions {\n spawn?: Spawn;\n processInspector?: ProcessInspector;\n maxLineBytes?: number;\n}\n\nexport class ClaudePrintRunner {\n private readonly spawn: Spawn;\n private readonly processInspector: ProcessInspector;\n private readonly maxLineBytes: number;\n\n constructor(options: ClaudePrintRunnerOptions = {}) {\n this.spawn = options.spawn ?? (nodeSpawn as Spawn);\n this.processInspector = options.processInspector ?? new LocalProcessInspector();\n this.maxLineBytes = options.maxLineBytes ?? 1024 * 1024;\n }\n\n async run(request: ClaudePrintRunRequest): Promise<ClaudePrintRunResult> {\n const sessionArgs = request.firstRun\n ? ['--session-id', request.agent.providerSessionId]\n : ['--resume', request.agent.providerSessionId];\n const args = ['-p', ...sessionArgs, '--output-format', 'stream-json', '--verbose'];\n const child = this.spawn(request.executable ?? 'claude', args, {\n cwd: request.agent.cwd,\n shell: false,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n if (!child.pid) {\n child.kill();\n throw new ClaudePrintError('Claude process did not provide a PID.', 'CLAUDE_PROCESS_IDENTITY');\n }\n const identity = this.processInspector.getIdentity(child.pid);\n if (!identity) {\n child.kill();\n throw new ClaudePrintError('Cannot verify Claude process identity.', 'CLAUDE_PROCESS_IDENTITY');\n }\n\n let buffer = Buffer.alloc(0);\n let terminal: ClaudePrintRunResult | null = null;\n let protocolError: ClaudePrintError | null = null;\n\n child.stdout.on('data', (chunk: Buffer | string) => {\n if (protocolError) return;\n buffer = Buffer.concat([buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)]);\n if (buffer.length > this.maxLineBytes && buffer.indexOf(0x0a) < 0) {\n protocolError = new ClaudePrintError('Claude stream line exceeded the safety limit.', 'CLAUDE_STREAM_OVERSIZED');\n return;\n }\n let newline: number;\n while ((newline = buffer.indexOf(0x0a)) >= 0) {\n const line = buffer.subarray(0, newline);\n buffer = buffer.subarray(newline + 1);\n if (line.length === 0) continue;\n if (line.length > this.maxLineBytes) {\n protocolError = new ClaudePrintError('Claude stream line exceeded the safety limit.', 'CLAUDE_STREAM_OVERSIZED');\n return;\n }\n try {\n const value = JSON.parse(line.toString('utf8')) as unknown;\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new ClaudePrintError('Claude emitted a non-object stream message.', 'CLAUDE_STREAM_INVALID');\n }\n const event = value as Record<string, unknown>;\n if (typeof event.session_id === 'string' && event.session_id !== request.agent.providerSessionId) {\n throw new ClaudePrintError('Claude returned a different session identity.', 'CLAUDE_SESSION_MISMATCH');\n }\n if (event.type === 'result') {\n if (terminal) throw new ClaudePrintError('Claude emitted more than one terminal result.', 'CLAUDE_STREAM_INVALID');\n if (typeof event.session_id !== 'string' || typeof event.result !== 'string') {\n throw new ClaudePrintError('Claude emitted an invalid terminal result.', 'CLAUDE_STREAM_INVALID');\n }\n terminal = { sessionId: event.session_id, result: event.result, exitCode: 0 };\n }\n } catch (error) {\n protocolError = error instanceof ClaudePrintError\n ? error\n : new ClaudePrintError('Claude emitted malformed stream JSON.', 'CLAUDE_STREAM_INVALID');\n return;\n }\n }\n });\n // Drain provider diagnostics without reflecting potentially sensitive prompt/tool data.\n child.stderr.resume();\n\n const closed = new Promise<{ code: number | null; signal: NodeJS.Signals | null }>((resolve, reject) => {\n child.once('error', reject);\n child.once('close', (code, signal) => resolve({ code, signal }));\n });\n\n try {\n await request.onSpawn(identity);\n } catch (error) {\n child.kill();\n throw error;\n }\n\n child.stdin.end(request.prompt);\n const { code, signal } = await closed;\n\n if (protocolError) throw protocolError;\n if (buffer.length > 0) {\n throw new ClaudePrintError('Claude stream ended with incomplete JSON.', 'CLAUDE_STREAM_INVALID');\n }\n if (code !== 0) {\n throw new ClaudePrintError(\n `Claude print run failed${signal ? ` (${signal})` : '.'}`,\n 'CLAUDE_PROCESS_FAILED',\n );\n }\n if (!terminal) throw new ClaudePrintError('Claude stream ended without a terminal result.', 'CLAUDE_RESULT_MISSING');\n const finalResult = terminal as ClaudePrintRunResult;\n return { sessionId: finalResult.sessionId, result: finalResult.result, exitCode: code };\n }\n}\n"],"names":["spawn","nodeSpawn","ClaudePrintError","LocalProcessInspector","ClaudePrintRunner","processInspector","maxLineBytes","options","run","request","sessionArgs","firstRun","agent","providerSessionId","args","child","executable","cwd","shell","stdio","pid","kill","identity","getIdentity","buffer","Buffer","alloc","terminal","protocolError","stdout","on","chunk","concat","isBuffer","from","length","indexOf","newline","line","subarray","value","JSON","parse","toString","Array","isArray","event","session_id","type","result","sessionId","exitCode","error","stderr","resume","closed","Promise","resolve","reject","once","code","signal","onSpawn","stdin","end","prompt","finalResult"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ export type DurableAgentState = 'ready' | 'running' | 'degraded';
2
+ export type DurableSessionHealth = 'uninitialized' | 'healthy' | 'unknown' | 'mismatch';
3
+ export type DurableRunStatus = 'succeeded' | 'failed' | 'interrupted';
4
+ export declare const AGENT_MODES: {
5
+ readonly INTERACTIVE: "interactive";
6
+ readonly DURABLE: "durable";
7
+ };
8
+ export interface ProcessIdentity {
9
+ pid: number;
10
+ startedAt: string;
11
+ }
12
+ export interface DurableActiveRun {
13
+ token: string;
14
+ owner: ProcessIdentity;
15
+ provider: ProcessIdentity | null;
16
+ startedAt: string;
17
+ }
18
+ export interface DurableLastResult {
19
+ status: DurableRunStatus;
20
+ completedAt: string;
21
+ exitCode: number | null;
22
+ summary: string;
23
+ }
24
+ export interface DurableAgent {
25
+ id: string;
26
+ name: string;
27
+ provider: 'claude';
28
+ mode: typeof AGENT_MODES.DURABLE;
29
+ cwd: string;
30
+ providerSessionId: string;
31
+ state: DurableAgentState;
32
+ sessionHealth: DurableSessionHealth;
33
+ createdAt: string;
34
+ updatedAt: string;
35
+ lastActiveAt: string | null;
36
+ lastResult: DurableLastResult | null;
37
+ activeRun: DurableActiveRun | null;
38
+ }
39
+ export declare class DurableAgentError extends Error {
40
+ readonly code: string;
41
+ constructor(message: string, code: string);
42
+ }
43
+ export declare class DurableAgentBusyError extends DurableAgentError {
44
+ readonly agentId: string;
45
+ constructor(agentId: string, agentName: string);
46
+ }
47
+ export declare class DurableAgentNotFoundError extends DurableAgentError {
48
+ readonly reference: string;
49
+ constructor(reference: string);
50
+ }
51
+ export declare class DurableAgentRepositoryError extends DurableAgentError {
52
+ constructor(message: string);
53
+ }
54
+ export declare class DurableAgentNameConflictError extends DurableAgentError {
55
+ readonly agentName: string;
56
+ constructor(agentName: string);
57
+ }
58
+ export declare class ClaudePrintError extends DurableAgentError {
59
+ constructor(message: string, code?: string);
60
+ }
61
+ //# sourceMappingURL=DurableAgent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DurableAgent.d.ts","sourceRoot":"","sources":["../../src/durable/DurableAgent.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AACjE,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AACxF,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,QAAQ,GAAG,aAAa,CAAC;AAEtE,eAAO,MAAM,WAAW;;;CAGd,CAAC;AAEX,MAAM,WAAW,eAAe;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,eAAe,CAAC;IACvB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,OAAO,WAAW,CAAC,OAAO,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,iBAAiB,CAAC;IACzB,aAAa,EAAE,oBAAoB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrC,SAAS,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACtC;AAED,qBAAa,iBAAkB,SAAQ,KAAK;aAGpB,IAAI,EAAE,MAAM;gBAD5B,OAAO,EAAE,MAAM,EACC,IAAI,EAAE,MAAM;CAKnC;AAED,qBAAa,qBAAsB,SAAQ,iBAAiB;aAEpC,OAAO,EAAE,MAAM;gBAAf,OAAO,EAAE,MAAM,EAC/B,SAAS,EAAE,MAAM;CAKxB;AAED,qBAAa,yBAA0B,SAAQ,iBAAiB;aAChC,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIhD;AAED,qBAAa,2BAA4B,SAAQ,iBAAiB;gBAClD,OAAO,EAAE,MAAM;CAI9B;AAED,qBAAa,6BAA8B,SAAQ,iBAAiB;aACpC,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIhD;AAED,qBAAa,gBAAiB,SAAQ,iBAAiB;gBACvC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAwB;CAI5D"}
@@ -0,0 +1,46 @@
1
+ export const AGENT_MODES = {
2
+ INTERACTIVE: 'interactive',
3
+ DURABLE: 'durable'
4
+ };
5
+ export class DurableAgentError extends Error {
6
+ code;
7
+ constructor(message, code){
8
+ super(message), this.code = code;
9
+ this.name = 'DurableAgentError';
10
+ }
11
+ }
12
+ export class DurableAgentBusyError extends DurableAgentError {
13
+ agentId;
14
+ constructor(agentId, agentName){
15
+ super(`Durable agent "${agentName}" is busy.`, 'DURABLE_AGENT_BUSY'), this.agentId = agentId;
16
+ this.name = 'DurableAgentBusyError';
17
+ }
18
+ }
19
+ export class DurableAgentNotFoundError extends DurableAgentError {
20
+ reference;
21
+ constructor(reference){
22
+ super(`Durable agent "${reference}" was not found.`, 'DURABLE_AGENT_NOT_FOUND'), this.reference = reference;
23
+ this.name = 'DurableAgentNotFoundError';
24
+ }
25
+ }
26
+ export class DurableAgentRepositoryError extends DurableAgentError {
27
+ constructor(message){
28
+ super(message, 'DURABLE_AGENT_REPOSITORY');
29
+ this.name = 'DurableAgentRepositoryError';
30
+ }
31
+ }
32
+ export class DurableAgentNameConflictError extends DurableAgentError {
33
+ agentName;
34
+ constructor(agentName){
35
+ super(`Durable agent name "${agentName}" is already in use.`, 'DURABLE_AGENT_NAME_CONFLICT'), this.agentName = agentName;
36
+ this.name = 'DurableAgentNameConflictError';
37
+ }
38
+ }
39
+ export class ClaudePrintError extends DurableAgentError {
40
+ constructor(message, code = 'CLAUDE_PRINT_FAILED'){
41
+ super(message, code);
42
+ this.name = 'ClaudePrintError';
43
+ }
44
+ }
45
+
46
+ //# sourceMappingURL=DurableAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/durable/DurableAgent.ts"],"sourcesContent":["export type DurableAgentState = 'ready' | 'running' | 'degraded';\nexport type DurableSessionHealth = 'uninitialized' | 'healthy' | 'unknown' | 'mismatch';\nexport type DurableRunStatus = 'succeeded' | 'failed' | 'interrupted';\n\nexport const AGENT_MODES = {\n INTERACTIVE: 'interactive',\n DURABLE: 'durable',\n} as const;\n\nexport interface ProcessIdentity {\n pid: number;\n startedAt: string;\n}\n\nexport interface DurableActiveRun {\n token: string;\n owner: ProcessIdentity;\n provider: ProcessIdentity | null;\n startedAt: string;\n}\n\nexport interface DurableLastResult {\n status: DurableRunStatus;\n completedAt: string;\n exitCode: number | null;\n summary: string;\n}\n\nexport interface DurableAgent {\n id: string;\n name: string;\n provider: 'claude';\n mode: typeof AGENT_MODES.DURABLE;\n cwd: string;\n providerSessionId: string;\n state: DurableAgentState;\n sessionHealth: DurableSessionHealth;\n createdAt: string;\n updatedAt: string;\n lastActiveAt: string | null;\n lastResult: DurableLastResult | null;\n activeRun: DurableActiveRun | null;\n}\n\nexport class DurableAgentError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n ) {\n super(message);\n this.name = 'DurableAgentError';\n }\n}\n\nexport class DurableAgentBusyError extends DurableAgentError {\n constructor(\n public readonly agentId: string,\n agentName: string,\n ) {\n super(`Durable agent \"${agentName}\" is busy.`, 'DURABLE_AGENT_BUSY');\n this.name = 'DurableAgentBusyError';\n }\n}\n\nexport class DurableAgentNotFoundError extends DurableAgentError {\n constructor(public readonly reference: string) {\n super(`Durable agent \"${reference}\" was not found.`, 'DURABLE_AGENT_NOT_FOUND');\n this.name = 'DurableAgentNotFoundError';\n }\n}\n\nexport class DurableAgentRepositoryError extends DurableAgentError {\n constructor(message: string) {\n super(message, 'DURABLE_AGENT_REPOSITORY');\n this.name = 'DurableAgentRepositoryError';\n }\n}\n\nexport class DurableAgentNameConflictError extends DurableAgentError {\n constructor(public readonly agentName: string) {\n super(`Durable agent name \"${agentName}\" is already in use.`, 'DURABLE_AGENT_NAME_CONFLICT');\n this.name = 'DurableAgentNameConflictError';\n }\n}\n\nexport class ClaudePrintError extends DurableAgentError {\n constructor(message: string, code = 'CLAUDE_PRINT_FAILED') {\n super(message, code);\n this.name = 'ClaudePrintError';\n }\n}\n"],"names":["AGENT_MODES","INTERACTIVE","DURABLE","DurableAgentError","Error","message","code","name","DurableAgentBusyError","agentId","agentName","DurableAgentNotFoundError","reference","DurableAgentRepositoryError","DurableAgentNameConflictError","ClaudePrintError"],"mappings":"AAIA,OAAO,MAAMA,cAAc;IACvBC,aAAa;IACbC,SAAS;AACb,EAAW;AAqCX,OAAO,MAAMC,0BAA0BC;;IACnC,YACIC,OAAe,EACf,AAAgBC,IAAY,CAC9B;QACE,KAAK,CAACD,eAFUC,OAAAA;QAGhB,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMC,8BAA8BL;;IACvC,YACI,AAAgBM,OAAe,EAC/BC,SAAiB,CACnB;QACE,KAAK,CAAC,CAAC,eAAe,EAAEA,UAAU,UAAU,CAAC,EAAE,4BAH/BD,UAAAA;QAIhB,IAAI,CAACF,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMI,kCAAkCR;;IAC3C,YAAY,AAAgBS,SAAiB,CAAE;QAC3C,KAAK,CAAC,CAAC,eAAe,EAAEA,UAAU,gBAAgB,CAAC,EAAE,iCAD7BA,YAAAA;QAExB,IAAI,CAACL,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMM,oCAAoCV;IAC7C,YAAYE,OAAe,CAAE;QACzB,KAAK,CAACA,SAAS;QACf,IAAI,CAACE,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMO,sCAAsCX;;IAC/C,YAAY,AAAgBO,SAAiB,CAAE;QAC3C,KAAK,CAAC,CAAC,oBAAoB,EAAEA,UAAU,oBAAoB,CAAC,EAAE,qCADtCA,YAAAA;QAExB,IAAI,CAACH,IAAI,GAAG;IAChB;AACJ;AAEA,OAAO,MAAMQ,yBAAyBZ;IAClC,YAAYE,OAAe,EAAEC,OAAO,qBAAqB,CAAE;QACvD,KAAK,CAACD,SAASC;QACf,IAAI,CAACC,IAAI,GAAG;IAChB;AACJ"}
@@ -0,0 +1,60 @@
1
+ import { type DurableAgent, type ProcessIdentity, type DurableRunStatus, type DurableSessionHealth } from './DurableAgent.js';
2
+ export interface CreateDurableAgentInput {
3
+ name: string;
4
+ cwd: string;
5
+ }
6
+ export interface DurableAgentRepositoryOptions {
7
+ dbPath?: string;
8
+ readonly?: boolean;
9
+ /** @deprecated SQLite busy_timeout replaces filesystem lock polling. */
10
+ lockTimeoutMs?: number;
11
+ now?: () => Date;
12
+ processInspector?: ProcessInspector;
13
+ /** @deprecated Active ownership is committed atomically. */
14
+ incompleteLockGraceMs?: number;
15
+ /** @deprecated SQLite transactions replace mutation lock directories. */
16
+ mutationLockStaleMs?: number;
17
+ }
18
+ export interface ProcessInspector {
19
+ getIdentity(pid: number): ProcessIdentity | null;
20
+ }
21
+ export interface DurableRunCompletion {
22
+ status: DurableRunStatus;
23
+ exitCode: number | null;
24
+ summary: string;
25
+ sessionHealth: DurableSessionHealth;
26
+ }
27
+ export declare class DurableAgentRepository {
28
+ readonly dbPath: string;
29
+ private readonly now;
30
+ private readonly processInspector;
31
+ private readonly readonly;
32
+ private readonly db;
33
+ constructor(options?: DurableAgentRepositoryOptions);
34
+ create(input: CreateDurableAgentInput): Promise<DurableAgent>;
35
+ list(): Promise<DurableAgent[]>;
36
+ getById(id: string): Promise<DurableAgent | null>;
37
+ resolve(reference: string): Promise<DurableAgent | DurableAgent[] | null>;
38
+ acquireRun(id: string): Promise<{
39
+ agent: DurableAgent;
40
+ token: string;
41
+ }>;
42
+ recordProviderProcess(id: string, token: string, identity: ProcessIdentity): Promise<void>;
43
+ completeRun(id: string, token: string, result: DurableRunCompletion): Promise<DurableAgent>;
44
+ reconcile(): Promise<void>;
45
+ private immediate;
46
+ private listRaw;
47
+ private findById;
48
+ private requireById;
49
+ private fromRow;
50
+ private canonicalDirectory;
51
+ private validateBoundCwd;
52
+ private isActive;
53
+ private sameProcess;
54
+ private assertWritable;
55
+ private storageError;
56
+ }
57
+ export declare class LocalProcessInspector implements ProcessInspector {
58
+ getIdentity(pid: number): ProcessIdentity | null;
59
+ }
60
+ //# sourceMappingURL=DurableAgentRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DurableAgentRepository.d.ts","sourceRoot":"","sources":["../../src/durable/DurableAgentRepository.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsC,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAiBlK,MAAM,WAAW,uBAAuB;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAEtE,MAAM,WAAW,6BAA6B;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,4DAA4D;IAC5D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAAG,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAA;CAAE;AACtF,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,oBAAoB,CAAC;CAC3G;AAED,qBAAa,sBAAsB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAqB;gBAE5B,OAAO,GAAE,6BAAkC;IAajD,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,YAAY,CAAC;IAqB7D,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAK/B,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAKjD,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,YAAY,EAAE,GAAG,IAAI,CAAC;IAQzE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAkDvE,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAS1F,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC;IAgB3F,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBhC,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,OAAO;IAqBf,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;CAIvB;AAED,qBAAa,qBAAsB,YAAW,gBAAgB;IAC1D,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;CAkBnD"}
@@ -0,0 +1,325 @@
1
+ import fs from 'fs';
2
+ import { randomUUID } from 'crypto';
3
+ import { execFileSync } from 'child_process';
4
+ import { DatabaseConnection, DEFAULT_AGENT_REGISTRY_DB_PATH } from '../database/index.js';
5
+ import { AGENT_MODES } from './DurableAgent.js';
6
+ import { DurableAgentBusyError, DurableAgentNameConflictError, DurableAgentNotFoundError, DurableAgentRepositoryError } from './DurableAgent.js';
7
+ export class DurableAgentRepository {
8
+ dbPath;
9
+ now;
10
+ processInspector;
11
+ readonly;
12
+ db;
13
+ constructor(options = {}){
14
+ this.dbPath = options.dbPath ?? DEFAULT_AGENT_REGISTRY_DB_PATH;
15
+ this.now = options.now ?? (()=>new Date());
16
+ this.processInspector = options.processInspector ?? new LocalProcessInspector();
17
+ this.readonly = options.readonly ?? false;
18
+ try {
19
+ this.db = new DatabaseConnection({
20
+ dbPath: this.dbPath,
21
+ readonly: this.readonly
22
+ });
23
+ } catch (error) {
24
+ if (error instanceof DurableAgentRepositoryError) throw error;
25
+ throw new DurableAgentRepositoryError(`Cannot open durable-agent database: ${error.message}`);
26
+ }
27
+ }
28
+ async create(input) {
29
+ this.assertWritable();
30
+ const cwd = this.canonicalDirectory(input.cwd);
31
+ const timestamp = this.now().toISOString();
32
+ const id = randomUUID();
33
+ let providerSessionId = randomUUID();
34
+ while(providerSessionId === id)providerSessionId = randomUUID();
35
+ try {
36
+ this.db.execute(`INSERT INTO durable_agents (
37
+ id, name, provider, mode, cwd, provider_session_id, state, session_health, created_at, updated_at
38
+ ) VALUES (?, ?, 'claude', ?, ?, ?, 'ready', 'uninitialized', ?, ?)`, [
39
+ id,
40
+ input.name,
41
+ AGENT_MODES.DURABLE,
42
+ cwd,
43
+ providerSessionId,
44
+ timestamp,
45
+ timestamp
46
+ ]);
47
+ } catch (error) {
48
+ if (/UNIQUE constraint failed: durable_agents\.name/i.test(error.message)) {
49
+ throw new DurableAgentNameConflictError(input.name);
50
+ }
51
+ throw this.storageError('Failed to create durable agent', error);
52
+ }
53
+ return this.requireById(id);
54
+ }
55
+ async list() {
56
+ if (!this.readonly) await this.reconcile();
57
+ return this.listRaw();
58
+ }
59
+ async getById(id) {
60
+ if (!this.readonly) await this.reconcile();
61
+ return this.findById(id);
62
+ }
63
+ async resolve(reference) {
64
+ const agents = await this.list();
65
+ const byId = agents.find((agent)=>agent.id === reference);
66
+ if (byId) return byId;
67
+ const matches = agents.filter((agent)=>agent.name.toLowerCase() === reference.toLowerCase());
68
+ return matches.length === 0 ? null : matches.length === 1 ? matches[0] : matches;
69
+ }
70
+ async acquireRun(id) {
71
+ this.assertWritable();
72
+ const snapshot = this.findById(id);
73
+ if (!snapshot) throw new DurableAgentNotFoundError(id);
74
+ this.validateBoundCwd(snapshot.cwd);
75
+ const observed = snapshot.activeRun;
76
+ const observedLive = observed ? this.isActive(observed) : false;
77
+ if (observedLive) throw new DurableAgentBusyError(id, snapshot.name);
78
+ const owner = this.processInspector.getIdentity(process.pid);
79
+ if (!owner) throw new DurableAgentRepositoryError('Cannot determine the current process identity.');
80
+ const token = randomUUID();
81
+ const startedAt = this.now().toISOString();
82
+ let recovered = false;
83
+ try {
84
+ this.immediate(()=>{
85
+ const current = this.findById(id);
86
+ if (!current) throw new DurableAgentNotFoundError(id);
87
+ if (current.state === 'running') {
88
+ if (!observed || current.activeRun?.token !== observed.token || observedLive) {
89
+ throw new DurableAgentBusyError(id, current.name);
90
+ }
91
+ recovered = true;
92
+ }
93
+ const changed = this.db.execute(`UPDATE durable_agents SET
94
+ state = 'running', active_run_token = ?, active_owner_pid = ?, active_owner_started_at = ?,
95
+ active_provider_pid = NULL, active_provider_started_at = NULL, active_run_started_at = ?, updated_at = ?,
96
+ session_health = CASE WHEN state = 'running' THEN 'unknown' ELSE session_health END,
97
+ last_result_status = CASE WHEN state = 'running' THEN 'interrupted' ELSE last_result_status END,
98
+ last_result_completed_at = CASE WHEN state = 'running' THEN ? ELSE last_result_completed_at END,
99
+ last_result_exit_code = CASE WHEN state = 'running' THEN NULL ELSE last_result_exit_code END,
100
+ last_result_summary = CASE WHEN state = 'running' THEN 'Previous print run was interrupted.' ELSE last_result_summary END
101
+ WHERE id = ? AND (state <> 'running' OR (
102
+ active_run_token = ? AND active_owner_started_at = ? AND active_run_started_at = ?
103
+ ))
104
+ `, [
105
+ token,
106
+ owner.pid,
107
+ owner.startedAt,
108
+ startedAt,
109
+ startedAt,
110
+ startedAt,
111
+ id,
112
+ observed?.token ?? null,
113
+ observed?.owner.startedAt ?? null,
114
+ observed?.startedAt ?? null
115
+ ]);
116
+ if (changed.changes !== 1) throw new DurableAgentBusyError(id, current.name);
117
+ });
118
+ } catch (error) {
119
+ if (error instanceof DurableAgentBusyError || error instanceof DurableAgentNotFoundError) throw error;
120
+ if (/busy|locked/i.test(error.message)) throw new DurableAgentBusyError(id, snapshot.name);
121
+ throw this.storageError('Failed to acquire durable-agent run', error);
122
+ }
123
+ const agent = this.requireById(id);
124
+ if (recovered && agent.lastResult?.status !== 'interrupted') {
125
+ throw new DurableAgentRepositoryError('Failed to record interrupted print run.');
126
+ }
127
+ return {
128
+ agent,
129
+ token
130
+ };
131
+ }
132
+ async recordProviderProcess(id, token, identity) {
133
+ this.assertWritable();
134
+ const changed = this.db.execute(`UPDATE durable_agents SET
135
+ active_provider_pid = ?, active_provider_started_at = ?, updated_at = ?
136
+ WHERE id = ? AND state = 'running' AND active_run_token = ?`, [
137
+ identity.pid,
138
+ identity.startedAt,
139
+ this.now().toISOString(),
140
+ id,
141
+ token
142
+ ]);
143
+ if (changed.changes !== 1) throw new DurableAgentRepositoryError('Print run ownership changed.');
144
+ }
145
+ async completeRun(id, token, result) {
146
+ this.assertWritable();
147
+ const completedAt = this.now().toISOString();
148
+ const changed = this.db.execute(`UPDATE durable_agents SET
149
+ state = ?, session_health = ?, active_run_token = NULL, active_owner_pid = NULL,
150
+ active_owner_started_at = NULL, active_provider_pid = NULL, active_provider_started_at = NULL,
151
+ active_run_started_at = NULL, last_active_at = ?, updated_at = ?, last_result_status = ?,
152
+ last_result_completed_at = ?, last_result_exit_code = ?, last_result_summary = ?
153
+ WHERE id = ? AND state = 'running' AND active_run_token = ?`, [
154
+ result.status === 'succeeded' ? 'ready' : 'degraded',
155
+ result.sessionHealth,
156
+ completedAt,
157
+ completedAt,
158
+ result.status,
159
+ completedAt,
160
+ result.exitCode,
161
+ result.summary.slice(0, 4096),
162
+ id,
163
+ token
164
+ ]);
165
+ if (changed.changes !== 1) throw new DurableAgentRepositoryError('Print run ownership changed.');
166
+ return this.requireById(id);
167
+ }
168
+ async reconcile() {
169
+ this.assertWritable();
170
+ const running = this.listRaw().filter((agent)=>agent.state === 'running' && agent.activeRun);
171
+ for (const snapshot of running){
172
+ if (this.isActive(snapshot.activeRun)) continue;
173
+ const completedAt = this.now().toISOString();
174
+ this.db.execute(`UPDATE durable_agents SET
175
+ state = 'degraded', session_health = 'unknown', active_run_token = NULL,
176
+ active_owner_pid = NULL, active_owner_started_at = NULL, active_provider_pid = NULL,
177
+ active_provider_started_at = NULL, active_run_started_at = NULL, updated_at = ?, last_active_at = ?,
178
+ last_result_status = 'interrupted', last_result_completed_at = ?, last_result_exit_code = NULL,
179
+ last_result_summary = 'Previous print run was interrupted.'
180
+ WHERE id = ? AND state = 'running' AND active_run_token = ?
181
+ AND active_owner_started_at = ? AND active_run_started_at = ?`, [
182
+ completedAt,
183
+ completedAt,
184
+ completedAt,
185
+ snapshot.id,
186
+ snapshot.activeRun.token,
187
+ snapshot.activeRun.owner.startedAt,
188
+ snapshot.activeRun.startedAt
189
+ ]);
190
+ }
191
+ }
192
+ immediate(operation) {
193
+ this.db.instance.exec('BEGIN IMMEDIATE');
194
+ try {
195
+ const result = operation();
196
+ this.db.instance.exec('COMMIT');
197
+ return result;
198
+ } catch (error) {
199
+ try {
200
+ this.db.instance.exec('ROLLBACK');
201
+ } catch {}
202
+ throw error;
203
+ }
204
+ }
205
+ listRaw() {
206
+ try {
207
+ return this.db.query('SELECT * FROM durable_agents ORDER BY updated_at DESC, name COLLATE NOCASE').map((row)=>this.fromRow(row));
208
+ } catch (error) {
209
+ throw this.storageError('Failed to read durable-agent database', error);
210
+ }
211
+ }
212
+ findById(id) {
213
+ const row = this.db.queryOne('SELECT * FROM durable_agents WHERE id = ?', [
214
+ id
215
+ ]);
216
+ return row ? this.fromRow(row) : null;
217
+ }
218
+ requireById(id) {
219
+ const agent = this.findById(id);
220
+ if (!agent) throw new DurableAgentNotFoundError(id);
221
+ return agent;
222
+ }
223
+ fromRow(row) {
224
+ const activeRun = row.active_run_token === null ? null : {
225
+ token: row.active_run_token,
226
+ owner: {
227
+ pid: row.active_owner_pid,
228
+ startedAt: row.active_owner_started_at
229
+ },
230
+ provider: row.active_provider_pid === null ? null : {
231
+ pid: row.active_provider_pid,
232
+ startedAt: row.active_provider_started_at
233
+ },
234
+ startedAt: row.active_run_started_at
235
+ };
236
+ return {
237
+ id: row.id,
238
+ name: row.name,
239
+ provider: row.provider,
240
+ mode: row.mode,
241
+ cwd: row.cwd,
242
+ providerSessionId: row.provider_session_id,
243
+ state: row.state,
244
+ sessionHealth: row.session_health,
245
+ createdAt: row.created_at,
246
+ updatedAt: row.updated_at,
247
+ lastActiveAt: row.last_active_at,
248
+ lastResult: row.last_result_status === null ? null : {
249
+ status: row.last_result_status,
250
+ completedAt: row.last_result_completed_at,
251
+ exitCode: row.last_result_exit_code,
252
+ summary: row.last_result_summary ?? ''
253
+ },
254
+ activeRun
255
+ };
256
+ }
257
+ canonicalDirectory(input) {
258
+ try {
259
+ const resolved = fs.realpathSync(input);
260
+ if (!fs.statSync(resolved).isDirectory()) throw new Error('not a directory');
261
+ return resolved;
262
+ } catch {
263
+ throw new DurableAgentRepositoryError(`Durable agent cwd is not an existing directory: ${input}`);
264
+ }
265
+ }
266
+ validateBoundCwd(bound) {
267
+ try {
268
+ const stat = fs.lstatSync(bound);
269
+ if (!stat.isDirectory() || stat.isSymbolicLink() || fs.realpathSync(bound) !== bound) throw new Error('binding changed');
270
+ } catch {
271
+ throw new DurableAgentRepositoryError(`Durable agent cwd binding is no longer safe: ${bound}`);
272
+ }
273
+ }
274
+ isActive(metadata) {
275
+ return this.sameProcess(metadata.owner) || metadata.provider !== null && this.sameProcess(metadata.provider);
276
+ }
277
+ sameProcess(expected) {
278
+ const actual = this.processInspector.getIdentity(expected.pid);
279
+ return actual !== null && actual.startedAt === expected.startedAt;
280
+ }
281
+ assertWritable() {
282
+ if (this.readonly) throw new DurableAgentRepositoryError('Durable-agent repository is readonly.');
283
+ }
284
+ storageError(prefix, error) {
285
+ return error instanceof DurableAgentRepositoryError ? error : new DurableAgentRepositoryError(`${prefix}: ${error.message}`);
286
+ }
287
+ }
288
+ export class LocalProcessInspector {
289
+ getIdentity(pid) {
290
+ if (!Number.isInteger(pid) || pid <= 0) return null;
291
+ try {
292
+ if (process.platform === 'linux') {
293
+ const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
294
+ const close = stat.lastIndexOf(')');
295
+ const fields = stat.slice(close + 2).split(' ');
296
+ const startTicks = fields[19];
297
+ return startTicks ? {
298
+ pid,
299
+ startedAt: `linux:${startTicks}`
300
+ } : null;
301
+ }
302
+ const startedAt = execFileSync('ps', [
303
+ '-o',
304
+ 'lstart=',
305
+ '-p',
306
+ String(pid)
307
+ ], {
308
+ encoding: 'utf8',
309
+ stdio: [
310
+ 'ignore',
311
+ 'pipe',
312
+ 'ignore'
313
+ ]
314
+ }).trim();
315
+ return startedAt ? {
316
+ pid,
317
+ startedAt
318
+ } : null;
319
+ } catch {
320
+ return null;
321
+ }
322
+ }
323
+ }
324
+
325
+ //# sourceMappingURL=DurableAgentRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/durable/DurableAgentRepository.ts"],"sourcesContent":["import fs from 'fs';\nimport { randomUUID } from 'crypto';\nimport { execFileSync } from 'child_process';\nimport { DatabaseConnection, DEFAULT_AGENT_REGISTRY_DB_PATH } from '../database/index.js';\nimport { AGENT_MODES, type DurableActiveRun, type DurableAgent, type ProcessIdentity, type DurableRunStatus, type DurableSessionHealth } from './DurableAgent.js';\nimport {\n DurableAgentBusyError,\n DurableAgentNameConflictError,\n DurableAgentNotFoundError,\n DurableAgentRepositoryError,\n} from './DurableAgent.js';\n\ninterface DurableAgentRow {\n id: string; name: string; provider: 'claude'; mode: typeof AGENT_MODES.DURABLE; cwd: string; provider_session_id: string;\n state: DurableAgent['state']; session_health: DurableSessionHealth; created_at: string; updated_at: string;\n last_active_at: string | null; last_result_status: DurableRunStatus | null;\n last_result_completed_at: string | null; last_result_exit_code: number | null; last_result_summary: string | null;\n active_run_token: string | null; active_owner_pid: number | null; active_owner_started_at: string | null;\n active_provider_pid: number | null; active_provider_started_at: string | null; active_run_started_at: string | null;\n}\n\nexport interface CreateDurableAgentInput { name: string; cwd: string }\n\nexport interface DurableAgentRepositoryOptions {\n dbPath?: string;\n readonly?: boolean;\n /** @deprecated SQLite busy_timeout replaces filesystem lock polling. */\n lockTimeoutMs?: number;\n now?: () => Date;\n processInspector?: ProcessInspector;\n /** @deprecated Active ownership is committed atomically. */\n incompleteLockGraceMs?: number;\n /** @deprecated SQLite transactions replace mutation lock directories. */\n mutationLockStaleMs?: number;\n}\n\nexport interface ProcessInspector { getIdentity(pid: number): ProcessIdentity | null }\nexport interface DurableRunCompletion {\n status: DurableRunStatus; exitCode: number | null; summary: string; sessionHealth: DurableSessionHealth;\n}\n\nexport class DurableAgentRepository {\n readonly dbPath: string;\n private readonly now: () => Date;\n private readonly processInspector: ProcessInspector;\n private readonly readonly: boolean;\n private readonly db: DatabaseConnection;\n\n constructor(options: DurableAgentRepositoryOptions = {}) {\n this.dbPath = options.dbPath ?? DEFAULT_AGENT_REGISTRY_DB_PATH;\n this.now = options.now ?? (() => new Date());\n this.processInspector = options.processInspector ?? new LocalProcessInspector();\n this.readonly = options.readonly ?? false;\n try {\n this.db = new DatabaseConnection({ dbPath: this.dbPath, readonly: this.readonly });\n } catch (error) {\n if (error instanceof DurableAgentRepositoryError) throw error;\n throw new DurableAgentRepositoryError(`Cannot open durable-agent database: ${(error as Error).message}`);\n }\n }\n\n async create(input: CreateDurableAgentInput): Promise<DurableAgent> {\n this.assertWritable();\n const cwd = this.canonicalDirectory(input.cwd);\n const timestamp = this.now().toISOString();\n const id = randomUUID();\n let providerSessionId = randomUUID();\n while (providerSessionId === id) providerSessionId = randomUUID();\n try {\n this.db.execute(`INSERT INTO durable_agents (\n id, name, provider, mode, cwd, provider_session_id, state, session_health, created_at, updated_at\n ) VALUES (?, ?, 'claude', ?, ?, ?, 'ready', 'uninitialized', ?, ?)`,\n [id, input.name, AGENT_MODES.DURABLE, cwd, providerSessionId, timestamp, timestamp]);\n } catch (error) {\n if (/UNIQUE constraint failed: durable_agents\\.name/i.test((error as Error).message)) {\n throw new DurableAgentNameConflictError(input.name);\n }\n throw this.storageError('Failed to create durable agent', error);\n }\n return this.requireById(id);\n }\n\n async list(): Promise<DurableAgent[]> {\n if (!this.readonly) await this.reconcile();\n return this.listRaw();\n }\n\n async getById(id: string): Promise<DurableAgent | null> {\n if (!this.readonly) await this.reconcile();\n return this.findById(id);\n }\n\n async resolve(reference: string): Promise<DurableAgent | DurableAgent[] | null> {\n const agents = await this.list();\n const byId = agents.find((agent) => agent.id === reference);\n if (byId) return byId;\n const matches = agents.filter((agent) => agent.name.toLowerCase() === reference.toLowerCase());\n return matches.length === 0 ? null : matches.length === 1 ? matches[0]! : matches;\n }\n\n async acquireRun(id: string): Promise<{ agent: DurableAgent; token: string }> {\n this.assertWritable();\n const snapshot = this.findById(id);\n if (!snapshot) throw new DurableAgentNotFoundError(id);\n this.validateBoundCwd(snapshot.cwd);\n const observed = snapshot.activeRun;\n const observedLive = observed ? this.isActive(observed) : false;\n if (observedLive) throw new DurableAgentBusyError(id, snapshot.name);\n const owner = this.processInspector.getIdentity(process.pid);\n if (!owner) throw new DurableAgentRepositoryError('Cannot determine the current process identity.');\n const token = randomUUID();\n const startedAt = this.now().toISOString();\n let recovered = false;\n try {\n this.immediate(() => {\n const current = this.findById(id);\n if (!current) throw new DurableAgentNotFoundError(id);\n if (current.state === 'running') {\n if (!observed || current.activeRun?.token !== observed.token || observedLive) {\n throw new DurableAgentBusyError(id, current.name);\n }\n recovered = true;\n }\n const changed = this.db.execute(`UPDATE durable_agents SET\n state = 'running', active_run_token = ?, active_owner_pid = ?, active_owner_started_at = ?,\n active_provider_pid = NULL, active_provider_started_at = NULL, active_run_started_at = ?, updated_at = ?,\n session_health = CASE WHEN state = 'running' THEN 'unknown' ELSE session_health END,\n last_result_status = CASE WHEN state = 'running' THEN 'interrupted' ELSE last_result_status END,\n last_result_completed_at = CASE WHEN state = 'running' THEN ? ELSE last_result_completed_at END,\n last_result_exit_code = CASE WHEN state = 'running' THEN NULL ELSE last_result_exit_code END,\n last_result_summary = CASE WHEN state = 'running' THEN 'Previous print run was interrupted.' ELSE last_result_summary END\n WHERE id = ? AND (state <> 'running' OR (\n active_run_token = ? AND active_owner_started_at = ? AND active_run_started_at = ?\n ))\n `, [token, owner.pid, owner.startedAt, startedAt, startedAt, startedAt, id,\n observed?.token ?? null, observed?.owner.startedAt ?? null, observed?.startedAt ?? null]);\n if (changed.changes !== 1) throw new DurableAgentBusyError(id, current.name);\n });\n } catch (error) {\n if (error instanceof DurableAgentBusyError || error instanceof DurableAgentNotFoundError) throw error;\n if (/busy|locked/i.test((error as Error).message)) throw new DurableAgentBusyError(id, snapshot.name);\n throw this.storageError('Failed to acquire durable-agent run', error);\n }\n const agent = this.requireById(id);\n if (recovered && agent.lastResult?.status !== 'interrupted') {\n throw new DurableAgentRepositoryError('Failed to record interrupted print run.');\n }\n return { agent, token };\n }\n\n async recordProviderProcess(id: string, token: string, identity: ProcessIdentity): Promise<void> {\n this.assertWritable();\n const changed = this.db.execute(`UPDATE durable_agents SET\n active_provider_pid = ?, active_provider_started_at = ?, updated_at = ?\n WHERE id = ? AND state = 'running' AND active_run_token = ?`,\n [identity.pid, identity.startedAt, this.now().toISOString(), id, token]);\n if (changed.changes !== 1) throw new DurableAgentRepositoryError('Print run ownership changed.');\n }\n\n async completeRun(id: string, token: string, result: DurableRunCompletion): Promise<DurableAgent> {\n this.assertWritable();\n const completedAt = this.now().toISOString();\n const changed = this.db.execute(`UPDATE durable_agents SET\n state = ?, session_health = ?, active_run_token = NULL, active_owner_pid = NULL,\n active_owner_started_at = NULL, active_provider_pid = NULL, active_provider_started_at = NULL,\n active_run_started_at = NULL, last_active_at = ?, updated_at = ?, last_result_status = ?,\n last_result_completed_at = ?, last_result_exit_code = ?, last_result_summary = ?\n WHERE id = ? AND state = 'running' AND active_run_token = ?`, [\n result.status === 'succeeded' ? 'ready' : 'degraded', result.sessionHealth, completedAt, completedAt,\n result.status, completedAt, result.exitCode, result.summary.slice(0, 4096), id, token,\n ]);\n if (changed.changes !== 1) throw new DurableAgentRepositoryError('Print run ownership changed.');\n return this.requireById(id);\n }\n\n async reconcile(): Promise<void> {\n this.assertWritable();\n const running = this.listRaw().filter((agent) => agent.state === 'running' && agent.activeRun);\n for (const snapshot of running) {\n if (this.isActive(snapshot.activeRun!)) continue;\n const completedAt = this.now().toISOString();\n this.db.execute(`UPDATE durable_agents SET\n state = 'degraded', session_health = 'unknown', active_run_token = NULL,\n active_owner_pid = NULL, active_owner_started_at = NULL, active_provider_pid = NULL,\n active_provider_started_at = NULL, active_run_started_at = NULL, updated_at = ?, last_active_at = ?,\n last_result_status = 'interrupted', last_result_completed_at = ?, last_result_exit_code = NULL,\n last_result_summary = 'Previous print run was interrupted.'\n WHERE id = ? AND state = 'running' AND active_run_token = ?\n AND active_owner_started_at = ? AND active_run_started_at = ?`, [\n completedAt, completedAt, completedAt, snapshot.id, snapshot.activeRun!.token,\n snapshot.activeRun!.owner.startedAt, snapshot.activeRun!.startedAt,\n ]);\n }\n }\n\n private immediate<T>(operation: () => T): T {\n this.db.instance.exec('BEGIN IMMEDIATE');\n try {\n const result = operation();\n this.db.instance.exec('COMMIT');\n return result;\n } catch (error) {\n try { this.db.instance.exec('ROLLBACK'); } catch { /* retain original failure */ }\n throw error;\n }\n }\n\n private listRaw(): DurableAgent[] {\n try {\n return this.db.query<DurableAgentRow>(\n 'SELECT * FROM durable_agents ORDER BY updated_at DESC, name COLLATE NOCASE',\n ).map((row) => this.fromRow(row));\n } catch (error) {\n throw this.storageError('Failed to read durable-agent database', error);\n }\n }\n\n private findById(id: string): DurableAgent | null {\n const row = this.db.queryOne<DurableAgentRow>('SELECT * FROM durable_agents WHERE id = ?', [id]);\n return row ? this.fromRow(row) : null;\n }\n\n private requireById(id: string): DurableAgent {\n const agent = this.findById(id);\n if (!agent) throw new DurableAgentNotFoundError(id);\n return agent;\n }\n\n private fromRow(row: DurableAgentRow): DurableAgent {\n const activeRun: DurableActiveRun | null = row.active_run_token === null ? null : {\n token: row.active_run_token,\n owner: { pid: row.active_owner_pid!, startedAt: row.active_owner_started_at! },\n provider: row.active_provider_pid === null ? null : {\n pid: row.active_provider_pid, startedAt: row.active_provider_started_at!,\n },\n startedAt: row.active_run_started_at!,\n };\n return {\n id: row.id, name: row.name, provider: row.provider, mode: row.mode, cwd: row.cwd,\n providerSessionId: row.provider_session_id, state: row.state, sessionHealth: row.session_health,\n createdAt: row.created_at, updatedAt: row.updated_at, lastActiveAt: row.last_active_at,\n lastResult: row.last_result_status === null ? null : {\n status: row.last_result_status, completedAt: row.last_result_completed_at!,\n exitCode: row.last_result_exit_code, summary: row.last_result_summary ?? '',\n },\n activeRun,\n };\n }\n\n private canonicalDirectory(input: string): string {\n try {\n const resolved = fs.realpathSync(input);\n if (!fs.statSync(resolved).isDirectory()) throw new Error('not a directory');\n return resolved;\n } catch {\n throw new DurableAgentRepositoryError(`Durable agent cwd is not an existing directory: ${input}`);\n }\n }\n\n private validateBoundCwd(bound: string): void {\n try {\n const stat = fs.lstatSync(bound);\n if (!stat.isDirectory() || stat.isSymbolicLink() || fs.realpathSync(bound) !== bound) throw new Error('binding changed');\n } catch {\n throw new DurableAgentRepositoryError(`Durable agent cwd binding is no longer safe: ${bound}`);\n }\n }\n\n private isActive(metadata: DurableActiveRun): boolean {\n return this.sameProcess(metadata.owner) || (metadata.provider !== null && this.sameProcess(metadata.provider));\n }\n\n private sameProcess(expected: ProcessIdentity): boolean {\n const actual = this.processInspector.getIdentity(expected.pid);\n return actual !== null && actual.startedAt === expected.startedAt;\n }\n\n private assertWritable(): void {\n if (this.readonly) throw new DurableAgentRepositoryError('Durable-agent repository is readonly.');\n }\n\n private storageError(prefix: string, error: unknown): DurableAgentRepositoryError {\n return error instanceof DurableAgentRepositoryError ? error\n : new DurableAgentRepositoryError(`${prefix}: ${(error as Error).message}`);\n }\n}\n\nexport class LocalProcessInspector implements ProcessInspector {\n getIdentity(pid: number): ProcessIdentity | null {\n if (!Number.isInteger(pid) || pid <= 0) return null;\n try {\n if (process.platform === 'linux') {\n const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');\n const close = stat.lastIndexOf(')');\n const fields = stat.slice(close + 2).split(' ');\n const startTicks = fields[19];\n return startTicks ? { pid, startedAt: `linux:${startTicks}` } : null;\n }\n const startedAt = execFileSync('ps', ['-o', 'lstart=', '-p', String(pid)], {\n encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return startedAt ? { pid, startedAt } : null;\n } catch {\n return null;\n }\n }\n}\n"],"names":["fs","randomUUID","execFileSync","DatabaseConnection","DEFAULT_AGENT_REGISTRY_DB_PATH","AGENT_MODES","DurableAgentBusyError","DurableAgentNameConflictError","DurableAgentNotFoundError","DurableAgentRepositoryError","DurableAgentRepository","dbPath","now","processInspector","readonly","db","options","Date","LocalProcessInspector","error","message","create","input","assertWritable","cwd","canonicalDirectory","timestamp","toISOString","id","providerSessionId","execute","name","DURABLE","test","storageError","requireById","list","reconcile","listRaw","getById","findById","resolve","reference","agents","byId","find","agent","matches","filter","toLowerCase","length","acquireRun","snapshot","validateBoundCwd","observed","activeRun","observedLive","isActive","owner","getIdentity","process","pid","token","startedAt","recovered","immediate","current","state","changed","changes","lastResult","status","recordProviderProcess","identity","completeRun","result","completedAt","sessionHealth","exitCode","summary","slice","running","operation","instance","exec","query","map","row","fromRow","queryOne","active_run_token","active_owner_pid","active_owner_started_at","provider","active_provider_pid","active_provider_started_at","active_run_started_at","mode","provider_session_id","session_health","createdAt","created_at","updatedAt","updated_at","lastActiveAt","last_active_at","last_result_status","last_result_completed_at","last_result_exit_code","last_result_summary","resolved","realpathSync","statSync","isDirectory","Error","bound","stat","lstatSync","isSymbolicLink","metadata","sameProcess","expected","actual","prefix","Number","isInteger","platform","readFileSync","close","lastIndexOf","fields","split","startTicks","String","encoding","stdio","trim"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -22,15 +22,15 @@ export { AGENTS } from './utils/agents.js';
22
22
  export type { AgentConfig, StartableAgentType } from './utils/agents.js';
23
23
  export type { AgentRequest } from './utils/agent-requests.js';
24
24
  export { getAgentRequestPath, readLatestAgentRequest, writeAgentRequest } from './utils/agent-requests.js';
25
- export { PrintAgentError, PrintAgentBusyError, PrintAgentNotFoundError, PrintAgentStoreError, PrintAgentNameConflictError, ClaudePrintError, } from './print/PrintAgent.js';
26
- export type { PrintAgent, PrintAgentState, PrintSessionHealth, PrintRunStatus, PrintActiveRun, PrintLastResult, ProcessIdentity, } from './print/PrintAgent.js';
27
- export { PrintAgentStore } from './print/PrintAgentStore.js';
28
- export { LocalProcessInspector } from './print/PrintAgentStore.js';
29
- export type { CreatePrintAgentInput, PrintAgentStoreOptions, ProcessInspector, PrintRunCompletion, } from './print/PrintAgentStore.js';
30
- export { ClaudeCliProbe } from './print/ClaudeCliProbe.js';
31
- export type { ClaudeCliProbeOptions } from './print/ClaudeCliProbe.js';
32
- export { ClaudePrintRunner } from './print/ClaudePrintRunner.js';
33
- export type { ClaudePrintRunnerOptions, ClaudePrintRunRequest, ClaudePrintRunResult, } from './print/ClaudePrintRunner.js';
34
- export { ClaudePrintAgentService } from './print/ClaudePrintAgentService.js';
35
- export type { ClaudePrintAgentServiceOptions, ClaudePrintSendResult, } from './print/ClaudePrintAgentService.js';
25
+ export { AGENT_MODES, DurableAgentError, DurableAgentBusyError, DurableAgentNotFoundError, DurableAgentRepositoryError, DurableAgentNameConflictError, ClaudePrintError, } from './durable/DurableAgent.js';
26
+ export type { DurableAgent, DurableAgentState, DurableSessionHealth, DurableRunStatus, DurableActiveRun, DurableLastResult, ProcessIdentity, } from './durable/DurableAgent.js';
27
+ export { DurableAgentRepository } from './durable/DurableAgentRepository.js';
28
+ export { LocalProcessInspector } from './durable/DurableAgentRepository.js';
29
+ export type { CreateDurableAgentInput, DurableAgentRepositoryOptions, ProcessInspector, DurableRunCompletion, } from './durable/DurableAgentRepository.js';
30
+ export { ClaudeCliProbe } from './durable/ClaudeCliProbe.js';
31
+ export type { ClaudeCliProbeOptions } from './durable/ClaudeCliProbe.js';
32
+ export { ClaudePrintRunner } from './durable/ClaudePrintRunner.js';
33
+ export type { ClaudePrintRunnerOptions, ClaudePrintRunRequest, ClaudePrintRunResult, } from './durable/ClaudePrintRunner.js';
34
+ export { ClaudePrintAgentService } from './durable/ClaudePrintAgentService.js';
35
+ export type { ClaudePrintAgentServiceOptions, ClaudePrintSendResult, } from './durable/ClaudePrintAgentService.js';
36
36
  //# sourceMappingURL=index.d.ts.map