@ai-devkit/agent-manager 0.26.3 → 0.26.4

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.
@@ -25,6 +25,7 @@ describe('AgentRegistry', ()=>{
25
25
  registry = new AgentRegistry(regPath);
26
26
  });
27
27
  afterEach(()=>{
28
+ vi.restoreAllMocks();
28
29
  fs.rmSync(tmpDir, {
29
30
  recursive: true,
30
31
  force: true
@@ -101,6 +102,22 @@ describe('AgentRegistry', ()=>{
101
102
  expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();
102
103
  expect(registry.list()).toHaveLength(1);
103
104
  });
105
+ it('preserves an existing name conflict when its probe fails with EPERM', ()=>{
106
+ registry.register(makeEntry({
107
+ name: 'claimed-name',
108
+ pid: process.pid
109
+ }));
110
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
111
+ throw Object.assign(new Error('operation not permitted'), {
112
+ code: 'EPERM'
113
+ });
114
+ });
115
+ expect(()=>registry.register(makeEntry({
116
+ name: 'claimed-name',
117
+ pid: process.pid + 1
118
+ }))).toThrow();
119
+ expect(registry.lookup('claimed-name')?.pid).toBe(process.pid);
120
+ });
104
121
  });
105
122
  describe('registerBatch', ()=>{
106
123
  it('is a no-op on empty array', ()=>{
@@ -161,6 +178,44 @@ describe('AgentRegistry', ()=>{
161
178
  expect(registry.list()).toHaveLength(1);
162
179
  expect(registry.lookup('custom-name')?.pid).toBe(process.pid);
163
180
  });
181
+ it('cleans up a cross-type row when its pid has been reused', ()=>{
182
+ registry.register(makeEntry({
183
+ name: 'old-claude',
184
+ type: 'claude',
185
+ pid: process.pid
186
+ }));
187
+ registry.register(makeEntry({
188
+ name: 'new-codex',
189
+ type: 'codex',
190
+ pid: process.pid,
191
+ tmuxSession: ''
192
+ }));
193
+ expect(registry.lookup('old-claude')).toBeNull();
194
+ expect(registry.lookup('new-codex')).toMatchObject({
195
+ type: 'codex',
196
+ pid: process.pid
197
+ });
198
+ expect(registry.list()).toHaveLength(1);
199
+ });
200
+ it('rolls back the whole batch when a live name conflict rejects one entry', ()=>{
201
+ registry.register(makeEntry({
202
+ name: 'taken',
203
+ pid: process.pid
204
+ }));
205
+ expect(()=>registry.registerBatch([
206
+ makeEntry({
207
+ name: 'fresh',
208
+ pid: 999998
209
+ }),
210
+ makeEntry({
211
+ name: 'taken',
212
+ type: 'codex',
213
+ pid: 999997
214
+ })
215
+ ])).toThrow(/UNIQUE constraint failed/);
216
+ expect(registry.lookup('fresh')).toBeNull();
217
+ expect(registry.lookup('taken')?.pid).toBe(process.pid);
218
+ });
164
219
  });
165
220
  describe('lookup', ()=>{
166
221
  it('returns null when name not found', ()=>{
@@ -207,6 +262,28 @@ describe('AgentRegistry', ()=>{
207
262
  pid: 999999
208
263
  }))).toBe(false);
209
264
  });
265
+ it('returns true when the process probe is forbidden with EPERM', ()=>{
266
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
267
+ throw Object.assign(new Error('operation not permitted'), {
268
+ code: 'EPERM'
269
+ });
270
+ });
271
+ expect(registry.isAlive(makeEntry())).toBe(true);
272
+ });
273
+ it('returns false when the process probe reports ESRCH', ()=>{
274
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
275
+ throw Object.assign(new Error('no such process'), {
276
+ code: 'ESRCH'
277
+ });
278
+ });
279
+ expect(registry.isAlive(makeEntry())).toBe(false);
280
+ });
281
+ it('returns true when the process probe fails without a definitive error code', ()=>{
282
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
283
+ throw new Error('indeterminate probe failure');
284
+ });
285
+ expect(registry.isAlive(makeEntry())).toBe(true);
286
+ });
210
287
  });
211
288
  describe('prune', ()=>{
212
289
  it('removes entries whose PIDs are dead', ()=>{
@@ -232,9 +309,55 @@ describe('AgentRegistry', ()=>{
232
309
  const after = registry.list();
233
310
  expect(after).toEqual(before);
234
311
  });
312
+ it('preserves entries when liveness probing fails with EPERM', ()=>{
313
+ registry.register(makeEntry({
314
+ name: 'custom-name',
315
+ tmuxSession: 'tmux-custom'
316
+ }));
317
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
318
+ throw Object.assign(new Error('operation not permitted'), {
319
+ code: 'EPERM'
320
+ });
321
+ });
322
+ registry.prune();
323
+ expect(registry.lookup('custom-name')).toMatchObject({
324
+ name: 'custom-name',
325
+ tmuxSession: 'tmux-custom'
326
+ });
327
+ });
328
+ it('removes entries when liveness probing fails with ESRCH', ()=>{
329
+ registry.register(makeEntry({
330
+ name: 'dead'
331
+ }));
332
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
333
+ throw Object.assign(new Error('no such process'), {
334
+ code: 'ESRCH'
335
+ });
336
+ });
337
+ registry.prune();
338
+ expect(registry.lookup('dead')).toBeNull();
339
+ });
235
340
  it('does nothing when file is missing', ()=>{
236
341
  expect(()=>registry.prune()).not.toThrow();
237
342
  });
