@ai-devkit/agent-manager 0.11.0 → 0.12.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/adapters/ClaudeCodeAdapter.d.ts +8 -0
- package/dist/adapters/ClaudeCodeAdapter.d.ts.map +1 -1
- package/dist/adapters/ClaudeCodeAdapter.js +48 -4
- package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +70 -0
- package/src/adapters/ClaudeCodeAdapter.ts +60 -4
|
@@ -26,6 +26,14 @@ export declare class ClaudeCodeAdapter implements AgentAdapter {
|
|
|
26
26
|
* via a single batched stat call across all directories.
|
|
27
27
|
*/
|
|
28
28
|
private discoverSessions;
|
|
29
|
+
/**
|
|
30
|
+
* Match processes via `claude --resume <uuid>` in their command line.
|
|
31
|
+
* This works for resumed sessions, where the JSONL was created earlier
|
|
32
|
+
* (so its birthtime is far from the process startTime and the legacy
|
|
33
|
+
* matcher can't pair them) and the PID file may also be misaligned.
|
|
34
|
+
*/
|
|
35
|
+
private tryResumeMatching;
|
|
36
|
+
private extractResumeSessionId;
|
|
29
37
|
/**
|
|
30
38
|
* Attempt to match each process to its session via ~/.claude/sessions/<pid>.json.
|
|
31
39
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeCodeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACtB,MAAM,gBAAgB,CAAC;AAkCxB;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAElC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAsB;;IASpC,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAI5C,OAAO,CAAC,kBAAkB;IAMpB,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ClaudeCodeAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACR,YAAY,EACZ,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACtB,MAAM,gBAAgB,CAAC;AAkCxB;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,YAAY;IAClD,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAElC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAsB;;IASpC,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO;IAI5C,OAAO,CAAC,kBAAkB;IAMpB,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IA+D1C;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IA6BxB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAsCzB,OAAO,CAAC,sBAAsB;IAK9B;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAkD1B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,mBAAmB;IAa3B,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE;IAI1F,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAkCzE;;;;;;;;;;OAUG;IACH,OAAO,CAAC,oBAAoB;CAqB/B"}
|
|
@@ -74,9 +74,14 @@ class ClaudeCodeAdapter {
|
|
|
74
74
|
if (processes.length === 0) {
|
|
75
75
|
return [];
|
|
76
76
|
}
|
|
77
|
-
// Step 1:
|
|
78
|
-
|
|
79
|
-
//
|
|
77
|
+
// Step 1: extract `--resume <id>` from command line — authoritative for
|
|
78
|
+
// resumed sessions where the JSONL predates the process and PID-file/
|
|
79
|
+
// birthtime heuristics can't match it.
|
|
80
|
+
const { direct: resumeDirect, fallback: noResume } = this.tryResumeMatching(processes);
|
|
81
|
+
// Step 2: try authoritative PID-file matching for the rest
|
|
82
|
+
const { direct: pidDirect, fallback } = this.tryPidFileMatching(noResume);
|
|
83
|
+
const direct = [...resumeDirect, ...pidDirect];
|
|
84
|
+
// Step 3: run legacy CWD+birthtime matching only for processes without a PID file
|
|
80
85
|
const legacySessions = this.discoverSessions(fallback);
|
|
81
86
|
const legacyMatches = fallback.length > 0 && legacySessions.length > 0
|
|
82
87
|
? (0, matching_1.matchProcessesToSessions)(fallback, legacySessions)
|
|
@@ -86,7 +91,7 @@ class ClaudeCodeAdapter {
|
|
|
86
91
|
...legacyMatches.map((m) => m.process.pid),
|
|
87
92
|
]);
|
|
88
93
|
const agents = [];
|
|
89
|
-
// Build agents from direct (PID-file) matches
|
|
94
|
+
// Build agents from direct (resume + PID-file) matches
|
|
90
95
|
for (const { process: proc, sessionFile } of direct) {
|
|
91
96
|
const sessionData = this.parser.readSession(sessionFile.filePath, sessionFile.resolvedCwd);
|
|
92
97
|
if (sessionData) {
|
|
@@ -146,6 +151,45 @@ class ClaudeCodeAdapter {
|
|
|
146
151
|
}
|
|
147
152
|
return files;
|
|
148
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Match processes via `claude --resume <uuid>` in their command line.
|
|
156
|
+
* This works for resumed sessions, where the JSONL was created earlier
|
|
157
|
+
* (so its birthtime is far from the process startTime and the legacy
|
|
158
|
+
* matcher can't pair them) and the PID file may also be misaligned.
|
|
159
|
+
*/
|
|
160
|
+
tryResumeMatching(processes) {
|
|
161
|
+
const direct = [];
|
|
162
|
+
const fallback = [];
|
|
163
|
+
for (const proc of processes) {
|
|
164
|
+
const sessionId = this.extractResumeSessionId(proc.command);
|
|
165
|
+
if (!sessionId || !proc.cwd) {
|
|
166
|
+
fallback.push(proc);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const projectDir = this.getProjectDir(proc.cwd);
|
|
170
|
+
const jsonlPath = path.join(projectDir, `${sessionId}.jsonl`);
|
|
171
|
+
const stat = (0, session_1.safeStat)(jsonlPath);
|
|
172
|
+
if (!stat) {
|
|
173
|
+
fallback.push(proc);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
direct.push({
|
|
177
|
+
process: proc,
|
|
178
|
+
sessionFile: {
|
|
179
|
+
sessionId,
|
|
180
|
+
filePath: jsonlPath,
|
|
181
|
+
projectDir,
|
|
182
|
+
birthtimeMs: stat.birthtimeMs,
|
|
183
|
+
resolvedCwd: proc.cwd,
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return { direct, fallback };
|
|
188
|
+
}
|
|
189
|
+
extractResumeSessionId(command) {
|
|
190
|
+
const match = command.match(/--resume\s+([0-9a-f-]{36})/i);
|
|
191
|
+
return match?.[1] ?? null;
|
|
192
|
+
}
|
|
149
193
|
/**
|
|
150
194
|
* Attempt to match each process to its session via ~/.claude/sessions/<pid>.json.
|
|
151
195
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeCodeAdapter.js","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAS7B,iDAA6C;AAC7C,8CAAuE;AACvE,8CAAgH;AAEhH,gDAAgF;AAChF,sEAAmE;AAyBnE,oFAAoF;AACpF,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAEpC;;;;;;;;;GASG;AACH,MAAa,iBAAiB;IAO1B;QANS,SAAI,GAAG,QAAiB,CAAC;QAO9B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;QAClE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,GAAG,IAAI,yCAAmB,EAAE,CAAC;IAC5C,CAAC;IAED,SAAS,CAAC,WAAwB;QAC9B,OAAO,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACxD,CAAC;IAEO,kBAAkB,CAAC,OAAe;QACtC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QACrD,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,YAAY,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,YAAY;QACd,MAAM,SAAS,GAAG,IAAA,yBAAe,EAAC,IAAA,4BAAkB,EAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACd,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"ClaudeCodeAdapter.js","sourceRoot":"","sources":["../../src/adapters/ClaudeCodeAdapter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -289,6 +289,76 @@ describe('ClaudeCodeAdapter', () => {
|
|
|
289
289
|
});
|
|
290
290
|
});
|
|
291
291
|
|
|
292
|
+
it('should match via --resume <uuid> in command line and skip PID-file/legacy', async () => {
|
|
293
|
+
const sessionId = '0555f803-7eca-4fc6-a1e0-34dbf86b33b2';
|
|
294
|
+
const processes: ProcessInfo[] = [
|
|
295
|
+
{
|
|
296
|
+
pid: 41920,
|
|
297
|
+
command: `claude --resume ${sessionId}`,
|
|
298
|
+
cwd: '/project/resumed',
|
|
299
|
+
tty: 'ttys001',
|
|
300
|
+
startTime: new Date(),
|
|
301
|
+
},
|
|
302
|
+
];
|
|
303
|
+
mockedListAgentProcesses.mockReturnValue(processes);
|
|
304
|
+
mockedEnrichProcesses.mockReturnValue(processes);
|
|
305
|
+
|
|
306
|
+
const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'claude-resume-'));
|
|
307
|
+
const projectsDir = path.join(tmpDir, 'projects');
|
|
308
|
+
const projDir = path.join(projectsDir, '-project-resumed');
|
|
309
|
+
fs.mkdirSync(projDir, { recursive: true });
|
|
310
|
+
|
|
311
|
+
const jsonlPath = path.join(projDir, `${sessionId}.jsonl`);
|
|
312
|
+
fs.writeFileSync(jsonlPath, [
|
|
313
|
+
JSON.stringify({ type: 'user', timestamp: new Date().toISOString(), cwd: '/project/resumed', message: { content: 'resumed conversation' } }),
|
|
314
|
+
JSON.stringify({ type: 'assistant', timestamp: new Date().toISOString() }),
|
|
315
|
+
].join('\n'));
|
|
316
|
+
|
|
317
|
+
(adapter as any).projectsDir = projectsDir;
|
|
318
|
+
(adapter as any).sessionsDir = path.join(tmpDir, 'sessions'); // empty — no PID file
|
|
319
|
+
|
|
320
|
+
const agents = await adapter.detectAgents();
|
|
321
|
+
|
|
322
|
+
// Legacy matching helpers must NOT have been consulted — resume match was authoritative
|
|
323
|
+
expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
|
|
324
|
+
expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
|
|
325
|
+
|
|
326
|
+
expect(agents).toHaveLength(1);
|
|
327
|
+
expect(agents[0]).toMatchObject({
|
|
328
|
+
type: 'claude',
|
|
329
|
+
pid: 41920,
|
|
330
|
+
sessionId,
|
|
331
|
+
projectPath: '/project/resumed',
|
|
332
|
+
});
|
|
333
|
+
expect(agents[0].summary).toContain('resumed conversation');
|
|
334
|
+
|
|
335
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should fall through when --resume points to a JSONL that does not exist', async () => {
|
|
339
|
+
const processes: ProcessInfo[] = [
|
|
340
|
+
{
|
|
341
|
+
pid: 41921,
|
|
342
|
+
command: 'claude --resume aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
|
|
343
|
+
cwd: '/project/missing',
|
|
344
|
+
tty: 'ttys001',
|
|
345
|
+
startTime: new Date(),
|
|
346
|
+
},
|
|
347
|
+
];
|
|
348
|
+
mockedListAgentProcesses.mockReturnValue(processes);
|
|
349
|
+
mockedEnrichProcesses.mockReturnValue(processes);
|
|
350
|
+
|
|
351
|
+
// No projects dir, no PID file → both matchers fail → process-only
|
|
352
|
+
(adapter as any).projectsDir = '/nonexistent';
|
|
353
|
+
(adapter as any).sessionsDir = '/nonexistent';
|
|
354
|
+
|
|
355
|
+
const agents = await adapter.detectAgents();
|
|
356
|
+
|
|
357
|
+
expect(agents).toHaveLength(1);
|
|
358
|
+
expect(agents[0].sessionId).toBe('pid-41921');
|
|
359
|
+
expect(agents[0].status).toBe(AgentStatus.IDLE);
|
|
360
|
+
});
|
|
361
|
+
|
|
292
362
|
it('should use PID file for direct match and skip legacy matching for that process', async () => {
|
|
293
363
|
const startTime = new Date();
|
|
294
364
|
const processes: ProcessInfo[] = [
|
|
@@ -81,10 +81,17 @@ export class ClaudeCodeAdapter implements AgentAdapter {
|
|
|
81
81
|
return [];
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
// Step 1:
|
|
85
|
-
|
|
84
|
+
// Step 1: extract `--resume <id>` from command line — authoritative for
|
|
85
|
+
// resumed sessions where the JSONL predates the process and PID-file/
|
|
86
|
+
// birthtime heuristics can't match it.
|
|
87
|
+
const { direct: resumeDirect, fallback: noResume } = this.tryResumeMatching(processes);
|
|
86
88
|
|
|
87
|
-
// Step 2:
|
|
89
|
+
// Step 2: try authoritative PID-file matching for the rest
|
|
90
|
+
const { direct: pidDirect, fallback } = this.tryPidFileMatching(noResume);
|
|
91
|
+
|
|
92
|
+
const direct = [...resumeDirect, ...pidDirect];
|
|
93
|
+
|
|
94
|
+
// Step 3: run legacy CWD+birthtime matching only for processes without a PID file
|
|
88
95
|
const legacySessions = this.discoverSessions(fallback);
|
|
89
96
|
const legacyMatches =
|
|
90
97
|
fallback.length > 0 && legacySessions.length > 0
|
|
@@ -98,7 +105,7 @@ export class ClaudeCodeAdapter implements AgentAdapter {
|
|
|
98
105
|
|
|
99
106
|
const agents: AgentInfo[] = [];
|
|
100
107
|
|
|
101
|
-
// Build agents from direct (PID-file) matches
|
|
108
|
+
// Build agents from direct (resume + PID-file) matches
|
|
102
109
|
for (const { process: proc, sessionFile } of direct) {
|
|
103
110
|
const sessionData = this.parser.readSession(sessionFile.filePath, sessionFile.resolvedCwd);
|
|
104
111
|
if (sessionData) {
|
|
@@ -167,6 +174,55 @@ export class ClaudeCodeAdapter implements AgentAdapter {
|
|
|
167
174
|
return files;
|
|
168
175
|
}
|
|
169
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Match processes via `claude --resume <uuid>` in their command line.
|
|
179
|
+
* This works for resumed sessions, where the JSONL was created earlier
|
|
180
|
+
* (so its birthtime is far from the process startTime and the legacy
|
|
181
|
+
* matcher can't pair them) and the PID file may also be misaligned.
|
|
182
|
+
*/
|
|
183
|
+
private tryResumeMatching(processes: ProcessInfo[]): {
|
|
184
|
+
direct: DirectMatch[];
|
|
185
|
+
fallback: ProcessInfo[];
|
|
186
|
+
} {
|
|
187
|
+
const direct: DirectMatch[] = [];
|
|
188
|
+
const fallback: ProcessInfo[] = [];
|
|
189
|
+
|
|
190
|
+
for (const proc of processes) {
|
|
191
|
+
const sessionId = this.extractResumeSessionId(proc.command);
|
|
192
|
+
if (!sessionId || !proc.cwd) {
|
|
193
|
+
fallback.push(proc);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const projectDir = this.getProjectDir(proc.cwd);
|
|
198
|
+
const jsonlPath = path.join(projectDir, `${sessionId}.jsonl`);
|
|
199
|
+
|
|
200
|
+
const stat = safeStat(jsonlPath);
|
|
201
|
+
if (!stat) {
|
|
202
|
+
fallback.push(proc);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
direct.push({
|
|
207
|
+
process: proc,
|
|
208
|
+
sessionFile: {
|
|
209
|
+
sessionId,
|
|
210
|
+
filePath: jsonlPath,
|
|
211
|
+
projectDir,
|
|
212
|
+
birthtimeMs: stat.birthtimeMs,
|
|
213
|
+
resolvedCwd: proc.cwd,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { direct, fallback };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private extractResumeSessionId(command: string): string | null {
|
|
222
|
+
const match = command.match(/--resume\s+([0-9a-f-]{36})/i);
|
|
223
|
+
return match?.[1] ?? null;
|
|
224
|
+
}
|
|
225
|
+
|
|
170
226
|
/**
|
|
171
227
|
* Attempt to match each process to its session via ~/.claude/sessions/<pid>.json.
|
|
172
228
|
*
|