@ai-devkit/agent-manager 0.25.0 → 0.26.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 +14 -0
- package/dist/__tests__/print/ClaudeCliProbe.test.js +53 -0
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -0
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +69 -0
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +108 -0
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -0
- package/dist/__tests__/print/ClaudePrintRunner.test.js +187 -0
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -0
- package/dist/__tests__/print/PrintAgent.test.js +17 -0
- package/dist/__tests__/print/PrintAgent.test.js.map +1 -0
- package/dist/__tests__/print/PrintAgentStore.test.js +307 -0
- package/dist/__tests__/print/PrintAgentStore.test.js.map +1 -0
- package/dist/__tests__/terminal/TmuxManager.test.js +9 -0
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/print/ClaudeCliProbe.d.ts +20 -0
- package/dist/print/ClaudeCliProbe.d.ts.map +1 -0
- package/dist/print/ClaudeCliProbe.js +57 -0
- package/dist/print/ClaudeCliProbe.js.map +1 -0
- package/dist/print/ClaudePrintAgentService.d.ts +44 -0
- package/dist/print/ClaudePrintAgentService.d.ts.map +1 -0
- package/dist/print/ClaudePrintAgentService.js +66 -0
- package/dist/print/ClaudePrintAgentService.js.map +1 -0
- package/dist/print/ClaudePrintRunner.d.ts +32 -0
- package/dist/print/ClaudePrintRunner.d.ts.map +1 -0
- package/dist/print/ClaudePrintRunner.js +128 -0
- package/dist/print/ClaudePrintRunner.js.map +1 -0
- package/dist/print/PrintAgent.d.ts +57 -0
- package/dist/print/PrintAgent.d.ts.map +1 -0
- package/dist/print/PrintAgent.js +42 -0
- package/dist/print/PrintAgent.js.map +1 -0
- package/dist/print/PrintAgentStore.d.ts +69 -0
- package/dist/print/PrintAgentStore.d.ts.map +1 -0
- package/dist/print/PrintAgentStore.js +484 -0
- package/dist/print/PrintAgentStore.js.map +1 -0
- package/dist/terminal/TmuxManager.d.ts +2 -2
- package/dist/terminal/TmuxManager.d.ts.map +1 -1
- package/dist/terminal/TmuxManager.js +5 -7
- package/dist/terminal/TmuxManager.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/fixtures/fake-claude.cjs +24 -0
- package/src/__tests__/print/ClaudeCliProbe.test.ts +32 -0
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +56 -0
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +46 -0
- package/src/__tests__/print/ClaudePrintRunner.test.ts +105 -0
- package/src/__tests__/print/PrintAgent.test.ts +21 -0
- package/src/__tests__/print/PrintAgentStore.test.ts +192 -0
- package/src/__tests__/terminal/TmuxManager.test.ts +10 -0
- package/src/index.ts +39 -0
- package/src/print/ClaudeCliProbe.ts +58 -0
- package/src/print/ClaudePrintAgentService.ts +94 -0
- package/src/print/ClaudePrintRunner.ts +139 -0
- package/src/print/PrintAgent.ts +86 -0
- package/src/print/PrintAgentStore.ts +503 -0
- package/src/terminal/TmuxManager.ts +5 -7
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
const tempDirs = [];
|
|
6
|
+
afterEach(()=>{
|
|
7
|
+
for (const dir of tempDirs.splice(0))fs.rmSync(dir, {
|
|
8
|
+
recursive: true,
|
|
9
|
+
force: true
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
async function loadStore() {
|
|
13
|
+
const api = await import('../../index.js');
|
|
14
|
+
expect(api).toHaveProperty('PrintAgentStore');
|
|
15
|
+
return api.PrintAgentStore;
|
|
16
|
+
}
|
|
17
|
+
function fixture() {
|
|
18
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'print-agent-store-'));
|
|
19
|
+
tempDirs.push(root);
|
|
20
|
+
const cwd = path.join(root, 'project');
|
|
21
|
+
fs.mkdirSync(cwd);
|
|
22
|
+
return {
|
|
23
|
+
root,
|
|
24
|
+
cwd,
|
|
25
|
+
filePath: path.join(root, 'state', 'print-agents.json')
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
describe('PrintAgentStore create/list/resolve', ()=>{
|
|
29
|
+
it('creates distinct durable identities with a canonical cwd and lists them', async ()=>{
|
|
30
|
+
const PrintAgentStore = await loadStore();
|
|
31
|
+
const { cwd, filePath } = fixture();
|
|
32
|
+
const store = new PrintAgentStore({
|
|
33
|
+
filePath,
|
|
34
|
+
now: ()=>new Date('2026-08-07T09:00:00Z')
|
|
35
|
+
});
|
|
36
|
+
const agent = await store.create({
|
|
37
|
+
name: 'reviewer',
|
|
38
|
+
cwd
|
|
39
|
+
});
|
|
40
|
+
expect(agent).toMatchObject({
|
|
41
|
+
name: 'reviewer',
|
|
42
|
+
provider: 'claude',
|
|
43
|
+
mode: 'print',
|
|
44
|
+
cwd: fs.realpathSync(cwd),
|
|
45
|
+
state: 'ready',
|
|
46
|
+
sessionHealth: 'uninitialized',
|
|
47
|
+
activeRun: null
|
|
48
|
+
});
|
|
49
|
+
expect(agent.id).toMatch(/^[0-9a-f-]{36}$/);
|
|
50
|
+
expect(agent.providerSessionId).toMatch(/^[0-9a-f-]{36}$/);
|
|
51
|
+
expect(agent.id).not.toBe(agent.providerSessionId);
|
|
52
|
+
expect(await store.list()).toEqual([
|
|
53
|
+
agent
|
|
54
|
+
]);
|
|
55
|
+
expect(fs.statSync(filePath).mode & 0o777).toBe(0o600);
|
|
56
|
+
});
|
|
57
|
+
it('resolves exact ids and names and rejects duplicate names', async ()=>{
|
|
58
|
+
const PrintAgentStore = await loadStore();
|
|
59
|
+
const { cwd, filePath } = fixture();
|
|
60
|
+
const store = new PrintAgentStore({
|
|
61
|
+
filePath
|
|
62
|
+
});
|
|
63
|
+
const agent = await store.create({
|
|
64
|
+
name: 'Reviewer',
|
|
65
|
+
cwd
|
|
66
|
+
});
|
|
67
|
+
expect(await store.resolve(agent.id)).toMatchObject({
|
|
68
|
+
id: agent.id
|
|
69
|
+
});
|
|
70
|
+
expect(await store.resolve('reviewer')).toMatchObject({
|
|
71
|
+
id: agent.id
|
|
72
|
+
});
|
|
73
|
+
expect(await store.resolve('view')).toBeNull();
|
|
74
|
+
await expect(store.create({
|
|
75
|
+
name: 'reviewer',
|
|
76
|
+
cwd
|
|
77
|
+
})).rejects.toMatchObject({
|
|
78
|
+
code: 'PRINT_AGENT_NAME_CONFLICT'
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
it('rejects missing cwd, malformed storage, and symlinked store targets', async ()=>{
|
|
82
|
+
const PrintAgentStore = await loadStore();
|
|
83
|
+
const { root, cwd, filePath } = fixture();
|
|
84
|
+
const store = new PrintAgentStore({
|
|
85
|
+
filePath
|
|
86
|
+
});
|
|
87
|
+
await expect(store.create({
|
|
88
|
+
name: 'missing',
|
|
89
|
+
cwd: path.join(root, 'missing')
|
|
90
|
+
})).rejects.toMatchObject({
|
|
91
|
+
code: 'PRINT_AGENT_STORE'
|
|
92
|
+
});
|
|
93
|
+
fs.mkdirSync(path.dirname(filePath), {
|
|
94
|
+
recursive: true
|
|
95
|
+
});
|
|
96
|
+
fs.writeFileSync(filePath, '{bad json', {
|
|
97
|
+
mode: 0o600
|
|
98
|
+
});
|
|
99
|
+
await expect(store.list()).rejects.toMatchObject({
|
|
100
|
+
code: 'PRINT_AGENT_STORE'
|
|
101
|
+
});
|
|
102
|
+
fs.rmSync(filePath);
|
|
103
|
+
const target = path.join(root, 'target.json');
|
|
104
|
+
fs.writeFileSync(target, JSON.stringify({
|
|
105
|
+
version: 1,
|
|
106
|
+
agents: []
|
|
107
|
+
}));
|
|
108
|
+
fs.symlinkSync(target, filePath);
|
|
109
|
+
await expect(store.create({
|
|
110
|
+
name: 'unsafe',
|
|
111
|
+
cwd
|
|
112
|
+
})).rejects.toMatchObject({
|
|
113
|
+
code: 'PRINT_AGENT_STORE'
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
it('recovers an abandoned old mutation lock after a crash', async ()=>{
|
|
117
|
+
const PrintAgentStore = await loadStore();
|
|
118
|
+
const { cwd, filePath } = fixture();
|
|
119
|
+
fs.mkdirSync(path.dirname(filePath), {
|
|
120
|
+
recursive: true
|
|
121
|
+
});
|
|
122
|
+
const lockPath = `${filePath}.lock`;
|
|
123
|
+
fs.mkdirSync(lockPath);
|
|
124
|
+
const old = new Date(Date.now() - 60_000);
|
|
125
|
+
fs.utimesSync(lockPath, old, old);
|
|
126
|
+
const store = new PrintAgentStore({
|
|
127
|
+
filePath,
|
|
128
|
+
mutationLockStaleMs: 10
|
|
129
|
+
});
|
|
130
|
+
await expect(store.create({
|
|
131
|
+
name: 'recovered',
|
|
132
|
+
cwd
|
|
133
|
+
})).resolves.toMatchObject({
|
|
134
|
+
name: 'recovered'
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('PrintAgentStore run ownership', ()=>{
|
|
139
|
+
it('fails fast when another exact owner is live and completes only for its token', async ()=>{
|
|
140
|
+
const PrintAgentStore = await loadStore();
|
|
141
|
+
const { cwd, filePath } = fixture();
|
|
142
|
+
const live = new Map([
|
|
143
|
+
[
|
|
144
|
+
process.pid,
|
|
145
|
+
'owner-start'
|
|
146
|
+
]
|
|
147
|
+
]);
|
|
148
|
+
const processInspector = {
|
|
149
|
+
getIdentity: (pid)=>{
|
|
150
|
+
const startedAt = live.get(pid);
|
|
151
|
+
return startedAt ? {
|
|
152
|
+
pid,
|
|
153
|
+
startedAt
|
|
154
|
+
} : null;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const store = new PrintAgentStore({
|
|
158
|
+
filePath,
|
|
159
|
+
processInspector
|
|
160
|
+
});
|
|
161
|
+
const agent = await store.create({
|
|
162
|
+
name: 'runner',
|
|
163
|
+
cwd
|
|
164
|
+
});
|
|
165
|
+
const acquired = await store.acquireRun(agent.id);
|
|
166
|
+
await expect(store.acquireRun(agent.id)).rejects.toMatchObject({
|
|
167
|
+
code: 'PRINT_AGENT_BUSY'
|
|
168
|
+
});
|
|
169
|
+
await expect(store.completeRun(agent.id, 'wrong-token', {
|
|
170
|
+
status: 'succeeded',
|
|
171
|
+
exitCode: 0,
|
|
172
|
+
summary: 'done',
|
|
173
|
+
sessionHealth: 'healthy'
|
|
174
|
+
})).rejects.toMatchObject({
|
|
175
|
+
code: 'PRINT_AGENT_STORE'
|
|
176
|
+
});
|
|
177
|
+
const completed = await store.completeRun(agent.id, acquired.token, {
|
|
178
|
+
status: 'succeeded',
|
|
179
|
+
exitCode: 0,
|
|
180
|
+
summary: 'done',
|
|
181
|
+
sessionHealth: 'healthy'
|
|
182
|
+
});
|
|
183
|
+
expect(completed).toMatchObject({
|
|
184
|
+
state: 'ready',
|
|
185
|
+
sessionHealth: 'healthy',
|
|
186
|
+
activeRun: null
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
it('retains busy for a live provider then recovers a dead run without signaling it', async ()=>{
|
|
190
|
+
const PrintAgentStore = await loadStore();
|
|
191
|
+
const { cwd, filePath } = fixture();
|
|
192
|
+
const live = new Map([
|
|
193
|
+
[
|
|
194
|
+
process.pid,
|
|
195
|
+
'owner-start'
|
|
196
|
+
],
|
|
197
|
+
[
|
|
198
|
+
4242,
|
|
199
|
+
'provider-start'
|
|
200
|
+
]
|
|
201
|
+
]);
|
|
202
|
+
const processInspector = {
|
|
203
|
+
getIdentity: (pid)=>{
|
|
204
|
+
const startedAt = live.get(pid);
|
|
205
|
+
return startedAt ? {
|
|
206
|
+
pid,
|
|
207
|
+
startedAt
|
|
208
|
+
} : null;
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const first = new PrintAgentStore({
|
|
212
|
+
filePath,
|
|
213
|
+
processInspector
|
|
214
|
+
});
|
|
215
|
+
const agent = await first.create({
|
|
216
|
+
name: 'recoverable',
|
|
217
|
+
cwd
|
|
218
|
+
});
|
|
219
|
+
const run = await first.acquireRun(agent.id);
|
|
220
|
+
await first.recordProviderProcess(agent.id, run.token, {
|
|
221
|
+
pid: 4242,
|
|
222
|
+
startedAt: 'provider-start'
|
|
223
|
+
});
|
|
224
|
+
live.delete(process.pid);
|
|
225
|
+
await expect(first.acquireRun(agent.id)).rejects.toMatchObject({
|
|
226
|
+
code: 'PRINT_AGENT_BUSY'
|
|
227
|
+
});
|
|
228
|
+
live.delete(4242);
|
|
229
|
+
live.set(process.pid, 'replacement-owner-start');
|
|
230
|
+
const recovered = await first.acquireRun(agent.id);
|
|
231
|
+
expect(recovered.agent).toMatchObject({
|
|
232
|
+
state: 'running',
|
|
233
|
+
lastResult: {
|
|
234
|
+
status: 'interrupted'
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
await first.completeRun(agent.id, recovered.token, {
|
|
238
|
+
status: 'failed',
|
|
239
|
+
exitCode: 1,
|
|
240
|
+
summary: 'failed',
|
|
241
|
+
sessionHealth: 'unknown'
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
it('reconciles an old incomplete lock to degraded during list', async ()=>{
|
|
245
|
+
const PrintAgentStore = await loadStore();
|
|
246
|
+
const { root, cwd, filePath } = fixture();
|
|
247
|
+
const live = new Map([
|
|
248
|
+
[
|
|
249
|
+
process.pid,
|
|
250
|
+
'owner-start'
|
|
251
|
+
]
|
|
252
|
+
]);
|
|
253
|
+
const store = new PrintAgentStore({
|
|
254
|
+
filePath,
|
|
255
|
+
incompleteLockGraceMs: 10,
|
|
256
|
+
processInspector: {
|
|
257
|
+
getIdentity: (pid)=>{
|
|
258
|
+
const startedAt = live.get(pid);
|
|
259
|
+
return startedAt ? {
|
|
260
|
+
pid,
|
|
261
|
+
startedAt
|
|
262
|
+
} : null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
const agent = await store.create({
|
|
267
|
+
name: 'crashed',
|
|
268
|
+
cwd
|
|
269
|
+
});
|
|
270
|
+
await store.acquireRun(agent.id);
|
|
271
|
+
const lockPath = path.join(root, 'state', 'print-agent-locks', `${agent.id}.lock`);
|
|
272
|
+
fs.unlinkSync(path.join(lockPath, 'owner.json'));
|
|
273
|
+
const old = new Date(Date.now() - 1000);
|
|
274
|
+
fs.utimesSync(lockPath, old, old);
|
|
275
|
+
live.clear();
|
|
276
|
+
const listed = await store.list();
|
|
277
|
+
expect(listed[0]).toMatchObject({
|
|
278
|
+
state: 'degraded',
|
|
279
|
+
sessionHealth: 'unknown',
|
|
280
|
+
activeRun: null,
|
|
281
|
+
lastResult: {
|
|
282
|
+
status: 'interrupted'
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
it('rejects send acquisition when the bound cwd is replaced by a symlink', async ()=>{
|
|
287
|
+
const PrintAgentStore = await loadStore();
|
|
288
|
+
const { root, cwd, filePath } = fixture();
|
|
289
|
+
const store = new PrintAgentStore({
|
|
290
|
+
filePath
|
|
291
|
+
});
|
|
292
|
+
const agent = await store.create({
|
|
293
|
+
name: 'bound',
|
|
294
|
+
cwd
|
|
295
|
+
});
|
|
296
|
+
const moved = path.join(root, 'moved-project');
|
|
297
|
+
const other = path.join(root, 'other-project');
|
|
298
|
+
fs.renameSync(cwd, moved);
|
|
299
|
+
fs.mkdirSync(other);
|
|
300
|
+
fs.symlinkSync(other, cwd);
|
|
301
|
+
await expect(store.acquireRun(agent.id)).rejects.toMatchObject({
|
|
302
|
+
code: 'PRINT_AGENT_STORE'
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
//# sourceMappingURL=PrintAgentStore.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/print/PrintAgentStore.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { afterEach, describe, expect, it } from 'vitest';\n\nconst tempDirs: string[] = [];\n\nafterEach(() => {\n for (const dir of tempDirs.splice(0)) fs.rmSync(dir, { recursive: true, force: true });\n});\n\nasync function loadStore(): Promise<any> {\n const api = await import('../../index.js') as Record<string, unknown>;\n expect(api).toHaveProperty('PrintAgentStore');\n return api.PrintAgentStore;\n}\n\nfunction fixture(): { root: string; cwd: string; filePath: string } {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), 'print-agent-store-'));\n tempDirs.push(root);\n const cwd = path.join(root, 'project');\n fs.mkdirSync(cwd);\n return { root, cwd, filePath: path.join(root, 'state', 'print-agents.json') };\n}\n\ndescribe('PrintAgentStore create/list/resolve', () => {\n it('creates distinct durable identities with a canonical cwd and lists them', async () => {\n const PrintAgentStore = await loadStore();\n const { cwd, filePath } = fixture();\n const store = new PrintAgentStore({ filePath, now: () => new Date('2026-08-07T09:00:00Z') });\n\n const agent = await store.create({ name: 'reviewer', cwd });\n\n expect(agent).toMatchObject({\n name: 'reviewer',\n provider: 'claude',\n mode: 'print',\n cwd: fs.realpathSync(cwd),\n state: 'ready',\n sessionHealth: 'uninitialized',\n activeRun: null,\n });\n expect(agent.id).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.providerSessionId).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.id).not.toBe(agent.providerSessionId);\n expect(await store.list()).toEqual([agent]);\n expect(fs.statSync(filePath).mode & 0o777).toBe(0o600);\n });\n\n it('resolves exact ids and names and rejects duplicate names', async () => {\n const PrintAgentStore = await loadStore();\n const { cwd, filePath } = fixture();\n const store = new PrintAgentStore({ filePath });\n const agent = await store.create({ name: 'Reviewer', cwd });\n\n expect(await store.resolve(agent.id)).toMatchObject({ id: agent.id });\n expect(await store.resolve('reviewer')).toMatchObject({ id: agent.id });\n expect(await store.resolve('view')).toBeNull();\n await expect(store.create({ name: 'reviewer', cwd })).rejects.toMatchObject({\n code: 'PRINT_AGENT_NAME_CONFLICT',\n });\n });\n\n it('rejects missing cwd, malformed storage, and symlinked store targets', async () => {\n const PrintAgentStore = await loadStore();\n const { root, cwd, filePath } = fixture();\n const store = new PrintAgentStore({ filePath });\n\n await expect(store.create({ name: 'missing', cwd: path.join(root, 'missing') }))\n .rejects.toMatchObject({ code: 'PRINT_AGENT_STORE' });\n\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n fs.writeFileSync(filePath, '{bad json', { mode: 0o600 });\n await expect(store.list()).rejects.toMatchObject({ code: 'PRINT_AGENT_STORE' });\n\n fs.rmSync(filePath);\n const target = path.join(root, 'target.json');\n fs.writeFileSync(target, JSON.stringify({ version: 1, agents: [] }));\n fs.symlinkSync(target, filePath);\n await expect(store.create({ name: 'unsafe', cwd })).rejects.toMatchObject({\n code: 'PRINT_AGENT_STORE',\n });\n });\n\n it('recovers an abandoned old mutation lock after a crash', async () => {\n const PrintAgentStore = await loadStore();\n const { cwd, filePath } = fixture();\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n const lockPath = `${filePath}.lock`;\n fs.mkdirSync(lockPath);\n const old = new Date(Date.now() - 60_000);\n fs.utimesSync(lockPath, old, old);\n const store = new PrintAgentStore({ filePath, mutationLockStaleMs: 10 });\n\n await expect(store.create({ name: 'recovered', cwd })).resolves.toMatchObject({ name: 'recovered' });\n });\n});\n\ndescribe('PrintAgentStore run ownership', () => {\n it('fails fast when another exact owner is live and completes only for its token', async () => {\n const PrintAgentStore = await loadStore();\n const { cwd, filePath } = fixture();\n const live = new Map<number, string>([[process.pid, 'owner-start']]);\n const processInspector = { getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n } };\n const store = new PrintAgentStore({ filePath, processInspector });\n const agent = await store.create({ name: 'runner', cwd });\n\n const acquired = await store.acquireRun(agent.id);\n await expect(store.acquireRun(agent.id)).rejects.toMatchObject({ code: 'PRINT_AGENT_BUSY' });\n await expect(store.completeRun(agent.id, 'wrong-token', {\n status: 'succeeded', exitCode: 0, summary: 'done', sessionHealth: 'healthy',\n })).rejects.toMatchObject({ code: 'PRINT_AGENT_STORE' });\n\n const completed = await store.completeRun(agent.id, acquired.token, {\n status: 'succeeded', exitCode: 0, summary: 'done', sessionHealth: 'healthy',\n });\n expect(completed).toMatchObject({ state: 'ready', sessionHealth: 'healthy', activeRun: null });\n });\n\n it('retains busy for a live provider then recovers a dead run without signaling it', async () => {\n const PrintAgentStore = await loadStore();\n const { cwd, filePath } = fixture();\n const live = new Map<number, string>([[process.pid, 'owner-start'], [4242, 'provider-start']]);\n const processInspector = { getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n } };\n const first = new PrintAgentStore({ filePath, processInspector });\n const agent = await first.create({ name: 'recoverable', cwd });\n const run = await first.acquireRun(agent.id);\n await first.recordProviderProcess(agent.id, run.token, { pid: 4242, startedAt: 'provider-start' });\n\n live.delete(process.pid);\n await expect(first.acquireRun(agent.id)).rejects.toMatchObject({ code: 'PRINT_AGENT_BUSY' });\n\n live.delete(4242);\n live.set(process.pid, 'replacement-owner-start');\n const recovered = await first.acquireRun(agent.id);\n expect(recovered.agent).toMatchObject({\n state: 'running',\n lastResult: { status: 'interrupted' },\n });\n await first.completeRun(agent.id, recovered.token, {\n status: 'failed', exitCode: 1, summary: 'failed', sessionHealth: 'unknown',\n });\n });\n\n it('reconciles an old incomplete lock to degraded during list', async () => {\n const PrintAgentStore = await loadStore();\n const { root, cwd, filePath } = fixture();\n const live = new Map<number, string>([[process.pid, 'owner-start']]);\n const store = new PrintAgentStore({ filePath, incompleteLockGraceMs: 10, processInspector: {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n } });\n const agent = await store.create({ name: 'crashed', cwd });\n await store.acquireRun(agent.id);\n const lockPath = path.join(root, 'state', 'print-agent-locks', `${agent.id}.lock`);\n fs.unlinkSync(path.join(lockPath, 'owner.json'));\n const old = new Date(Date.now() - 1000);\n fs.utimesSync(lockPath, old, old);\n live.clear();\n\n const listed = await store.list();\n\n expect(listed[0]).toMatchObject({\n state: 'degraded',\n sessionHealth: 'unknown',\n activeRun: null,\n lastResult: { status: 'interrupted' },\n });\n });\n\n it('rejects send acquisition when the bound cwd is replaced by a symlink', async () => {\n const PrintAgentStore = await loadStore();\n const { root, cwd, filePath } = fixture();\n const store = new PrintAgentStore({ filePath });\n const agent = await store.create({ name: 'bound', cwd });\n const moved = path.join(root, 'moved-project');\n const other = path.join(root, 'other-project');\n fs.renameSync(cwd, moved);\n fs.mkdirSync(other);\n fs.symlinkSync(other, cwd);\n\n await expect(store.acquireRun(agent.id)).rejects.toMatchObject({ code: 'PRINT_AGENT_STORE' });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","tempDirs","dir","splice","rmSync","recursive","force","loadStore","api","toHaveProperty","PrintAgentStore","fixture","root","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","filePath","store","now","Date","agent","create","name","toMatchObject","provider","mode","realpathSync","state","sessionHealth","activeRun","id","toMatch","providerSessionId","not","toBe","list","toEqual","statSync","resolve","toBeNull","rejects","code","dirname","writeFileSync","target","JSON","stringify","version","agents","symlinkSync","lockPath","old","utimesSync","mutationLockStaleMs","resolves","live","Map","process","pid","processInspector","getIdentity","startedAt","get","acquired","acquireRun","completeRun","status","exitCode","summary","completed","token","first","run","recordProviderProcess","delete","set","recovered","lastResult","incompleteLockGraceMs","unlinkSync","clear","listed","moved","other","renameSync"],"mappings":"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"}
|
|
@@ -93,6 +93,15 @@ describe('TmuxManager', ()=>{
|
|
|
93
93
|
});
|
|
94
94
|
expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();
|
|
95
95
|
});
|
|
96
|
+
it('returns the matching pane PID when the agent replaces the shell', async ()=>{
|
|
97
|
+
setExecFileHandler((cmd, args)=>{
|
|
98
|
+
if (cmd === 'tmux' && args[0] === 'list-panes') return '100\n';
|
|
99
|
+
if (cmd === 'pgrep') return new Error('no children');
|
|
100
|
+
if (cmd === 'ps' && args[1] === '100') return '/usr/local/bin/claude';
|
|
101
|
+
return '';
|
|
102
|
+
});
|
|
103
|
+
expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(100);
|
|
104
|
+
});
|
|
96
105
|
it('returns the matching descendant when found', async ()=>{
|
|
97
106
|
// pane 100 → child 200 (claude) — no grandchildren
|
|
98
107
|
setExecFileHandler((cmd, args)=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/terminal/TmuxManager.test.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport type { MockedFunction } from 'vitest';\nimport { TmuxManager } from '../../terminal/TmuxManager.js';\n\nvi.mock('child_process', () => ({\n execFile: vi.fn(),\n}));\n\ntype ExecFileCb = (err: Error | null, result?: { stdout: string; stderr: string }) => void;\nconst mockedExecFile = execFile as unknown as MockedFunction<\n (cmd: string, args: string[], cb: ExecFileCb) => void\n>;\n\n/** Drive the promisified execFile mock with a per-call handler. */\nfunction setExecFileHandler(handler: (cmd: string, args: string[]) => string | Error) {\n mockedExecFile.mockImplementation((_cmd, _args, cb) => {\n const result = handler(_cmd, _args);\n if (result instanceof Error) cb(result);\n else cb(null, { stdout: result, stderr: '' });\n });\n}\n\ndescribe('TmuxManager', () => {\n let tmux: TmuxManager;\n\n beforeEach(() => {\n tmux = new TmuxManager();\n mockedExecFile.mockReset();\n });\n\n describe('isAvailable', () => {\n it('returns true when `tmux -V` succeeds', async () => {\n setExecFileHandler(() => 'tmux 3.4');\n expect(await tmux.isAvailable()).toBe(true);\n });\n\n it('returns false when tmux is missing', async () => {\n setExecFileHandler(() => new Error('ENOENT'));\n expect(await tmux.isAvailable()).toBe(false);\n });\n });\n\n describe('sessionExists', () => {\n it('returns true when has-session succeeds', async () => {\n setExecFileHandler(() => '');\n expect(await tmux.sessionExists('foo')).toBe(true);\n });\n\n it('returns false when has-session fails', async () => {\n setExecFileHandler(() => new Error('no session'));\n expect(await tmux.sessionExists('foo')).toBe(false);\n });\n });\n\n describe('createSession', () => {\n it('issues `tmux new-session -d -s <name> -c <cwd>`', async () => {\n setExecFileHandler(() => '');\n await tmux.createSession('foo', '/work');\n expect(mockedExecFile).toHaveBeenCalledWith(\n 'tmux',\n ['new-session', '-d', '-s', 'foo', '-c', '/work'],\n expect.any(Function),\n );\n });\n });\n\n describe('sendKeys', () => {\n it('appends Enter so the command runs', async () => {\n setExecFileHandler(() => '');\n await tmux.sendKeys('foo', 'claude');\n expect(mockedExecFile).toHaveBeenCalledWith(\n 'tmux',\n ['send-keys', '-t', 'foo', 'claude', 'Enter'],\n expect.any(Function),\n );\n });\n });\n\n describe('killSession', () => {\n it('swallows errors when session is already gone', async () => {\n setExecFileHandler(() => new Error(\"can't find session\"));\n await expect(tmux.killSession('foo')).resolves.toBeUndefined();\n });\n });\n\n describe('findAgentPid', () => {\n const matchesClaude = (cmd: string) => cmd.split(/\\s+/)[0]?.endsWith('claude') ?? false;\n\n it('returns null when the session has no pane', async () => {\n setExecFileHandler((cmd, args) => {\n if (args[0] === 'list-panes') return new Error('no session');\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();\n });\n\n it('returns null when no descendant matches', async () => {\n // pane PID 100; child 200 is \"node /unrelated\" — no match\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux' && args[0] === 'list-panes') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'node /unrelated';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();\n });\n\n it('returns the matching descendant when found', async () => {\n // pane 100 → child 200 (claude) — no grandchildren\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(200);\n });\n\n it('prefers the deepest match (wrapper case)', async () => {\n // pane 100 → 200 (claude wrapper, matches) → 300 (claude, matches, deeper)\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep' && args[1] === '200') return '300\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return '/usr/local/bin/claude';\n if (cmd === 'ps' && args[1] === '300') return '/usr/local/lib/claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(300);\n });\n\n it('skips non-matching subprocesses (MCP child case)', async () => {\n // pane 100 → 200 (claude, matches) → 300 (mcp-server, no match)\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep' && args[1] === '200') return '300\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'claude';\n if (cmd === 'ps' && args[1] === '300') return 'node mcp-server.js';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(200);\n });\n\n it('handles the gemini Node-script shape via a token-scan matcher', async () => {\n const matchesGemini = (cmd: string) =>\n cmd.split(/\\s+/).some((t) => t.endsWith('/gemini') || t === 'gemini');\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'node /opt/homebrew/bin/gemini --foo';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesGemini)).toBe(200);\n });\n\n it('handles multiple children at the same level', async () => {\n // pane 100 → [200 (nope), 201 (claude)]\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n201\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'bash';\n if (cmd === 'ps' && args[1] === '201') return 'claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(201);\n });\n });\n});\n"],"names":["execFile","TmuxManager","vi","mock","fn","mockedExecFile","setExecFileHandler","handler","mockImplementation","_cmd","_args","cb","result","Error","stdout","stderr","describe","tmux","beforeEach","mockReset","it","expect","isAvailable","toBe","sessionExists","createSession","toHaveBeenCalledWith","any","Function","sendKeys","killSession","resolves","toBeUndefined","matchesClaude","cmd","split","endsWith","args","findAgentPid","toBeNull","matchesGemini","some","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/terminal/TmuxManager.test.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport type { MockedFunction } from 'vitest';\nimport { TmuxManager } from '../../terminal/TmuxManager.js';\n\nvi.mock('child_process', () => ({\n execFile: vi.fn(),\n}));\n\ntype ExecFileCb = (err: Error | null, result?: { stdout: string; stderr: string }) => void;\nconst mockedExecFile = execFile as unknown as MockedFunction<\n (cmd: string, args: string[], cb: ExecFileCb) => void\n>;\n\n/** Drive the promisified execFile mock with a per-call handler. */\nfunction setExecFileHandler(handler: (cmd: string, args: string[]) => string | Error) {\n mockedExecFile.mockImplementation((_cmd, _args, cb) => {\n const result = handler(_cmd, _args);\n if (result instanceof Error) cb(result);\n else cb(null, { stdout: result, stderr: '' });\n });\n}\n\ndescribe('TmuxManager', () => {\n let tmux: TmuxManager;\n\n beforeEach(() => {\n tmux = new TmuxManager();\n mockedExecFile.mockReset();\n });\n\n describe('isAvailable', () => {\n it('returns true when `tmux -V` succeeds', async () => {\n setExecFileHandler(() => 'tmux 3.4');\n expect(await tmux.isAvailable()).toBe(true);\n });\n\n it('returns false when tmux is missing', async () => {\n setExecFileHandler(() => new Error('ENOENT'));\n expect(await tmux.isAvailable()).toBe(false);\n });\n });\n\n describe('sessionExists', () => {\n it('returns true when has-session succeeds', async () => {\n setExecFileHandler(() => '');\n expect(await tmux.sessionExists('foo')).toBe(true);\n });\n\n it('returns false when has-session fails', async () => {\n setExecFileHandler(() => new Error('no session'));\n expect(await tmux.sessionExists('foo')).toBe(false);\n });\n });\n\n describe('createSession', () => {\n it('issues `tmux new-session -d -s <name> -c <cwd>`', async () => {\n setExecFileHandler(() => '');\n await tmux.createSession('foo', '/work');\n expect(mockedExecFile).toHaveBeenCalledWith(\n 'tmux',\n ['new-session', '-d', '-s', 'foo', '-c', '/work'],\n expect.any(Function),\n );\n });\n });\n\n describe('sendKeys', () => {\n it('appends Enter so the command runs', async () => {\n setExecFileHandler(() => '');\n await tmux.sendKeys('foo', 'claude');\n expect(mockedExecFile).toHaveBeenCalledWith(\n 'tmux',\n ['send-keys', '-t', 'foo', 'claude', 'Enter'],\n expect.any(Function),\n );\n });\n });\n\n describe('killSession', () => {\n it('swallows errors when session is already gone', async () => {\n setExecFileHandler(() => new Error(\"can't find session\"));\n await expect(tmux.killSession('foo')).resolves.toBeUndefined();\n });\n });\n\n describe('findAgentPid', () => {\n const matchesClaude = (cmd: string) => cmd.split(/\\s+/)[0]?.endsWith('claude') ?? false;\n\n it('returns null when the session has no pane', async () => {\n setExecFileHandler((cmd, args) => {\n if (args[0] === 'list-panes') return new Error('no session');\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();\n });\n\n it('returns null when no descendant matches', async () => {\n // pane PID 100; child 200 is \"node /unrelated\" — no match\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux' && args[0] === 'list-panes') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'node /unrelated';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBeNull();\n });\n\n it('returns the matching pane PID when the agent replaces the shell', async () => {\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux' && args[0] === 'list-panes') return '100\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '100') return '/usr/local/bin/claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(100);\n });\n\n it('returns the matching descendant when found', async () => {\n // pane 100 → child 200 (claude) — no grandchildren\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(200);\n });\n\n it('prefers the deepest match (wrapper case)', async () => {\n // pane 100 → 200 (claude wrapper, matches) → 300 (claude, matches, deeper)\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep' && args[1] === '200') return '300\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return '/usr/local/bin/claude';\n if (cmd === 'ps' && args[1] === '300') return '/usr/local/lib/claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(300);\n });\n\n it('skips non-matching subprocesses (MCP child case)', async () => {\n // pane 100 → 200 (claude, matches) → 300 (mcp-server, no match)\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep' && args[1] === '200') return '300\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'claude';\n if (cmd === 'ps' && args[1] === '300') return 'node mcp-server.js';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(200);\n });\n\n it('handles the gemini Node-script shape via a token-scan matcher', async () => {\n const matchesGemini = (cmd: string) =>\n cmd.split(/\\s+/).some((t) => t.endsWith('/gemini') || t === 'gemini');\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'node /opt/homebrew/bin/gemini --foo';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesGemini)).toBe(200);\n });\n\n it('handles multiple children at the same level', async () => {\n // pane 100 → [200 (nope), 201 (claude)]\n setExecFileHandler((cmd, args) => {\n if (cmd === 'tmux') return '100\\n';\n if (cmd === 'pgrep' && args[1] === '100') return '200\\n201\\n';\n if (cmd === 'pgrep') return new Error('no children');\n if (cmd === 'ps' && args[1] === '200') return 'bash';\n if (cmd === 'ps' && args[1] === '201') return 'claude';\n return '';\n });\n expect(await tmux.findAgentPid('foo', matchesClaude)).toBe(201);\n });\n });\n});\n"],"names":["execFile","TmuxManager","vi","mock","fn","mockedExecFile","setExecFileHandler","handler","mockImplementation","_cmd","_args","cb","result","Error","stdout","stderr","describe","tmux","beforeEach","mockReset","it","expect","isAvailable","toBe","sessionExists","createSession","toHaveBeenCalledWith","any","Function","sendKeys","killSession","resolves","toBeUndefined","matchesClaude","cmd","split","endsWith","args","findAgentPid","toBeNull","matchesGemini","some","t"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -21,4 +21,15 @@ export { AGENTS } from './utils/agents.js';
|
|
|
21
21
|
export type { AgentConfig, StartableAgentType } from './utils/agents.js';
|
|
22
22
|
export type { AgentRequest } from './utils/agent-requests.js';
|
|
23
23
|
export { getAgentRequestPath, readLatestAgentRequest, writeAgentRequest } from './utils/agent-requests.js';
|
|
24
|
+
export { PrintAgentError, PrintAgentBusyError, PrintAgentNotFoundError, PrintAgentStoreError, PrintAgentNameConflictError, ClaudePrintError, } from './print/PrintAgent.js';
|
|
25
|
+
export type { PrintAgent, PrintAgentState, PrintSessionHealth, PrintRunStatus, PrintActiveRun, PrintLastResult, ProcessIdentity, } from './print/PrintAgent.js';
|
|
26
|
+
export { PrintAgentStore } from './print/PrintAgentStore.js';
|
|
27
|
+
export { LocalProcessInspector } from './print/PrintAgentStore.js';
|
|
28
|
+
export type { CreatePrintAgentInput, PrintAgentStoreOptions, ProcessInspector, PrintRunCompletion, } from './print/PrintAgentStore.js';
|
|
29
|
+
export { ClaudeCliProbe } from './print/ClaudeCliProbe.js';
|
|
30
|
+
export type { ClaudeCliProbeOptions } from './print/ClaudeCliProbe.js';
|
|
31
|
+
export { ClaudePrintRunner } from './print/ClaudePrintRunner.js';
|
|
32
|
+
export type { ClaudePrintRunnerOptions, ClaudePrintRunRequest, ClaudePrintRunResult, } from './print/ClaudePrintRunner.js';
|
|
33
|
+
export { ClaudePrintAgentService } from './print/ClaudePrintAgentService.js';
|
|
34
|
+
export type { ClaudePrintAgentServiceOptions, ClaudePrintSendResult, } from './print/ClaudePrintAgentService.js';
|
|
24
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,YAAY,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACxF,YAAY,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACnG,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,YAAY,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,mBAAmB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACxF,YAAY,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACnG,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAE3G,OAAO,EACH,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACR,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EACR,qBAAqB,EACrB,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,GACrB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EACR,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,YAAY,EACR,8BAA8B,EAC9B,qBAAqB,GACxB,MAAM,oCAAoC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,5 +14,11 @@ export { AgentRegistry, RenameNotFoundError, RenameConflictError } from './utils
|
|
|
14
14
|
export { TmuxManager } from './terminal/TmuxManager.js';
|
|
15
15
|
export { AGENTS } from './utils/agents.js';
|
|
16
16
|
export { getAgentRequestPath, readLatestAgentRequest, writeAgentRequest } from './utils/agent-requests.js';
|
|
17
|
+
export { PrintAgentError, PrintAgentBusyError, PrintAgentNotFoundError, PrintAgentStoreError, PrintAgentNameConflictError, ClaudePrintError } from './print/PrintAgent.js';
|
|
18
|
+
export { PrintAgentStore } from './print/PrintAgentStore.js';
|
|
19
|
+
export { LocalProcessInspector } from './print/PrintAgentStore.js';
|
|
20
|
+
export { ClaudeCliProbe } from './print/ClaudeCliProbe.js';
|
|
21
|
+
export { ClaudePrintRunner } from './print/ClaudePrintRunner.js';
|
|
22
|
+
export { ClaudePrintAgentService } from './print/ClaudePrintAgentService.js';
|
|
17
23
|
|
|
18
24
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AgentManager } from './AgentManager.js';\n\nexport { ClaudeCodeAdapter } from './adapters/ClaudeCodeAdapter.js';\nexport { CodexAdapter } from './adapters/CodexAdapter.js';\nexport { CopilotAdapter } from './adapters/CopilotAdapter.js';\nexport { GeminiCliAdapter } from './adapters/GeminiCliAdapter.js';\nexport { GrokCliAdapter } from './adapters/GrokCliAdapter.js';\nexport { OpenCodeAdapter } from './adapters/OpenCodeAdapter.js';\nexport { PiAdapter } from './adapters/PiAdapter.js';\nexport { AgentStatus } from './adapters/AgentAdapter.js';\nexport type {\n AgentAdapter,\n AgentType,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n SessionSummary,\n ListSessionsOptions,\n} from './adapters/AgentAdapter.js';\n\nexport { TerminalFocusManager, TerminalType } from './terminal/TerminalFocusManager.js';\nexport type { TerminalLocation } from './terminal/TerminalFocusManager.js';\nexport { TtyWriter } from './terminal/TtyWriter.js';\n\nexport { getProcessTty } from './utils/process.js';\nexport type { AgentSortKey } from './utils/sortAgents.js';\nexport type { ListAgentsOptions } from './AgentManager.js';\n\nexport { AgentRegistry, RenameNotFoundError, RenameConflictError } from './utils/AgentRegistry.js';\nexport type { RegistryEntry } from './utils/AgentRegistry.js';\nexport { TmuxManager } from './terminal/TmuxManager.js';\nexport { AGENTS } from './utils/agents.js';\nexport type { AgentConfig, StartableAgentType } from './utils/agents.js';\n\nexport type { AgentRequest } from './utils/agent-requests.js';\nexport { getAgentRequestPath, readLatestAgentRequest, writeAgentRequest } from './utils/agent-requests.js';\n"],"names":["AgentManager","ClaudeCodeAdapter","CodexAdapter","CopilotAdapter","GeminiCliAdapter","GrokCliAdapter","OpenCodeAdapter","PiAdapter","AgentStatus","TerminalFocusManager","TerminalType","TtyWriter","getProcessTty","AgentRegistry","RenameNotFoundError","RenameConflictError","TmuxManager","AGENTS","getAgentRequestPath","readLatestAgentRequest","writeAgentRequest"],"mappings":"AAAA,SAASA,YAAY,QAAQ,oBAAoB;AAEjD,SAASC,iBAAiB,QAAQ,kCAAkC;AACpE,SAASC,YAAY,QAAQ,6BAA6B;AAC1D,SAASC,cAAc,QAAQ,+BAA+B;AAC9D,SAASC,gBAAgB,QAAQ,iCAAiC;AAClE,SAASC,cAAc,QAAQ,+BAA+B;AAC9D,SAASC,eAAe,QAAQ,gCAAgC;AAChE,SAASC,SAAS,QAAQ,0BAA0B;AACpD,SAASC,WAAW,QAAQ,6BAA6B;AAWzD,SAASC,oBAAoB,EAAEC,YAAY,QAAQ,qCAAqC;AAExF,SAASC,SAAS,QAAQ,0BAA0B;AAEpD,SAASC,aAAa,QAAQ,qBAAqB;AAInD,SAASC,aAAa,EAAEC,mBAAmB,EAAEC,mBAAmB,QAAQ,2BAA2B;AAEnG,SAASC,WAAW,QAAQ,4BAA4B;AACxD,SAASC,MAAM,QAAQ,oBAAoB;AAI3C,SAASC,mBAAmB,EAAEC,sBAAsB,EAAEC,iBAAiB,QAAQ,4BAA4B"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { AgentManager } from './AgentManager.js';\n\nexport { ClaudeCodeAdapter } from './adapters/ClaudeCodeAdapter.js';\nexport { CodexAdapter } from './adapters/CodexAdapter.js';\nexport { CopilotAdapter } from './adapters/CopilotAdapter.js';\nexport { GeminiCliAdapter } from './adapters/GeminiCliAdapter.js';\nexport { GrokCliAdapter } from './adapters/GrokCliAdapter.js';\nexport { OpenCodeAdapter } from './adapters/OpenCodeAdapter.js';\nexport { PiAdapter } from './adapters/PiAdapter.js';\nexport { AgentStatus } from './adapters/AgentAdapter.js';\nexport type {\n AgentAdapter,\n AgentType,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n SessionSummary,\n ListSessionsOptions,\n} from './adapters/AgentAdapter.js';\n\nexport { TerminalFocusManager, TerminalType } from './terminal/TerminalFocusManager.js';\nexport type { TerminalLocation } from './terminal/TerminalFocusManager.js';\nexport { TtyWriter } from './terminal/TtyWriter.js';\n\nexport { getProcessTty } from './utils/process.js';\nexport type { AgentSortKey } from './utils/sortAgents.js';\nexport type { ListAgentsOptions } from './AgentManager.js';\n\nexport { AgentRegistry, RenameNotFoundError, RenameConflictError } from './utils/AgentRegistry.js';\nexport type { RegistryEntry } from './utils/AgentRegistry.js';\nexport { TmuxManager } from './terminal/TmuxManager.js';\nexport { AGENTS } from './utils/agents.js';\nexport type { AgentConfig, StartableAgentType } from './utils/agents.js';\n\nexport type { AgentRequest } from './utils/agent-requests.js';\nexport { getAgentRequestPath, readLatestAgentRequest, writeAgentRequest } from './utils/agent-requests.js';\n\nexport {\n PrintAgentError,\n PrintAgentBusyError,\n PrintAgentNotFoundError,\n PrintAgentStoreError,\n PrintAgentNameConflictError,\n ClaudePrintError,\n} from './print/PrintAgent.js';\nexport type {\n PrintAgent,\n PrintAgentState,\n PrintSessionHealth,\n PrintRunStatus,\n PrintActiveRun,\n PrintLastResult,\n ProcessIdentity,\n} from './print/PrintAgent.js';\nexport { PrintAgentStore } from './print/PrintAgentStore.js';\nexport { LocalProcessInspector } from './print/PrintAgentStore.js';\nexport type {\n CreatePrintAgentInput,\n PrintAgentStoreOptions,\n ProcessInspector,\n PrintRunCompletion,\n} from './print/PrintAgentStore.js';\nexport { ClaudeCliProbe } from './print/ClaudeCliProbe.js';\nexport type { ClaudeCliProbeOptions } from './print/ClaudeCliProbe.js';\nexport { ClaudePrintRunner } from './print/ClaudePrintRunner.js';\nexport type {\n ClaudePrintRunnerOptions,\n ClaudePrintRunRequest,\n ClaudePrintRunResult,\n} from './print/ClaudePrintRunner.js';\nexport { ClaudePrintAgentService } from './print/ClaudePrintAgentService.js';\nexport type {\n ClaudePrintAgentServiceOptions,\n ClaudePrintSendResult,\n} from './print/ClaudePrintAgentService.js';\n"],"names":["AgentManager","ClaudeCodeAdapter","CodexAdapter","CopilotAdapter","GeminiCliAdapter","GrokCliAdapter","OpenCodeAdapter","PiAdapter","AgentStatus","TerminalFocusManager","TerminalType","TtyWriter","getProcessTty","AgentRegistry","RenameNotFoundError","RenameConflictError","TmuxManager","AGENTS","getAgentRequestPath","readLatestAgentRequest","writeAgentRequest","PrintAgentError","PrintAgentBusyError","PrintAgentNotFoundError","PrintAgentStoreError","PrintAgentNameConflictError","ClaudePrintError","PrintAgentStore","LocalProcessInspector","ClaudeCliProbe","ClaudePrintRunner","ClaudePrintAgentService"],"mappings":"AAAA,SAASA,YAAY,QAAQ,oBAAoB;AAEjD,SAASC,iBAAiB,QAAQ,kCAAkC;AACpE,SAASC,YAAY,QAAQ,6BAA6B;AAC1D,SAASC,cAAc,QAAQ,+BAA+B;AAC9D,SAASC,gBAAgB,QAAQ,iCAAiC;AAClE,SAASC,cAAc,QAAQ,+BAA+B;AAC9D,SAASC,eAAe,QAAQ,gCAAgC;AAChE,SAASC,SAAS,QAAQ,0BAA0B;AACpD,SAASC,WAAW,QAAQ,6BAA6B;AAWzD,SAASC,oBAAoB,EAAEC,YAAY,QAAQ,qCAAqC;AAExF,SAASC,SAAS,QAAQ,0BAA0B;AAEpD,SAASC,aAAa,QAAQ,qBAAqB;AAInD,SAASC,aAAa,EAAEC,mBAAmB,EAAEC,mBAAmB,QAAQ,2BAA2B;AAEnG,SAASC,WAAW,QAAQ,4BAA4B;AACxD,SAASC,MAAM,QAAQ,oBAAoB;AAI3C,SAASC,mBAAmB,EAAEC,sBAAsB,EAAEC,iBAAiB,QAAQ,4BAA4B;AAE3G,SACIC,eAAe,EACfC,mBAAmB,EACnBC,uBAAuB,EACvBC,oBAAoB,EACpBC,2BAA2B,EAC3BC,gBAAgB,QACb,wBAAwB;AAU/B,SAASC,eAAe,QAAQ,6BAA6B;AAC7D,SAASC,qBAAqB,QAAQ,6BAA6B;AAOnE,SAASC,cAAc,QAAQ,4BAA4B;AAE3D,SAASC,iBAAiB,QAAQ,+BAA+B;AAMjE,SAASC,uBAAuB,QAAQ,qCAAqC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type ExecResult = {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
};
|
|
5
|
+
type Exec = (file: string, args: string[]) => Promise<ExecResult>;
|
|
6
|
+
export interface ClaudeCliProbeOptions {
|
|
7
|
+
executable?: string;
|
|
8
|
+
exec?: Exec;
|
|
9
|
+
}
|
|
10
|
+
export declare class ClaudeCliProbe {
|
|
11
|
+
private readonly executable;
|
|
12
|
+
private readonly exec;
|
|
13
|
+
constructor(options?: ClaudeCliProbeOptions);
|
|
14
|
+
validate(): Promise<{
|
|
15
|
+
executable: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=ClaudeCliProbe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaudeCliProbe.d.ts","sourceRoot":"","sources":["../../src/print/ClaudeCliProbe.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrD,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAKlE,MAAM,WAAW,qBAAqB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;CACf;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;gBAEhB,OAAO,GAAE,qBAA0B;IAQzC,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAuBrE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { execFile } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { ClaudePrintError } from './PrintAgent.js';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
const REQUIRED = [
|
|
6
|
+
'--print',
|
|
7
|
+
'--session-id',
|
|
8
|
+
'--resume',
|
|
9
|
+
'--output-format',
|
|
10
|
+
'stream-json'
|
|
11
|
+
];
|
|
12
|
+
export class ClaudeCliProbe {
|
|
13
|
+
executable;
|
|
14
|
+
exec;
|
|
15
|
+
constructor(options = {}){
|
|
16
|
+
this.executable = options.executable ?? 'claude';
|
|
17
|
+
this.exec = options.exec ?? (async (file, args)=>{
|
|
18
|
+
const result = await execFileAsync(file, args, {
|
|
19
|
+
encoding: 'utf8',
|
|
20
|
+
maxBuffer: 1024 * 1024
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
stdout: result.stdout,
|
|
24
|
+
stderr: result.stderr
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
async validate() {
|
|
29
|
+
try {
|
|
30
|
+
const versionResult = await this.exec(this.executable, [
|
|
31
|
+
'--version'
|
|
32
|
+
]);
|
|
33
|
+
const helpResult = await this.exec(this.executable, [
|
|
34
|
+
'--help'
|
|
35
|
+
]);
|
|
36
|
+
const missing = REQUIRED.filter((capability)=>!helpResult.stdout.includes(capability));
|
|
37
|
+
if (missing.length > 0) {
|
|
38
|
+
throw new ClaudePrintError(`Claude CLI does not support required print-mode capabilities: ${missing.join(', ')}.`, 'CLAUDE_CLI_UNSUPPORTED');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
executable: this.executable,
|
|
42
|
+
version: sanitize(versionResult.stdout, 256) || 'unknown'
|
|
43
|
+
};
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof ClaudePrintError) throw error;
|
|
46
|
+
throw new ClaudePrintError(`Claude CLI validation failed: ${sanitize(error.message, 512)}`, 'CLAUDE_CLI_UNAVAILABLE');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function sanitize(value, max) {
|
|
51
|
+
return Array.from(value, (character)=>{
|
|
52
|
+
const code = character.charCodeAt(0);
|
|
53
|
+
return code <= 31 || code === 127 ? ' ' : character;
|
|
54
|
+
}).join('').trim().slice(0, max);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=ClaudeCliProbe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/print/ClaudeCliProbe.ts"],"sourcesContent":["import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { ClaudePrintError } from './PrintAgent.js';\n\ntype ExecResult = { stdout: string; stderr: string };\ntype Exec = (file: string, args: string[]) => Promise<ExecResult>;\n\nconst execFileAsync = promisify(execFile);\nconst REQUIRED = ['--print', '--session-id', '--resume', '--output-format', 'stream-json'];\n\nexport interface ClaudeCliProbeOptions {\n executable?: string;\n exec?: Exec;\n}\n\nexport class ClaudeCliProbe {\n private readonly executable: string;\n private readonly exec: Exec;\n\n constructor(options: ClaudeCliProbeOptions = {}) {\n this.executable = options.executable ?? 'claude';\n this.exec = options.exec ?? (async (file, args) => {\n const result = await execFileAsync(file, args, { encoding: 'utf8', maxBuffer: 1024 * 1024 });\n return { stdout: result.stdout, stderr: result.stderr };\n });\n }\n\n async validate(): Promise<{ executable: string; version: string }> {\n try {\n const versionResult = await this.exec(this.executable, ['--version']);\n const helpResult = await this.exec(this.executable, ['--help']);\n const missing = REQUIRED.filter((capability) => !helpResult.stdout.includes(capability));\n if (missing.length > 0) {\n throw new ClaudePrintError(\n `Claude CLI does not support required print-mode capabilities: ${missing.join(', ')}.`,\n 'CLAUDE_CLI_UNSUPPORTED',\n );\n }\n return {\n executable: this.executable,\n version: sanitize(versionResult.stdout, 256) || 'unknown',\n };\n } catch (error) {\n if (error instanceof ClaudePrintError) throw error;\n throw new ClaudePrintError(\n `Claude CLI validation failed: ${sanitize((error as Error).message, 512)}`,\n 'CLAUDE_CLI_UNAVAILABLE',\n );\n }\n }\n}\n\nfunction sanitize(value: string, max: number): string {\n return Array.from(value, (character) => {\n const code = character.charCodeAt(0);\n return code <= 31 || code === 127 ? ' ' : character;\n }).join('').trim().slice(0, max);\n}\n"],"names":["execFile","promisify","ClaudePrintError","execFileAsync","REQUIRED","ClaudeCliProbe","executable","exec","options","file","args","result","encoding","maxBuffer","stdout","stderr","validate","versionResult","helpResult","missing","filter","capability","includes","length","join","version","sanitize","error","message","value","max","Array","from","character","code","charCodeAt","trim","slice"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,gBAAgB;AACzC,SAASC,SAAS,QAAQ,OAAO;AACjC,SAASC,gBAAgB,QAAQ,kBAAkB;AAKnD,MAAMC,gBAAgBF,UAAUD;AAChC,MAAMI,WAAW;IAAC;IAAW;IAAgB;IAAY;IAAmB;CAAc;AAO1F,OAAO,MAAMC;IACQC,WAAmB;IACnBC,KAAW;IAE5B,YAAYC,UAAiC,CAAC,CAAC,CAAE;QAC7C,IAAI,CAACF,UAAU,GAAGE,QAAQF,UAAU,IAAI;QACxC,IAAI,CAACC,IAAI,GAAGC,QAAQD,IAAI,IAAK,CAAA,OAAOE,MAAMC;YACtC,MAAMC,SAAS,MAAMR,cAAcM,MAAMC,MAAM;gBAAEE,UAAU;gBAAQC,WAAW,OAAO;YAAK;YAC1F,OAAO;gBAAEC,QAAQH,OAAOG,MAAM;gBAAEC,QAAQJ,OAAOI,MAAM;YAAC;QAC1D,CAAA;IACJ;IAEA,MAAMC,WAA6D;QAC/D,IAAI;YACA,MAAMC,gBAAgB,MAAM,IAAI,CAACV,IAAI,CAAC,IAAI,CAACD,UAAU,EAAE;gBAAC;aAAY;YACpE,MAAMY,aAAa,MAAM,IAAI,CAACX,IAAI,CAAC,IAAI,CAACD,UAAU,EAAE;gBAAC;aAAS;YAC9D,MAAMa,UAAUf,SAASgB,MAAM,CAAC,CAACC,aAAe,CAACH,WAAWJ,MAAM,CAACQ,QAAQ,CAACD;YAC5E,IAAIF,QAAQI,MAAM,GAAG,GAAG;gBACpB,MAAM,IAAIrB,iBACN,CAAC,8DAA8D,EAAEiB,QAAQK,IAAI,CAAC,MAAM,CAAC,CAAC,EACtF;YAER;YACA,OAAO;gBACHlB,YAAY,IAAI,CAACA,UAAU;gBAC3BmB,SAASC,SAAST,cAAcH,MAAM,EAAE,QAAQ;YACpD;QACJ,EAAE,OAAOa,OAAO;YACZ,IAAIA,iBAAiBzB,kBAAkB,MAAMyB;YAC7C,MAAM,IAAIzB,iBACN,CAAC,8BAA8B,EAAEwB,SAAS,AAACC,MAAgBC,OAAO,EAAE,MAAM,EAC1E;QAER;IACJ;AACJ;AAEA,SAASF,SAASG,KAAa,EAAEC,GAAW;IACxC,OAAOC,MAAMC,IAAI,CAACH,OAAO,CAACI;QACtB,MAAMC,OAAOD,UAAUE,UAAU,CAAC;QAClC,OAAOD,QAAQ,MAAMA,SAAS,MAAM,MAAMD;IAC9C,GAAGT,IAAI,CAAC,IAAIY,IAAI,GAAGC,KAAK,CAAC,GAAGP;AAChC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { PrintAgent, ProcessIdentity } from './PrintAgent.js';
|
|
2
|
+
import { ClaudePrintRunner, type ClaudePrintRunResult } from './ClaudePrintRunner.js';
|
|
3
|
+
import { type CreatePrintAgentInput, type PrintRunCompletion } from './PrintAgentStore.js';
|
|
4
|
+
interface StoreLike {
|
|
5
|
+
create(input: CreatePrintAgentInput): Promise<PrintAgent>;
|
|
6
|
+
list(): Promise<PrintAgent[]>;
|
|
7
|
+
resolve(reference: string): Promise<PrintAgent | PrintAgent[] | null>;
|
|
8
|
+
acquireRun(id: string): Promise<{
|
|
9
|
+
agent: PrintAgent;
|
|
10
|
+
token: string;
|
|
11
|
+
}>;
|
|
12
|
+
recordProviderProcess(id: string, token: string, identity: ProcessIdentity): Promise<void>;
|
|
13
|
+
completeRun(id: string, token: string, result: PrintRunCompletion): Promise<PrintAgent>;
|
|
14
|
+
}
|
|
15
|
+
interface ProbeLike {
|
|
16
|
+
validate(): Promise<{
|
|
17
|
+
executable: string;
|
|
18
|
+
version: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
interface RunnerLike {
|
|
22
|
+
run(request: Parameters<ClaudePrintRunner['run']>[0]): Promise<ClaudePrintRunResult>;
|
|
23
|
+
}
|
|
24
|
+
export interface ClaudePrintAgentServiceOptions {
|
|
25
|
+
store?: StoreLike;
|
|
26
|
+
probe?: ProbeLike;
|
|
27
|
+
runner?: RunnerLike;
|
|
28
|
+
executable?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ClaudePrintSendResult extends ClaudePrintRunResult {
|
|
31
|
+
agentId: string;
|
|
32
|
+
agentName: string;
|
|
33
|
+
}
|
|
34
|
+
export declare class ClaudePrintAgentService {
|
|
35
|
+
readonly store: StoreLike;
|
|
36
|
+
private readonly probe;
|
|
37
|
+
private readonly runner;
|
|
38
|
+
private readonly executable?;
|
|
39
|
+
constructor(options?: ClaudePrintAgentServiceOptions);
|
|
40
|
+
create(input: CreatePrintAgentInput): Promise<PrintAgent>;
|
|
41
|
+
send(reference: string, prompt: string): Promise<ClaudePrintSendResult>;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=ClaudePrintAgentService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaudePrintAgentService.d.ts","sourceRoot":"","sources":["../../src/print/ClaudePrintAgentService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAAmB,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE5G,UAAU,SAAS;IACf,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC9B,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IACtE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3F;AAED,UAAU,SAAS;IAAG,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;AACpF,UAAU,UAAU;IAAG,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;CAAE;AAE7G,MAAM,WAAW,8BAA8B;IAC3C,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IAC/D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,uBAAuB;IAChC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;gBAEzB,OAAO,GAAE,8BAAmC;IAOlD,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC;IAKzD,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAoChF"}
|