343
+ it('keeps forced prune available before the passive cadence is due', ()=>{
344
+ let nowMs = Date.parse('2026-08-14T10:00:00.000Z');
345
+ const clocked = new AgentRegistry(regPath, {
346
+ now: ()=>new Date(nowMs),
347
+ pruneIntervalMs: 30_000
348
+ });
349
+ clocked.register(makeEntry({
350
+ name: 'forced',
351
+ pid: process.pid
352
+ }));
353
+ const alive = vi.spyOn(clocked, 'isAlive').mockReturnValue(true);
354
+ clocked.pruneIfDue();
355
+ alive.mockReturnValue(false);
356
+ nowMs += 1;
357
+ clocked.prune();
358
+ expect(alive).toHaveBeenCalledTimes(2);
359
+ expect(clocked.lookup('forced')).toBeNull();
360
+ });
238
361
  });
239
362
  describe('default()', ()=>{
240
363
  it('returns a singleton instance', ()=>{
@@ -278,6 +401,23 @@ describe('AgentRegistry', ()=>{
278
401
  }));
279
402
  expect(()=>registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);
280
403
  });
404
+ it('throws RenameConflictError when the conflicting entry probe fails with EPERM', ()=>{
405
+ registry.register(makeEntry({
406
+ name: 'agent-a',
407
+ pid: process.pid
408
+ }));
409
+ registry.register(makeEntry({
410
+ name: 'agent-b',
411
+ pid: process.ppid
412
+ }));
413
+ vi.spyOn(process, 'kill').mockImplementation(()=>{
414
+ throw Object.assign(new Error('operation not permitted'), {
415
+ code: 'EPERM'
416
+ });
417
+ });
418
+ expect(()=>registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);
419
+ expect(registry.lookup('agent-b')?.pid).toBe(process.ppid);
420
+ });
281
421
  it('succeeds when new name exists only as a stale (dead) entry', ()=>{
282
422
  registry.register(makeEntry({
283
423
  name: 'agent-a',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { AgentRegistry, RenameNotFoundError, RenameConflictError, type RegistryEntry } from '../../utils/AgentRegistry.js';\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: 'agent1',\n type: 'claude',\n pid: process.pid,\n tmuxSession: 'agent1',\n cwd: '/tmp',\n startedAt: '2026-05-30T00:00:00.000Z',\n sessionId: 'sid-1',\n sessionFilePath: '/tmp/session.jsonl',\n ...over,\n };\n}\n\ndescribe('AgentRegistry', () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-registry-'));\n regPath = path.join(tmpDir, 'nested', 'agents.json');\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe('register', () => {\n it('creates the SQLite database and parent directory if missing', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n expect(registry.list()[0].name).toBe('agent1');\n });\n\n it('appends a new entry when name is unique', () => {\n registry.register(makeEntry({ name: 'a' }));\n registry.register(makeEntry({ name: 'b', pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it('upserts in place when type and pid already exist', () => {\n registry.register(makeEntry({ name: 'a', pid: process.pid }));\n registry.register(makeEntry({ name: 'fallback', pid: process.pid, tmuxSession: '' }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe('a');\n });\n\n it('does not write through the legacy fixed .tmp path', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it('persists session fields', () => {\n registry.register(makeEntry({ sessionId: 'sid-xyz', sessionFilePath: '/foo/bar.jsonl' }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe('sid-xyz');\n expect(saved.sessionFilePath).toBe('/foo/bar.jsonl');\n });\n\n it('preserves existing tmuxSession when incoming is empty string', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.register(makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }));\n const saved = registry.lookup('a');\n expect(saved?.tmuxSession).toBe('pinned');\n expect(saved?.pid).toBe(process.pid);\n });\n\n it('lets a managed start entry replace a generated fallback for the same pid', () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n expect(registry.lookup('custom-name')?.tmuxSession).toBe('custom-name');\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n });\n\n describe('registerBatch', () => {\n it('is a no-op on empty array', () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it('upserts multiple entries in a single batch', () => {\n registry.registerBatch([\n makeEntry({ name: 'a' }),\n makeEntry({ name: 'b', pid: process.pid + 1 }),\n makeEntry({ name: 'c', pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it('applies the tmuxSession merge per entry', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.registerBatch([\n makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }),\n makeEntry({ name: 'b', tmuxSession: '', pid: process.pid + 1 }),\n ]);\n expect(registry.lookup('a')?.tmuxSession).toBe('pinned');\n expect(registry.lookup('a')?.pid).toBe(process.pid);\n expect(registry.lookup('b')?.tmuxSession).toBe('');\n });\n\n it('handles concurrent registry instances without duplicate pid rows', () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n other.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup('custom-name')?.pid).toBe(process.pid);\n });\n });\n\n describe('lookup', () => {\n it('returns null when name not found', () => {\n expect(registry.lookup('missing')).toBeNull();\n });\n\n it('returns the entry when name matches', () => {\n registry.register(makeEntry({ name: 'a' }));\n expect(registry.lookup('a')?.name).toBe('a');\n });\n });\n\n describe('list', () => {\n it('returns empty array when database does not contain entries', () => {\n expect(registry.list()).toEqual([]);\n });\n\n it('ignores existing legacy agents.json entries', () => {\n const legacyEntry = makeEntry({ name: 'legacy', tmuxSession: 'legacy' });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), 'utf8');\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup('legacy')).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n });\n });\n\n describe('isAlive', () => {\n it('returns true for the current process', () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it('returns false for a PID that does not exist', () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n });\n\n describe('prune', () => {\n it('removes entries whose PIDs are dead', () => {\n registry.register(makeEntry({ name: 'alive', pid: process.pid }));\n registry.register(makeEntry({ name: 'dead', pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe('alive');\n });\n\n it('is a no-op when all entries are alive', () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it('does nothing when file is missing', () => {\n expect(() => registry.prune()).not.toThrow();\n });\n });\n\n describe('default()', () => {\n it('returns a singleton instance', () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe('rename', () => {\n it('updates the name of an existing entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(registry.lookup('new-name')?.name).toBe('new-name');\n expect(registry.lookup('old-name')).toBeNull();\n });\n\n it('preserves all other fields on the renamed entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid, tmuxSession: 'old-name', cwd: '/my/cwd' }));\n registry.rename('old-name', 'new-name');\n const entry = registry.lookup('new-name');\n expect(entry?.tmuxSession).toBe('old-name');\n expect(entry?.cwd).toBe('/my/cwd');\n expect(entry?.pid).toBe(process.pid);\n });\n\n it('throws RenameNotFoundError when current name does not exist', () => {\n expect(() => registry.rename('ghost', 'new-name')).toThrow(RenameNotFoundError);\n });\n\n it('throws RenameConflictError when new name is already in use by a live entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n });\n\n it('succeeds when new name exists only as a stale (dead) entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: 999999 }));\n expect(() => registry.rename('agent-a', 'agent-b')).not.toThrow();\n expect(registry.lookup('agent-b')?.pid).toBe(process.pid);\n });\n\n it('does not create the legacy fixed .tmp path on rename', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","tmuxSession","cwd","startedAt","sessionId","sessionFilePath","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","lookup","toBeNull","registerBatch","other","toEqual","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","isAlive","prune","remaining","before","after","not","toThrow","default","rename","entry"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport { AgentRegistry, RenameNotFoundError, RenameConflictError, type RegistryEntry } from '../../utils/AgentRegistry.js';\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: 'agent1',\n type: 'claude',\n pid: process.pid,\n tmuxSession: 'agent1',\n cwd: '/tmp',\n startedAt: '2026-05-30T00:00:00.000Z',\n sessionId: 'sid-1',\n sessionFilePath: '/tmp/session.jsonl',\n ...over,\n };\n}\n\ndescribe('AgentRegistry', () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-registry-'));\n regPath = path.join(tmpDir, 'nested', 'agents.json');\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe('register', () => {\n it('creates the SQLite database and parent directory if missing', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n expect(registry.list()[0].name).toBe('agent1');\n });\n\n it('appends a new entry when name is unique', () => {\n registry.register(makeEntry({ name: 'a' }));\n registry.register(makeEntry({ name: 'b', pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it('upserts in place when type and pid already exist', () => {\n registry.register(makeEntry({ name: 'a', pid: process.pid }));\n registry.register(makeEntry({ name: 'fallback', pid: process.pid, tmuxSession: '' }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe('a');\n });\n\n it('does not write through the legacy fixed .tmp path', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it('persists session fields', () => {\n registry.register(makeEntry({ sessionId: 'sid-xyz', sessionFilePath: '/foo/bar.jsonl' }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe('sid-xyz');\n expect(saved.sessionFilePath).toBe('/foo/bar.jsonl');\n });\n\n it('preserves existing tmuxSession when incoming is empty string', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.register(makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }));\n const saved = registry.lookup('a');\n expect(saved?.tmuxSession).toBe('pinned');\n expect(saved?.pid).toBe(process.pid);\n });\n\n it('lets a managed start entry replace a generated fallback for the same pid', () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n expect(registry.lookup('custom-name')?.tmuxSession).toBe('custom-name');\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it('preserves an existing name conflict when its probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'claimed-name', pid: process.pid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.register(makeEntry({\n name: 'claimed-name',\n pid: process.pid + 1,\n }))).toThrow();\n expect(registry.lookup('claimed-name')?.pid).toBe(process.pid);\n });\n });\n\n describe('registerBatch', () => {\n it('is a no-op on empty array', () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it('upserts multiple entries in a single batch', () => {\n registry.registerBatch([\n makeEntry({ name: 'a' }),\n makeEntry({ name: 'b', pid: process.pid + 1 }),\n makeEntry({ name: 'c', pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it('applies the tmuxSession merge per entry', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.registerBatch([\n makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }),\n makeEntry({ name: 'b', tmuxSession: '', pid: process.pid + 1 }),\n ]);\n expect(registry.lookup('a')?.tmuxSession).toBe('pinned');\n expect(registry.lookup('a')?.pid).toBe(process.pid);\n expect(registry.lookup('b')?.tmuxSession).toBe('');\n });\n\n it('handles concurrent registry instances without duplicate pid rows', () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n other.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup('custom-name')?.pid).toBe(process.pid);\n });\n\n it('cleans up a cross-type row when its pid has been reused', () => {\n registry.register(makeEntry({ name: 'old-claude', type: 'claude', pid: process.pid }));\n\n registry.register(makeEntry({\n name: 'new-codex',\n type: 'codex',\n pid: process.pid,\n tmuxSession: '',\n }));\n\n expect(registry.lookup('old-claude')).toBeNull();\n expect(registry.lookup('new-codex')).toMatchObject({ type: 'codex', pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it('rolls back the whole batch when a live name conflict rejects one entry', () => {\n registry.register(makeEntry({ name: 'taken', pid: process.pid }));\n\n expect(() => registry.registerBatch([\n makeEntry({ name: 'fresh', pid: 999998 }),\n makeEntry({ name: 'taken', type: 'codex', pid: 999997 }),\n ])).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup('fresh')).toBeNull();\n expect(registry.lookup('taken')?.pid).toBe(process.pid);\n });\n });\n\n describe('lookup', () => {\n it('returns null when name not found', () => {\n expect(registry.lookup('missing')).toBeNull();\n });\n\n it('returns the entry when name matches', () => {\n registry.register(makeEntry({ name: 'a' }));\n expect(registry.lookup('a')?.name).toBe('a');\n });\n });\n\n describe('list', () => {\n it('returns empty array when database does not contain entries', () => {\n expect(registry.list()).toEqual([]);\n });\n\n it('ignores existing legacy agents.json entries', () => {\n const legacyEntry = makeEntry({ name: 'legacy', tmuxSession: 'legacy' });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), 'utf8');\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup('legacy')).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n });\n });\n\n describe('isAlive', () => {\n it('returns true for the current process', () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it('returns false for a PID that does not exist', () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it('returns true when the process probe is forbidden with EPERM', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it('returns false when the process probe reports ESRCH', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it('returns true when the process probe fails without a definitive error code', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw new Error('indeterminate probe failure');\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe('prune', () => {\n it('removes entries whose PIDs are dead', () => {\n registry.register(makeEntry({ name: 'alive', pid: process.pid }));\n registry.register(makeEntry({ name: 'dead', pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe('alive');\n });\n\n it('is a no-op when all entries are alive', () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it('preserves entries when liveness probing fails with EPERM', () => {\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'tmux-custom' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n registry.prune();\n\n expect(registry.lookup('custom-name')).toMatchObject({\n name: 'custom-name',\n tmuxSession: 'tmux-custom',\n });\n });\n\n it('removes entries when liveness probing fails with ESRCH', () => {\n registry.register(makeEntry({ name: 'dead' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n registry.prune();\n\n expect(registry.lookup('dead')).toBeNull();\n });\n\n it('does nothing when file is missing', () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it('keeps forced prune available before the passive cadence is due', () => {\n let nowMs = Date.parse('2026-08-14T10:00:00.000Z');\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: 'forced', pid: process.pid }));\n const alive = vi.spyOn(clocked, 'isAlive').mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup('forced')).toBeNull();\n });\n });\n\n describe('default()', () => {\n it('returns a singleton instance', () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe('rename', () => {\n it('updates the name of an existing entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(registry.lookup('new-name')?.name).toBe('new-name');\n expect(registry.lookup('old-name')).toBeNull();\n });\n\n it('preserves all other fields on the renamed entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid, tmuxSession: 'old-name', cwd: '/my/cwd' }));\n registry.rename('old-name', 'new-name');\n const entry = registry.lookup('new-name');\n expect(entry?.tmuxSession).toBe('old-name');\n expect(entry?.cwd).toBe('/my/cwd');\n expect(entry?.pid).toBe(process.pid);\n });\n\n it('throws RenameNotFoundError when current name does not exist', () => {\n expect(() => registry.rename('ghost', 'new-name')).toThrow(RenameNotFoundError);\n });\n\n it('throws RenameConflictError when new name is already in use by a live entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n });\n\n it('throws RenameConflictError when the conflicting entry probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n expect(registry.lookup('agent-b')?.pid).toBe(process.ppid);\n });\n\n it('succeeds when new name exists only as a stale (dead) entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: 999999 }));\n expect(() => registry.rename('agent-a', 'agent-b')).not.toThrow();\n expect(registry.lookup('agent-b')?.pid).toBe(process.pid);\n });\n\n it('does not create the legacy fixed .tmp path on rename', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","tmuxSession","cwd","startedAt","sessionId","sessionFilePath","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","lookup","toBeNull","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","toMatchObject","toEqual","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","isAlive","prune","remaining","before","after","not","nowMs","Date","parse","clocked","now","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","rename","entry"],"mappings":"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"}
@@ -2,7 +2,7 @@ import Database from 'better-sqlite3';
2
2
  export declare const DEFAULT_AGENT_REGISTRY_DB_PATH: string;
3
3
  export interface DatabaseOptions {
4
4
  dbPath?: string;
5
- verbose?: boolean;
5
+ verbose?: boolean | ((message: string) => void);
6
6
  readonly?: boolean;
7
7
  }
8
8
  export declare function resolveAgentRegistryDbPath(filePath?: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAMtC,eAAO,MAAM,8BAA8B,QAA6C,CAAC;AAEzF,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,GAAE,eAAoB;IAazC,OAAO,CAAC,SAAS;IAQjB,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAEhC;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,CAAC,EAAE;IAIlD,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,CAAC,GAAG,SAAS;IAI/D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,QAAQ,CAAC,SAAS;IAIhE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAI9B,KAAK,IAAI,IAAI;CAKhB"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/database/connection.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAMtC,eAAO,MAAM,8BAA8B,QAA6C,CAAC;AAEzF,MAAM,WAAW,eAAe;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpE;AAED,qBAAa,kBAAkB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,GAAE,eAAoB;IAezC,OAAO,CAAC,SAAS;IAQjB,IAAI,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAEhC;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,CAAC,EAAE;IAIlD,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,CAAC,GAAG,SAAS;IAI/D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,OAAO,EAAO,GAAG,QAAQ,CAAC,SAAS;IAIhE,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAI9B,KAAK,IAAI,IAAI;CAKhB"}
@@ -18,7 +18,7 @@ export class DatabaseConnection {
18
18
  });
19
19
  this.db = new Database(this.dbPath, {
20
20
  readonly: options.readonly ?? false,
21
- verbose: options.verbose ? console.log : undefined
21
+ verbose: typeof options.verbose === 'function' ? options.verbose : options.verbose ? console.log : undefined
22
22
  });
23
23
  this.configure();
24
24
  initializeSchema(this);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/database/connection.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { mkdirSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { homedir } from 'os';\nimport { initializeSchema } from './schema.js';\n\nexport const DEFAULT_AGENT_REGISTRY_DB_PATH = join(homedir(), '.ai-devkit', 'agents.db');\n\nexport interface DatabaseOptions {\n dbPath?: string;\n verbose?: boolean;\n readonly?: boolean;\n}\n\nexport function resolveAgentRegistryDbPath(filePath?: string): string {\n if (!filePath) return DEFAULT_AGENT_REGISTRY_DB_PATH;\n return filePath.endsWith('.json') ? filePath.replace(/\\.json$/, '.db') : filePath;\n}\n\nexport class DatabaseConnection {\n private db: Database.Database;\n private readonly dbPath: string;\n\n constructor(options: DatabaseOptions = {}) {\n this.dbPath = options.dbPath ?? DEFAULT_AGENT_REGISTRY_DB_PATH;\n mkdirSync(dirname(this.dbPath), { recursive: true });\n\n this.db = new Database(this.dbPath, {\n readonly: options.readonly ?? false,\n verbose: options.verbose ? console.log : undefined,\n });\n\n this.configure();\n initializeSchema(this);\n }\n\n private configure(): void {\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.pragma('synchronous = NORMAL');\n this.db.pragma('busy_timeout = 5000');\n this.db.pragma('mmap_size = 268435456');\n }\n\n get instance(): Database.Database {\n return this.db;\n }\n\n get path(): string {\n return this.dbPath;\n }\n\n query<T>(sql: string, params: unknown[] = []): T[] {\n return this.db.prepare(sql).all(...params) as T[];\n }\n\n queryOne<T>(sql: string, params: unknown[] = []): T | undefined {\n return this.db.prepare(sql).get(...params) as T | undefined;\n }\n\n execute(sql: string, params: unknown[] = []): Database.RunResult {\n return this.db.prepare(sql).run(...params);\n }\n\n transaction<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n\n close(): void {\n if (this.db.open) {\n this.db.close();\n }\n }\n}\n"],"names":["Database","mkdirSync","dirname","join","homedir","initializeSchema","DEFAULT_AGENT_REGISTRY_DB_PATH","resolveAgentRegistryDbPath","filePath","endsWith","replace","DatabaseConnection","db","dbPath","options","recursive","readonly","verbose","console","log","undefined","configure","pragma","instance","path","query","sql","params","prepare","all","queryOne","get","execute","run","transaction","fn","close","open"],"mappings":"AAAA,OAAOA,cAAc,iBAAiB;AACtC,SAASC,SAAS,QAAQ,KAAK;AAC/B,SAASC,OAAO,EAAEC,IAAI,QAAQ,OAAO;AACrC,SAASC,OAAO,QAAQ,KAAK;AAC7B,SAASC,gBAAgB,QAAQ,cAAc;AAE/C,OAAO,MAAMC,iCAAiCH,KAAKC,WAAW,cAAc,aAAa;AAQzF,OAAO,SAASG,2BAA2BC,QAAiB;IACxD,IAAI,CAACA,UAAU,OAAOF;IACtB,OAAOE,SAASC,QAAQ,CAAC,WAAWD,SAASE,OAAO,CAAC,WAAW,SAASF;AAC7E;AAEA,OAAO,MAAMG;IACDC,GAAsB;IACbC,OAAe;IAEhC,YAAYC,UAA2B,CAAC,CAAC,CAAE;QACvC,IAAI,CAACD,MAAM,GAAGC,QAAQD,MAAM,IAAIP;QAChCL,UAAUC,QAAQ,IAAI,CAACW,MAAM,GAAG;YAAEE,WAAW;QAAK;QAElD,IAAI,CAACH,EAAE,GAAG,IAAIZ,SAAS,IAAI,CAACa,MAAM,EAAE;YAChCG,UAAUF,QAAQE,QAAQ,IAAI;YAC9BC,SAASH,QAAQG,OAAO,GAAGC,QAAQC,GAAG,GAAGC;QAC7C;QAEA,IAAI,CAACC,SAAS;QACdhB,iBAAiB,IAAI;IACzB;IAEQgB,YAAkB;QACtB,IAAI,CAACT,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;IACnB;IAEA,IAAIC,WAA8B;QAC9B,OAAO,IAAI,CAACX,EAAE;IAClB;IAEA,IAAIY,OAAe;QACf,OAAO,IAAI,CAACX,MAAM;IACtB;IAEAY,MAASC,GAAW,EAAEC,SAAoB,EAAE,EAAO;QAC/C,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKG,GAAG,IAAIF;IACvC;IAEAG,SAAYJ,GAAW,EAAEC,SAAoB,EAAE,EAAiB;QAC5D,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKK,GAAG,IAAIJ;IACvC;IAEAK,QAAQN,GAAW,EAAEC,SAAoB,EAAE,EAAsB;QAC7D,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKO,GAAG,IAAIN;IACvC;IAEAO,YAAeC,EAAW,EAAK;QAC3B,OAAO,IAAI,CAACvB,EAAE,CAACsB,WAAW,CAACC;IAC/B;IAEAC,QAAc;QACV,IAAI,IAAI,CAACxB,EAAE,CAACyB,IAAI,EAAE;YACd,IAAI,CAACzB,EAAE,CAACwB,KAAK;QACjB;IACJ;AACJ"}
1
+ {"version":3,"sources":["../../src/database/connection.ts"],"sourcesContent":["import Database from 'better-sqlite3';\nimport { mkdirSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { homedir } from 'os';\nimport { initializeSchema } from './schema.js';\n\nexport const DEFAULT_AGENT_REGISTRY_DB_PATH = join(homedir(), '.ai-devkit', 'agents.db');\n\nexport interface DatabaseOptions {\n dbPath?: string;\n verbose?: boolean | ((message: string) => void);\n readonly?: boolean;\n}\n\nexport function resolveAgentRegistryDbPath(filePath?: string): string {\n if (!filePath) return DEFAULT_AGENT_REGISTRY_DB_PATH;\n return filePath.endsWith('.json') ? filePath.replace(/\\.json$/, '.db') : filePath;\n}\n\nexport class DatabaseConnection {\n private db: Database.Database;\n private readonly dbPath: string;\n\n constructor(options: DatabaseOptions = {}) {\n this.dbPath = options.dbPath ?? DEFAULT_AGENT_REGISTRY_DB_PATH;\n mkdirSync(dirname(this.dbPath), { recursive: true });\n\n this.db = new Database(this.dbPath, {\n readonly: options.readonly ?? false,\n verbose: typeof options.verbose === 'function'\n ? options.verbose\n : options.verbose ? console.log : undefined,\n });\n\n this.configure();\n initializeSchema(this);\n }\n\n private configure(): void {\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('foreign_keys = ON');\n this.db.pragma('synchronous = NORMAL');\n this.db.pragma('busy_timeout = 5000');\n this.db.pragma('mmap_size = 268435456');\n }\n\n get instance(): Database.Database {\n return this.db;\n }\n\n get path(): string {\n return this.dbPath;\n }\n\n query<T>(sql: string, params: unknown[] = []): T[] {\n return this.db.prepare(sql).all(...params) as T[];\n }\n\n queryOne<T>(sql: string, params: unknown[] = []): T | undefined {\n return this.db.prepare(sql).get(...params) as T | undefined;\n }\n\n execute(sql: string, params: unknown[] = []): Database.RunResult {\n return this.db.prepare(sql).run(...params);\n }\n\n transaction<T>(fn: () => T): T {\n return this.db.transaction(fn)();\n }\n\n close(): void {\n if (this.db.open) {\n this.db.close();\n }\n }\n}\n"],"names":["Database","mkdirSync","dirname","join","homedir","initializeSchema","DEFAULT_AGENT_REGISTRY_DB_PATH","resolveAgentRegistryDbPath","filePath","endsWith","replace","DatabaseConnection","db","dbPath","options","recursive","readonly","verbose","console","log","undefined","configure","pragma","instance","path","query","sql","params","prepare","all","queryOne","get","execute","run","transaction","fn","close","open"],"mappings":"AAAA,OAAOA,cAAc,iBAAiB;AACtC,SAASC,SAAS,QAAQ,KAAK;AAC/B,SAASC,OAAO,EAAEC,IAAI,QAAQ,OAAO;AACrC,SAASC,OAAO,QAAQ,KAAK;AAC7B,SAASC,gBAAgB,QAAQ,cAAc;AAE/C,OAAO,MAAMC,iCAAiCH,KAAKC,WAAW,cAAc,aAAa;AAQzF,OAAO,SAASG,2BAA2BC,QAAiB;IACxD,IAAI,CAACA,UAAU,OAAOF;IACtB,OAAOE,SAASC,QAAQ,CAAC,WAAWD,SAASE,OAAO,CAAC,WAAW,SAASF;AAC7E;AAEA,OAAO,MAAMG;IACDC,GAAsB;IACbC,OAAe;IAEhC,YAAYC,UAA2B,CAAC,CAAC,CAAE;QACvC,IAAI,CAACD,MAAM,GAAGC,QAAQD,MAAM,IAAIP;QAChCL,UAAUC,QAAQ,IAAI,CAACW,MAAM,GAAG;YAAEE,WAAW;QAAK;QAElD,IAAI,CAACH,EAAE,GAAG,IAAIZ,SAAS,IAAI,CAACa,MAAM,EAAE;YAChCG,UAAUF,QAAQE,QAAQ,IAAI;YAC9BC,SAAS,OAAOH,QAAQG,OAAO,KAAK,aAC9BH,QAAQG,OAAO,GACfH,QAAQG,OAAO,GAAGC,QAAQC,GAAG,GAAGC;QAC1C;QAEA,IAAI,CAACC,SAAS;QACdhB,iBAAiB,IAAI;IACzB;IAEQgB,YAAkB;QACtB,IAAI,CAACT,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;QACf,IAAI,CAACV,EAAE,CAACU,MAAM,CAAC;IACnB;IAEA,IAAIC,WAA8B;QAC9B,OAAO,IAAI,CAACX,EAAE;IAClB;IAEA,IAAIY,OAAe;QACf,OAAO,IAAI,CAACX,MAAM;IACtB;IAEAY,MAASC,GAAW,EAAEC,SAAoB,EAAE,EAAO;QAC/C,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKG,GAAG,IAAIF;IACvC;IAEAG,SAAYJ,GAAW,EAAEC,SAAoB,EAAE,EAAiB;QAC5D,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKK,GAAG,IAAIJ;IACvC;IAEAK,QAAQN,GAAW,EAAEC,SAAoB,EAAE,EAAsB;QAC7D,OAAO,IAAI,CAACf,EAAE,CAACgB,OAAO,CAACF,KAAKO,GAAG,IAAIN;IACvC;IAEAO,YAAeC,EAAW,EAAK;QAC3B,OAAO,IAAI,CAACvB,EAAE,CAACsB,WAAW,CAACC;IAC/B;IAEAC,QAAc;QACV,IAAI,IAAI,CAACxB,EAAE,CAACyB,IAAI,EAAE;YACd,IAAI,CAACzB,EAAE,CAACwB,KAAK;QACjB;IACJ;AACJ"}
package/dist/index.d.ts CHANGED
@@ -16,7 +16,7 @@ export { captureProcessSnapshot, executableBasename, filterByProcessNames } from
16
16
  export type { AgentSortKey } from './utils/sortAgents.js';
17
17
  export type { ListAgentsOptions } from './AgentManager.js';
18
18
  export { AgentRegistry, RenameNotFoundError, RenameConflictError } from './utils/AgentRegistry.js';
19
- export type { RegistryEntry } from './utils/AgentRegistry.js';
19
+ export type { AgentRegistryOptions, RegistryEntry } from './utils/AgentRegistry.js';
20
20
  export { TmuxManager } from './terminal/TmuxManager.js';
21
21
  export { AGENTS } from './utils/agents.js';
22
22
  export type { AgentConfig, StartableAgentType } from './utils/agents.js';
@@ -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,EACnB,qBAAqB,GACxB,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,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACtG,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"}
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,EACnB,qBAAqB,GACxB,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,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACtG,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,oBAAoB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACpF,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.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 AgentDetectionContext,\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 { captureProcessSnapshot, executableBasename, filterByProcessNames } 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","captureProcessSnapshot","executableBasename","filterByProcessNames","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;AAYzD,SAASC,oBAAoB,EAAEC,YAAY,QAAQ,qCAAqC;AAExF,SAASC,SAAS,QAAQ,0BAA0B;AAEpD,SAASC,aAAa,QAAQ,qBAAqB;AACnD,SAASC,sBAAsB,EAAEC,kBAAkB,EAAEC,oBAAoB,QAAQ,qBAAqB;AAItG,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"}
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 AgentDetectionContext,\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 { captureProcessSnapshot, executableBasename, filterByProcessNames } 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 { AgentRegistryOptions, 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","captureProcessSnapshot","executableBasename","filterByProcessNames","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;AAYzD,SAASC,oBAAoB,EAAEC,YAAY,QAAQ,qCAAqC;AAExF,SAASC,SAAS,QAAQ,0BAA0B;AAEpD,SAASC,aAAa,QAAQ,qBAAqB;AACnD,SAASC,sBAAsB,EAAEC,kBAAkB,EAAEC,oBAAoB,QAAQ,qBAAqB;AAItG,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"}
@@ -17,19 +17,32 @@ export interface RegistryEntry {
17
17
  sessionId: string;
18
18
  sessionFilePath: string;
19
19
  }
20
+ export interface AgentRegistryOptions {
21
+ now?: () => Date;
22
+ pruneIntervalMs?: number;
23
+ onDatabaseOperation?: (sql: string) => void;
24
+ }
20
25
  export declare class AgentRegistry {
21
26
  private db;
22
- constructor(filePath?: string);
27
+ private readonly now;
28
+ private readonly pruneIntervalMs;
29
+ private lastPrunedAt;
30
+ constructor(filePath?: string, options?: AgentRegistryOptions);
23
31
  static default(): AgentRegistry;
24
32
  private rowToEntry;
25
33
  private mergeEntry;
26
34
  private findByIdentity;
27
35
  private findByName;
36
+ private findPidConflicts;
37
+ private entriesEqual;
28
38
  private deleteNameConflict;
29
39
  private insertOrUpdate;
40
+ private needsWrite;
30
41
  private save;
31
42
  isAlive(entry: RegistryEntry): boolean;
43
+ private pruneAt;
32
44
  prune(): void;
45
+ pruneIfDue(): void;
33
46
  register(entry: RegistryEntry): void;
34
47
  registerBatch(entries: RegistryEntry[]): void;
35
48
  rename(currentName: string, newName: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"AgentRegistry.d.ts","sourceRoot":"","sources":["../../src/utils/AgentRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAM7D,qBAAa,mBAAoB,SAAQ,KAAK;IACvB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIvC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IACvB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIvC;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAkBD,qBAAa,aAAa;IACtB,OAAO,CAAC,EAAE,CAAqB;gBAEnB,QAAQ,GAAE,MAA8B;IAIpD,MAAM,CAAC,OAAO,IAAI,aAAa;IAO/B,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAStC,KAAK,IAAI,IAAI;IAUb,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIpC,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAU7C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAqBlD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI1C,IAAI,IAAI,aAAa,EAAE;CAI1B"}
1
+ {"version":3,"file":"AgentRegistry.d.ts","sourceRoot":"","sources":["../../src/utils/AgentRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAM7D,qBAAa,mBAAoB,SAAQ,KAAK;IACvB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIvC;AAED,qBAAa,mBAAoB,SAAQ,KAAK;IACvB,SAAS,EAAE,MAAM;gBAAjB,SAAS,EAAE,MAAM;CAIvC;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAmBD,MAAM,WAAW,oBAAoB;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,EAAE,CAAqB;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,YAAY,CAAqB;gBAE7B,QAAQ,GAAE,MAA8B,EAAE,OAAO,GAAE,oBAAyB;IASxF,MAAM,CAAC,OAAO,IAAI,aAAa;IAO/B,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,IAAI;IAeZ,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAYtC,OAAO,CAAC,OAAO;IAaf,KAAK,IAAI,IAAI;IAIb,UAAU,IAAI,IAAI;IAOlB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAIpC,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI;IAU7C,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAqBlD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAI1C,IAAI,IAAI,aAAa,EAAE;CAI1B"}
@@ -16,12 +16,19 @@ export class RenameConflictError extends Error {
16
16
  }
17
17
  }
18
18
  const DEFAULT_REGISTRY_PATH = path.join(os.homedir(), '.ai-devkit', 'agents.json');
19
+ const DEFAULT_PRUNE_INTERVAL_MS = 30_000;
19
20
  let defaultInstance = null;
20
21
  export class AgentRegistry {
21
22
  db;
22
- constructor(filePath = DEFAULT_REGISTRY_PATH){
23
+ now;
24
+ pruneIntervalMs;
25
+ lastPrunedAt;
26
+ constructor(filePath = DEFAULT_REGISTRY_PATH, options = {}){
27
+ this.now = options.now ?? (()=>new Date());
28
+ this.pruneIntervalMs = options.pruneIntervalMs ?? DEFAULT_PRUNE_INTERVAL_MS;
23
29
  this.db = new DatabaseConnection({
24
- dbPath: resolveAgentRegistryDbPath(filePath)
30
+ dbPath: resolveAgentRegistryDbPath(filePath),
31
+ verbose: options.onDatabaseOperation
25
32
  });
26
33
  }
27
34
  static default() {
@@ -68,6 +75,15 @@ export class AgentRegistry {
68
75
  ]);
69
76
  return row ? this.rowToEntry(row) : undefined;
70
77
  }
78
+ findPidConflicts(type, pid) {
79
+ return this.db.query('SELECT * FROM agents WHERE pid = ? AND type <> ?', [
80
+ pid,
81
+ type
82
+ ]).map((row)=>this.rowToEntry(row));
83
+ }
84
+ entriesEqual(left, right) {
85
+ return left.name === right.name && left.type === right.type && left.pid === right.pid && left.tmuxSession === right.tmuxSession && left.cwd === right.cwd && left.startedAt === right.startedAt && left.sessionId === right.sessionId && left.sessionFilePath === right.sessionFilePath;
86
+ }
71
87
  deleteNameConflict(name, type, pid) {
72
88
  const conflict = this.findByName(name);
73
89
  if (!conflict) return;
@@ -97,32 +113,61 @@ export class AgentRegistry {
97
113
  updated_at = excluded.updated_at
98
114
  `).run({
99
115
  ...entry,
100
- updatedAt: new Date().toISOString()
116
+ updatedAt: this.now().toISOString()
101
117
  });
102
118
  }
103
- save(entry) {
104
- this.deleteNameConflict(entry.name, entry.type, entry.pid);
105
- this.insertOrUpdate(entry);
119
+ needsWrite(incoming) {
120
+ const existing = this.findByIdentity(incoming.type, incoming.pid);
121
+ const merged = this.mergeEntry(incoming, existing);
122
+ return !existing || !this.entriesEqual(merged, existing) || this.findPidConflicts(incoming.type, incoming.pid).length > 0;
123
+ }
124
+ save(incoming) {
125
+ const existing = this.findByIdentity(incoming.type, incoming.pid);
126
+ const merged = this.mergeEntry(incoming, existing);
127
+ const pidConflicts = this.findPidConflicts(incoming.type, incoming.pid);
128
+ if (existing && this.entriesEqual(merged, existing) && pidConflicts.length === 0) return;
129
+ for (const conflict of pidConflicts){
130
+ this.db.execute('DELETE FROM agents WHERE type = ? AND pid = ?', [
131
+ conflict.type,
132
+ conflict.pid
133
+ ]);
134
+ }
135
+ if (existing && this.entriesEqual(merged, existing)) return;
136
+ this.deleteNameConflict(merged.name, merged.type, merged.pid);
137
+ this.insertOrUpdate(merged);
106
138
  }
107
139
  isAlive(entry) {
108
140
  try {
109
141
  process.kill(entry.pid, 0);
110
142
  return true;
111
- } catch {
112
- return false;
143
+ } catch (error) {
144
+ const code = error && typeof error === 'object' && 'code' in error ? error.code : undefined;
145
+ return code !== 'ESRCH';
113
146
  }
114
147
  }
115
- prune() {
148
+ pruneAt(nowMs) {
116
149
  const entries = this.list();
117
150
  const stale = entries.filter((e)=>!this.isAlive(e));
118
- this.db.transaction(()=>{
119
- for (const entry of stale){
120
- this.db.execute('DELETE FROM agents WHERE type = ? AND pid = ?', [
121
- entry.type,
122
- entry.pid
123
- ]);
124
- }
125
- });
151
+ if (stale.length > 0) {
152
+ this.db.transaction(()=>{
153
+ for (const entry of stale){
154
+ this.db.execute('DELETE FROM agents WHERE type = ? AND pid = ?', [
155
+ entry.type,
156
+ entry.pid
157
+ ]);
158
+ }
159
+ });
160
+ }
161
+ this.lastPrunedAt = nowMs;
162
+ }
163
+ prune() {
164
+ this.pruneAt(this.now().getTime());
165
+ }
166
+ pruneIfDue() {
167
+ const nowMs = this.now().getTime();
168
+ const elapsed = this.lastPrunedAt === undefined ? undefined : nowMs - this.lastPrunedAt;
169
+ if (elapsed !== undefined && elapsed >= 0 && elapsed < this.pruneIntervalMs) return;
170
+ this.pruneAt(nowMs);
126
171
  }
127
172
  register(entry) {
128
173
  this.registerBatch([
@@ -131,10 +176,10 @@ export class AgentRegistry {
131
176
  }
132
177
  registerBatch(entries) {
133
178
  if (entries.length === 0) return;
179
+ if (!entries.some((entry)=>this.needsWrite(entry))) return;
134
180
  this.db.transaction(()=>{
135
181
  for (const incoming of entries){
136
- const existing = this.findByIdentity(incoming.type, incoming.pid);
137
- this.save(this.mergeEntry(incoming, existing));
182
+ this.save(incoming);
138
183
  }
139
184
  });
140
185
  }
@@ -156,7 +201,7 @@ export class AgentRegistry {
156
201
  }
157
202
  this.db.execute('UPDATE agents SET name = ?, updated_at = ? WHERE type = ? AND pid = ?', [
158
203
  newName,
159
- new Date().toISOString(),
204
+ this.now().toISOString(),
160
205
  existing.type,
161
206
  existing.pid
162
207
  ]);