@ai-devkit/agent-manager 0.27.0 → 0.28.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/README.md +12 -4
- package/dist/__tests__/adapters/CodexAdapter.test.js +199 -0
- package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
- package/dist/__tests__/database/DurableAgentsDatabase.test.js +100 -0
- package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +1 -0
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +7 -7
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +7 -7
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +1 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgent.test.js +17 -0
- package/dist/__tests__/print/DurableAgent.test.js.map +1 -0
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +186 -0
- package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -0
- package/dist/__tests__/print/{PrintAgentStore.test.js → DurableAgentRepository.test.js} +63 -110
- package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -0
- package/dist/adapters/CodexAdapter.d.ts +1 -0
- package/dist/adapters/CodexAdapter.d.ts.map +1 -1
- package/dist/adapters/CodexAdapter.js +16 -6
- package/dist/adapters/CodexAdapter.js.map +1 -1
- package/dist/database/connection.d.ts.map +1 -1
- package/dist/database/connection.js +17 -9
- package/dist/database/connection.js.map +1 -1
- package/dist/database/migrations/003_durable_agents.sql +43 -0
- package/dist/durable/ClaudeCliProbe.d.ts.map +1 -0
- package/dist/{print → durable}/ClaudeCliProbe.js +1 -1
- package/dist/durable/ClaudeCliProbe.js.map +1 -0
- package/dist/{print → durable}/ClaudePrintAgentService.d.ts +11 -11
- package/dist/durable/ClaudePrintAgentService.d.ts.map +1 -0
- package/dist/{print → durable}/ClaudePrintAgentService.js +12 -12
- package/dist/durable/ClaudePrintAgentService.js.map +1 -0
- package/dist/{print → durable}/ClaudePrintRunner.d.ts +3 -3
- package/dist/durable/ClaudePrintRunner.d.ts.map +1 -0
- package/dist/{print → durable}/ClaudePrintRunner.js +2 -2
- package/dist/durable/ClaudePrintRunner.js.map +1 -0
- package/dist/durable/DurableAgent.d.ts +61 -0
- package/dist/durable/DurableAgent.d.ts.map +1 -0
- package/dist/durable/DurableAgent.js +46 -0
- package/dist/durable/DurableAgent.js.map +1 -0
- package/dist/durable/DurableAgentRepository.d.ts +60 -0
- package/dist/durable/DurableAgentRepository.d.ts.map +1 -0
- package/dist/durable/DurableAgentRepository.js +325 -0
- package/dist/durable/DurableAgentRepository.js.map +1 -0
- package/dist/index.d.ts +11 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/adapters/CodexAdapter.test.ts +132 -0
- package/src/__tests__/database/DurableAgentsDatabase.test.ts +77 -0
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +6 -6
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +7 -7
- package/src/__tests__/print/ClaudePrintRunner.test.ts +3 -3
- package/src/__tests__/print/{PrintAgent.test.ts → DurableAgent.test.ts} +6 -6
- package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +105 -0
- package/src/__tests__/print/DurableAgentRepository.test.ts +163 -0
- package/src/adapters/CodexAdapter.ts +14 -11
- package/src/database/connection.ts +15 -9
- package/src/database/migrations/003_durable_agents.sql +43 -0
- package/src/{print → durable}/ClaudeCliProbe.ts +1 -1
- package/src/{print → durable}/ClaudePrintAgentService.ts +21 -21
- package/src/{print → durable}/ClaudePrintRunner.ts +4 -4
- package/src/durable/DurableAgent.ts +91 -0
- package/src/durable/DurableAgentRepository.ts +307 -0
- package/src/index.ts +26 -25
- package/dist/__tests__/print/PrintAgent.test.js +0 -17
- package/dist/__tests__/print/PrintAgent.test.js.map +0 -1
- package/dist/__tests__/print/PrintAgentStore.test.js.map +0 -1
- package/dist/print/ClaudeCliProbe.d.ts.map +0 -1
- package/dist/print/ClaudeCliProbe.js.map +0 -1
- package/dist/print/ClaudePrintAgentService.d.ts.map +0 -1
- package/dist/print/ClaudePrintAgentService.js.map +0 -1
- package/dist/print/ClaudePrintRunner.d.ts.map +0 -1
- package/dist/print/ClaudePrintRunner.js.map +0 -1
- package/dist/print/PrintAgent.d.ts +0 -57
- package/dist/print/PrintAgent.d.ts.map +0 -1
- package/dist/print/PrintAgent.js +0 -42
- package/dist/print/PrintAgent.js.map +0 -1
- package/dist/print/PrintAgentStore.d.ts +0 -69
- package/dist/print/PrintAgentStore.d.ts.map +0 -1
- package/dist/print/PrintAgentStore.js +0 -484
- package/dist/print/PrintAgentStore.js.map +0 -1
- package/src/__tests__/print/PrintAgentStore.test.ts +0 -192
- package/src/print/PrintAgent.ts +0 -86
- package/src/print/PrintAgentStore.ts +0 -503
- /package/dist/{print → durable}/ClaudeCliProbe.d.ts +0 -0
package/README.md
CHANGED
|
@@ -24,19 +24,27 @@ ai-devkit agent send "run the tests and report back" --id <agent-name> --wait
|
|
|
24
24
|
npm test 2>&1 | ai-devkit agent send --id <agent-name> --stdin
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Claude Code can also be registered as a durable
|
|
27
|
+
Claude Code can also be registered as a durable agent. Registration
|
|
28
28
|
does not launch Claude; each send starts one synchronous process and later sends
|
|
29
29
|
resume the same Claude session:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
ai-devkit agent start --type claude --mode
|
|
32
|
+
ai-devkit agent start --type claude --mode durable --name reviewer --cwd /path/to/project
|
|
33
33
|
ai-devkit agent send "review the current diff" --id reviewer
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
Durable mode inherits Claude Code's settings, permissions, hooks, MCP servers, and
|
|
37
37
|
tool side effects for that working directory. AI DevKit adds no permission bypass
|
|
38
38
|
or automatic retry, and prompts are delivered over stdin rather than command-line
|
|
39
|
-
arguments. `--timeout` is not supported for
|
|
39
|
+
arguments. `--timeout` is not supported for durable agents in this first release.
|
|
40
|
+
|
|
41
|
+
Durable durable-agent state is stored in `~/.ai-devkit/agents.db`. This feature was
|
|
42
|
+
not released with JSON persistence, so there is no legacy import or dual-write.
|
|
43
|
+
|
|
44
|
+
For direct `DurableAgentRepository` consumers, `dbPath` selects the SQLite database. The
|
|
45
|
+
`lockTimeoutMs`, `incompleteLockGraceMs`, and `mutationLockStaleMs` options are
|
|
46
|
+
deprecated, accepted, and ignored because SQLite transactions replace the
|
|
47
|
+
filesystem lock machinery.
|
|
40
48
|
|
|
41
49
|
Use this package directly only when building custom tooling around AI DevKit's agent detection and control surface.
|
|
42
50
|
|
|
@@ -884,6 +884,65 @@ describe('CodexAdapter', ()=>{
|
|
|
884
884
|
expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
|
|
885
885
|
expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
|
|
886
886
|
});
|
|
887
|
+
it('uses the hook session mapping instead of a stale registry entry for the same live pid', async ()=>{
|
|
888
|
+
registerEntry();
|
|
889
|
+
const sessionsDir = path.join(tmpDir, '.codex', 'sessions');
|
|
890
|
+
const dateDir = path.join(sessionsDir, '2026', '06', '26');
|
|
891
|
+
const mappingPath = path.join(tmpDir, '.codex', 'ai-devkit', 'sessions.json');
|
|
892
|
+
const currentSessionFile = path.join(dateDir, 'sess-current.jsonl');
|
|
893
|
+
const recentTs = new Date().toISOString();
|
|
894
|
+
fs.mkdirSync(dateDir, {
|
|
895
|
+
recursive: true
|
|
896
|
+
});
|
|
897
|
+
fs.mkdirSync(path.dirname(mappingPath), {
|
|
898
|
+
recursive: true
|
|
899
|
+
});
|
|
900
|
+
fs.writeFileSync(currentSessionFile, [
|
|
901
|
+
JSON.stringify({
|
|
902
|
+
type: 'session_meta',
|
|
903
|
+
payload: {
|
|
904
|
+
id: 'sess-current',
|
|
905
|
+
timestamp: recentTs,
|
|
906
|
+
cwd: '/repo-current'
|
|
907
|
+
}
|
|
908
|
+
}),
|
|
909
|
+
JSON.stringify({
|
|
910
|
+
type: 'event',
|
|
911
|
+
timestamp: recentTs,
|
|
912
|
+
payload: {
|
|
913
|
+
type: 'token_count',
|
|
914
|
+
message: 'Hello from current mapping'
|
|
915
|
+
}
|
|
916
|
+
})
|
|
917
|
+
].join('\n'));
|
|
918
|
+
fs.writeFileSync(mappingPath, JSON.stringify({
|
|
919
|
+
100: currentSessionFile
|
|
920
|
+
}));
|
|
921
|
+
cachedAdapter.codexSessionsDir = sessionsDir;
|
|
922
|
+
cachedAdapter.sessionMappingPath = mappingPath;
|
|
923
|
+
const processes = [
|
|
924
|
+
{
|
|
925
|
+
pid: 100,
|
|
926
|
+
command: 'codex',
|
|
927
|
+
cwd: '/repo-current',
|
|
928
|
+
tty: 'ttys001',
|
|
929
|
+
startTime: new Date()
|
|
930
|
+
}
|
|
931
|
+
];
|
|
932
|
+
mockedListAgentProcesses.mockReturnValue(processes);
|
|
933
|
+
mockedEnrichProcesses.mockReturnValue(processes);
|
|
934
|
+
const agents = await cachedAdapter.detectAgents();
|
|
935
|
+
expect(agents).toHaveLength(1);
|
|
936
|
+
expect(agents[0]).toMatchObject({
|
|
937
|
+
type: 'codex',
|
|
938
|
+
pid: 100,
|
|
939
|
+
sessionId: 'sess-current',
|
|
940
|
+
sessionFilePath: currentSessionFile,
|
|
941
|
+
summary: 'Hello from current mapping'
|
|
942
|
+
});
|
|
943
|
+
expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
|
|
944
|
+
expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
|
|
945
|
+
});
|
|
887
946
|
it('falls through when no registry entry exists for the pid', async ()=>{
|
|
888
947
|
const processes = [
|
|
889
948
|
{
|
|
@@ -2152,6 +2211,146 @@ describe('CodexAdapter', ()=>{
|
|
|
2152
2211
|
expect(result).toHaveLength(1);
|
|
2153
2212
|
expect(result[0].firstUserMessage).toBe('first user');
|
|
2154
2213
|
});
|
|
2214
|
+
it('captures the first current Codex response_item user message as firstUserMessage', async ()=>{
|
|
2215
|
+
const day = path.join(sessionsDir, '2025', '01', '01');
|
|
2216
|
+
writeCodexSession(day, 'response-item-user', [
|
|
2217
|
+
{
|
|
2218
|
+
type: 'session_meta',
|
|
2219
|
+
payload: {
|
|
2220
|
+
id: 'response-item-user',
|
|
2221
|
+
cwd: '/repo',
|
|
2222
|
+
timestamp: '2025-01-01T00:00:00Z'
|
|
2223
|
+
}
|
|
2224
|
+
},
|
|
2225
|
+
{
|
|
2226
|
+
type: 'response_item',
|
|
2227
|
+
timestamp: '2025-01-01T00:00:00.500Z',
|
|
2228
|
+
payload: {
|
|
2229
|
+
type: 'message',
|
|
2230
|
+
role: 'user',
|
|
2231
|
+
content: [
|
|
2232
|
+
{
|
|
2233
|
+
type: 'input_text',
|
|
2234
|
+
text: '<environment_context>\n <cwd>/repo</cwd>\n</environment_context>'
|
|
2235
|
+
}
|
|
2236
|
+
]
|
|
2237
|
+
}
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
type: 'response_item',
|
|
2241
|
+
timestamp: '2025-01-01T00:00:01Z',
|
|
2242
|
+
payload: {
|
|
2243
|
+
type: 'message',
|
|
2244
|
+
role: 'assistant',
|
|
2245
|
+
content: [
|
|
2246
|
+
{
|
|
2247
|
+
type: 'output_text',
|
|
2248
|
+
text: 'preamble'
|
|
2249
|
+
}
|
|
2250
|
+
]
|
|
2251
|
+
}
|
|
2252
|
+
},
|
|
2253
|
+
{
|
|
2254
|
+
type: 'response_item',
|
|
2255
|
+
timestamp: '2025-01-01T00:00:02Z',
|
|
2256
|
+
payload: {
|
|
2257
|
+
type: 'message',
|
|
2258
|
+
role: 'user',
|
|
2259
|
+
content: [
|
|
2260
|
+
{
|
|
2261
|
+
type: 'input_text',
|
|
2262
|
+
text: 'first current user'
|
|
2263
|
+
}
|
|
2264
|
+
]
|
|
2265
|
+
}
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
type: 'response_item',
|
|
2269
|
+
timestamp: '2025-01-01T00:00:03Z',
|
|
2270
|
+
payload: {
|
|
2271
|
+
type: 'message',
|
|
2272
|
+
role: 'user',
|
|
2273
|
+
content: [
|
|
2274
|
+
{
|
|
2275
|
+
type: 'input_text',
|
|
2276
|
+
text: 'second current user'
|
|
2277
|
+
}
|
|
2278
|
+
]
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
]);
|
|
2282
|
+
const result = await adapter.listSessions({
|
|
2283
|
+
cwd: '/repo'
|
|
2284
|
+
});
|
|
2285
|
+
expect(result).toHaveLength(1);
|
|
2286
|
+
expect(result[0].firstUserMessage).toBe('first current user');
|
|
2287
|
+
});
|
|
2288
|
+
it('captures the first current Codex event_msg user message as firstUserMessage', async ()=>{
|
|
2289
|
+
const day = path.join(sessionsDir, '2025', '01', '01');
|
|
2290
|
+
writeCodexSession(day, 'event-msg-user', [
|
|
2291
|
+
{
|
|
2292
|
+
type: 'session_meta',
|
|
2293
|
+
payload: {
|
|
2294
|
+
id: 'event-msg-user',
|
|
2295
|
+
cwd: '/repo',
|
|
2296
|
+
timestamp: '2025-01-01T00:00:00Z'
|
|
2297
|
+
}
|
|
2298
|
+
},
|
|
2299
|
+
{
|
|
2300
|
+
type: 'event_msg',
|
|
2301
|
+
timestamp: '2025-01-01T00:00:01Z',
|
|
2302
|
+
payload: {
|
|
2303
|
+
type: 'item_completed',
|
|
2304
|
+
item: {
|
|
2305
|
+
type: 'AgentMessage',
|
|
2306
|
+
content: [
|
|
2307
|
+
{
|
|
2308
|
+
type: 'Text',
|
|
2309
|
+
text: 'preamble'
|
|
2310
|
+
}
|
|
2311
|
+
]
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
},
|
|
2315
|
+
{
|
|
2316
|
+
type: 'event_msg',
|
|
2317
|
+
timestamp: '2025-01-01T00:00:02Z',
|
|
2318
|
+
payload: {
|
|
2319
|
+
type: 'item_completed',
|
|
2320
|
+
item: {
|
|
2321
|
+
type: 'UserMessage',
|
|
2322
|
+
content: [
|
|
2323
|
+
{
|
|
2324
|
+
type: 'text',
|
|
2325
|
+
text: 'first event user'
|
|
2326
|
+
}
|
|
2327
|
+
]
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
},
|
|
2331
|
+
{
|
|
2332
|
+
type: 'event_msg',
|
|
2333
|
+
timestamp: '2025-01-01T00:00:03Z',
|
|
2334
|
+
payload: {
|
|
2335
|
+
type: 'item_completed',
|
|
2336
|
+
item: {
|
|
2337
|
+
type: 'UserMessage',
|
|
2338
|
+
content: [
|
|
2339
|
+
{
|
|
2340
|
+
type: 'text',
|
|
2341
|
+
text: 'second event user'
|
|
2342
|
+
}
|
|
2343
|
+
]
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
]);
|
|
2348
|
+
const result = await adapter.listSessions({
|
|
2349
|
+
cwd: '/repo'
|
|
2350
|
+
});
|
|
2351
|
+
expect(result).toHaveLength(1);
|
|
2352
|
+
expect(result[0].firstUserMessage).toBe('first event user');
|
|
2353
|
+
});
|
|
2155
2354
|
it('returns empty firstUserMessage when no user_message exists', async ()=>{
|
|
2156
2355
|
const day = path.join(sessionsDir, '2025', '01', '01');
|
|
2157
2356
|
writeCodexSession(day, 's', [
|