@ai-devkit/agent-manager 0.16.0 → 0.18.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.
Files changed (105) hide show
  1. package/.swcrc +27 -0
  2. package/dist/AgentManager.js +72 -74
  3. package/dist/AgentManager.js.map +1 -1
  4. package/dist/__tests__/AgentManager.test.js +564 -0
  5. package/dist/__tests__/AgentManager.test.js.map +1 -0
  6. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +2157 -0
  7. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -0
  8. package/dist/__tests__/adapters/CodexAdapter.test.js +1419 -0
  9. package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -0
  10. package/dist/__tests__/adapters/CopilotAdapter.test.js +500 -0
  11. package/dist/__tests__/adapters/CopilotAdapter.test.js.map +1 -0
  12. package/dist/__tests__/adapters/GeminiCliAdapter.test.js +1229 -0
  13. package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +1 -0
  14. package/dist/__tests__/adapters/OpenCodeAdapter.test.js +626 -0
  15. package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -0
  16. package/dist/__tests__/adapters/PiAdapter.test.js +590 -0
  17. package/dist/__tests__/adapters/PiAdapter.test.js.map +1 -0
  18. package/dist/__tests__/terminal/TmuxManager.test.js +159 -0
  19. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -0
  20. package/dist/__tests__/terminal/TtyWriter.test.js +162 -0
  21. package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -0
  22. package/dist/__tests__/utils/AgentRegistry.test.js +282 -0
  23. package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -0
  24. package/dist/__tests__/utils/ClaudeSessionParser.test.js +312 -0
  25. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -0
  26. package/dist/__tests__/utils/matching.test.js +324 -0
  27. package/dist/__tests__/utils/matching.test.js.map +1 -0
  28. package/dist/__tests__/utils/process.test.js +177 -0
  29. package/dist/__tests__/utils/process.test.js.map +1 -0
  30. package/dist/__tests__/utils/session.test.js +158 -0
  31. package/dist/__tests__/utils/session.test.js.map +1 -0
  32. package/dist/adapters/AgentAdapter.d.ts +1 -1
  33. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  34. package/dist/adapters/AgentAdapter.js +8 -7
  35. package/dist/adapters/AgentAdapter.js.map +1 -1
  36. package/dist/adapters/ClaudeCodeAdapter.js +66 -77
  37. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  38. package/dist/adapters/CodexAdapter.d.ts +13 -0
  39. package/dist/adapters/CodexAdapter.d.ts.map +1 -1
  40. package/dist/adapters/CodexAdapter.js +225 -141
  41. package/dist/adapters/CodexAdapter.js.map +1 -1
  42. package/dist/adapters/CopilotAdapter.d.ts +44 -0
  43. package/dist/adapters/CopilotAdapter.d.ts.map +1 -0
  44. package/dist/adapters/CopilotAdapter.js +314 -0
  45. package/dist/adapters/CopilotAdapter.js.map +1 -0
  46. package/dist/adapters/GeminiCliAdapter.d.ts +2 -0
  47. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  48. package/dist/adapters/GeminiCliAdapter.js +138 -156
  49. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  50. package/dist/adapters/OpenCodeAdapter.js +60 -69
  51. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  52. package/dist/adapters/PiAdapter.d.ts +62 -0
  53. package/dist/adapters/PiAdapter.d.ts.map +1 -0
  54. package/dist/adapters/PiAdapter.js +450 -0
  55. package/dist/adapters/PiAdapter.js.map +1 -0
  56. package/dist/adapters/index.d.ts +2 -0
  57. package/dist/adapters/index.d.ts.map +1 -1
  58. package/dist/adapters/index.js +3 -0
  59. package/dist/adapters/index.js.map +1 -1
  60. package/dist/index.d.ts +2 -0
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +3 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/terminal/TerminalFocusManager.js +62 -49
  65. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  66. package/dist/terminal/TmuxManager.js +59 -34
  67. package/dist/terminal/TmuxManager.js.map +1 -1
  68. package/dist/terminal/TtyWriter.js +37 -16
  69. package/dist/terminal/TtyWriter.js.map +1 -1
  70. package/dist/terminal/index.js +1 -0
  71. package/dist/terminal/index.js.map +1 -1
  72. package/dist/utils/AgentRegistry.js +41 -32
  73. package/dist/utils/AgentRegistry.js.map +1 -1
  74. package/dist/utils/ClaudeSessionParser.js +46 -87
  75. package/dist/utils/ClaudeSessionParser.js.map +1 -1
  76. package/dist/utils/agents.d.ts +1 -1
  77. package/dist/utils/agents.d.ts.map +1 -1
  78. package/dist/utils/agents.js +22 -11
  79. package/dist/utils/agents.js.map +1 -1
  80. package/dist/utils/applescript.js +3 -6
  81. package/dist/utils/applescript.js.map +1 -1
  82. package/dist/utils/index.js +1 -0
  83. package/dist/utils/index.js.map +1 -1
  84. package/dist/utils/matching.js +21 -29
  85. package/dist/utils/matching.js.map +1 -1
  86. package/dist/utils/process.js +77 -56
  87. package/dist/utils/process.js.map +1 -1
  88. package/dist/utils/session.js +20 -34
  89. package/dist/utils/session.js.map +1 -1
  90. package/dist/utils/sortAgents.js +6 -8
  91. package/dist/utils/sortAgents.js.map +1 -1
  92. package/package.json +11 -7
  93. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +2 -0
  94. package/src/__tests__/adapters/CodexAdapter.test.ts +145 -0
  95. package/src/__tests__/adapters/CopilotAdapter.test.ts +411 -0
  96. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +74 -1
  97. package/src/__tests__/adapters/PiAdapter.test.ts +435 -0
  98. package/src/adapters/AgentAdapter.ts +1 -1
  99. package/src/adapters/CodexAdapter.ts +164 -6
  100. package/src/adapters/CopilotAdapter.ts +453 -0
  101. package/src/adapters/GeminiCliAdapter.ts +42 -3
  102. package/src/adapters/PiAdapter.ts +597 -0
  103. package/src/adapters/index.ts +2 -0
  104. package/src/index.ts +2 -0
  105. package/src/utils/agents.ts +1 -1
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Tests for utils/session.ts
3
+ */ import * as fs from 'fs';
4
+ import { batchGetSessionFileBirthtimes } from '../../utils/session.js';
5
+ vi.mock('fs', ()=>({
6
+ readdirSync: vi.fn(),
7
+ statSync: vi.fn()
8
+ }));
9
+ const mockedReaddirSync = fs.readdirSync;
10
+ const mockedStatSync = fs.statSync;
11
+ describe('batchGetSessionFileBirthtimes', ()=>{
12
+ beforeEach(()=>{
13
+ mockedReaddirSync.mockReset();
14
+ mockedStatSync.mockReset();
15
+ });
16
+ it('should parse session files correctly', ()=>{
17
+ mockedReaddirSync.mockReturnValue([
18
+ 'abc123.jsonl',
19
+ 'def456.jsonl'
20
+ ]);
21
+ mockedStatSync.mockReturnValueOnce({
22
+ birthtimeMs: 1710800324000
23
+ }).mockReturnValueOnce({
24
+ birthtimeMs: 1710800500000
25
+ });
26
+ const results = batchGetSessionFileBirthtimes([
27
+ '/home/.claude/projects/my-app'
28
+ ]);
29
+ expect(results).toHaveLength(2);
30
+ expect(results[0]).toEqual({
31
+ sessionId: 'abc123',
32
+ filePath: '/home/.claude/projects/my-app/abc123.jsonl',
33
+ projectDir: '/home/.claude/projects/my-app',
34
+ birthtimeMs: 1710800324000,
35
+ resolvedCwd: ''
36
+ });
37
+ expect(results[1].sessionId).toBe('def456');
38
+ expect(results[1].birthtimeMs).toBe(1710800500000);
39
+ });
40
+ it('should return empty array for empty dirs list', ()=>{
41
+ expect(batchGetSessionFileBirthtimes([])).toEqual([]);
42
+ expect(mockedReaddirSync).not.toHaveBeenCalled();
43
+ });
44
+ it('should return empty array on readdir failure', ()=>{
45
+ mockedReaddirSync.mockImplementation(()=>{
46
+ throw new Error('ENOENT');
47
+ });
48
+ expect(batchGetSessionFileBirthtimes([
49
+ '/some/dir'
50
+ ])).toEqual([]);
51
+ });
52
+ it('should skip files with invalid birthtime (0 or negative)', ()=>{
53
+ mockedReaddirSync.mockReturnValue([
54
+ 'bad.jsonl',
55
+ 'negative.jsonl',
56
+ 'good.jsonl'
57
+ ]);
58
+ mockedStatSync.mockReturnValueOnce({
59
+ birthtimeMs: 0
60
+ }).mockReturnValueOnce({
61
+ birthtimeMs: -1
62
+ }).mockReturnValueOnce({
63
+ birthtimeMs: 1710800324000
64
+ });
65
+ const results = batchGetSessionFileBirthtimes([
66
+ '/dir'
67
+ ]);
68
+ expect(results).toHaveLength(1);
69
+ expect(results[0].sessionId).toBe('good');
70
+ });
71
+ it('should skip non-jsonl files', ()=>{
72
+ mockedReaddirSync.mockReturnValue([
73
+ 'sessions-index.json',
74
+ 'abc123.jsonl'
75
+ ]);
76
+ mockedStatSync.mockReturnValueOnce({
77
+ birthtimeMs: 1710800500000
78
+ });
79
+ const results = batchGetSessionFileBirthtimes([
80
+ '/dir'
81
+ ]);
82
+ expect(results).toHaveLength(1);
83
+ expect(results[0].sessionId).toBe('abc123');
84
+ });
85
+ it('should handle empty directory', ()=>{
86
+ mockedReaddirSync.mockReturnValue([]);
87
+ expect(batchGetSessionFileBirthtimes([
88
+ '/dir'
89
+ ])).toEqual([]);
90
+ });
91
+ it('should handle UUID session IDs', ()=>{
92
+ mockedReaddirSync.mockReturnValue([
93
+ '068e7b1f-cff5-4c94-bf69-b9acd32d765c.jsonl'
94
+ ]);
95
+ mockedStatSync.mockReturnValueOnce({
96
+ birthtimeMs: 1710800324000
97
+ });
98
+ const results = batchGetSessionFileBirthtimes([
99
+ '/dir'
100
+ ]);
101
+ expect(results).toHaveLength(1);
102
+ expect(results[0].sessionId).toBe('068e7b1f-cff5-4c94-bf69-b9acd32d765c');
103
+ });
104
+ it('should leave resolvedCwd empty', ()=>{
105
+ mockedReaddirSync.mockReturnValue([
106
+ 'abc.jsonl'
107
+ ]);
108
+ mockedStatSync.mockReturnValueOnce({
109
+ birthtimeMs: 1710800324000
110
+ });
111
+ const results = batchGetSessionFileBirthtimes([
112
+ '/dir'
113
+ ]);
114
+ expect(results[0].resolvedCwd).toBe('');
115
+ });
116
+ it('should enumerate multiple directories', ()=>{
117
+ mockedReaddirSync.mockReturnValueOnce([
118
+ 'sess1.jsonl',
119
+ 'sess3.jsonl'
120
+ ]).mockReturnValueOnce([
121
+ 'sess2.jsonl'
122
+ ]);
123
+ mockedStatSync.mockReturnValueOnce({
124
+ birthtimeMs: 1710800324000
125
+ }).mockReturnValueOnce({
126
+ birthtimeMs: 1710800500000
127
+ }).mockReturnValueOnce({
128
+ birthtimeMs: 1710800400000
129
+ });
130
+ const results = batchGetSessionFileBirthtimes([
131
+ '/projects/app-a',
132
+ '/projects/app-b'
133
+ ]);
134
+ expect(mockedReaddirSync).toHaveBeenCalledTimes(2);
135
+ expect(results).toHaveLength(3);
136
+ expect(results[0].projectDir).toBe('/projects/app-a');
137
+ expect(results[1].projectDir).toBe('/projects/app-a');
138
+ expect(results[2].projectDir).toBe('/projects/app-b');
139
+ });
140
+ it('should skip files where statSync fails', ()=>{
141
+ mockedReaddirSync.mockReturnValue([
142
+ 'good.jsonl',
143
+ 'gone.jsonl'
144
+ ]);
145
+ mockedStatSync.mockReturnValueOnce({
146
+ birthtimeMs: 1710800324000
147
+ }).mockImplementationOnce(()=>{
148
+ throw new Error('ENOENT');
149
+ });
150
+ const results = batchGetSessionFileBirthtimes([
151
+ '/dir'
152
+ ]);
153
+ expect(results).toHaveLength(1);
154
+ expect(results[0].sessionId).toBe('good');
155
+ });
156
+ });
157
+
158
+ //# sourceMappingURL=session.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/__tests__/utils/session.test.ts"],"sourcesContent":["/**\n * Tests for utils/session.ts\n */\n\nimport type { MockedFunction } from 'vitest';\n\nimport * as fs from 'fs';\nimport { batchGetSessionFileBirthtimes } from '../../utils/session.js';\n\nvi.mock('fs', () => ({\n readdirSync: vi.fn(),\n statSync: vi.fn(),\n}));\n\nconst mockedReaddirSync = fs.readdirSync as MockedFunction<typeof fs.readdirSync>;\nconst mockedStatSync = fs.statSync as MockedFunction<typeof fs.statSync>;\n\ndescribe('batchGetSessionFileBirthtimes', () => {\n beforeEach(() => {\n mockedReaddirSync.mockReset();\n mockedStatSync.mockReset();\n });\n\n it('should parse session files correctly', () => {\n mockedReaddirSync.mockReturnValue([\n 'abc123.jsonl',\n 'def456.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats)\n .mockReturnValueOnce({ birthtimeMs: 1710800500000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/home/.claude/projects/my-app']);\n\n expect(results).toHaveLength(2);\n expect(results[0]).toEqual({\n sessionId: 'abc123',\n filePath: '/home/.claude/projects/my-app/abc123.jsonl',\n projectDir: '/home/.claude/projects/my-app',\n birthtimeMs: 1710800324000,\n resolvedCwd: '',\n });\n expect(results[1].sessionId).toBe('def456');\n expect(results[1].birthtimeMs).toBe(1710800500000);\n });\n\n it('should return empty array for empty dirs list', () => {\n expect(batchGetSessionFileBirthtimes([])).toEqual([]);\n expect(mockedReaddirSync).not.toHaveBeenCalled();\n });\n\n it('should return empty array on readdir failure', () => {\n mockedReaddirSync.mockImplementation(() => {\n throw new Error('ENOENT');\n });\n\n expect(batchGetSessionFileBirthtimes(['/some/dir'])).toEqual([]);\n });\n\n it('should skip files with invalid birthtime (0 or negative)', () => {\n mockedReaddirSync.mockReturnValue([\n 'bad.jsonl',\n 'negative.jsonl',\n 'good.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 0 } as fs.Stats)\n .mockReturnValueOnce({ birthtimeMs: -1 } as fs.Stats)\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/dir']);\n expect(results).toHaveLength(1);\n expect(results[0].sessionId).toBe('good');\n });\n\n it('should skip non-jsonl files', () => {\n mockedReaddirSync.mockReturnValue([\n 'sessions-index.json',\n 'abc123.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800500000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/dir']);\n expect(results).toHaveLength(1);\n expect(results[0].sessionId).toBe('abc123');\n });\n\n it('should handle empty directory', () => {\n mockedReaddirSync.mockReturnValue([] as unknown as ReturnType<typeof fs.readdirSync>);\n expect(batchGetSessionFileBirthtimes(['/dir'])).toEqual([]);\n });\n\n it('should handle UUID session IDs', () => {\n mockedReaddirSync.mockReturnValue([\n '068e7b1f-cff5-4c94-bf69-b9acd32d765c.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/dir']);\n expect(results).toHaveLength(1);\n expect(results[0].sessionId).toBe('068e7b1f-cff5-4c94-bf69-b9acd32d765c');\n });\n\n it('should leave resolvedCwd empty', () => {\n mockedReaddirSync.mockReturnValue([\n 'abc.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/dir']);\n expect(results[0].resolvedCwd).toBe('');\n });\n\n it('should enumerate multiple directories', () => {\n mockedReaddirSync\n .mockReturnValueOnce([\n 'sess1.jsonl',\n 'sess3.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>)\n .mockReturnValueOnce([\n 'sess2.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats)\n .mockReturnValueOnce({ birthtimeMs: 1710800500000 } as fs.Stats)\n .mockReturnValueOnce({ birthtimeMs: 1710800400000 } as fs.Stats);\n\n const results = batchGetSessionFileBirthtimes(['/projects/app-a', '/projects/app-b']);\n\n expect(mockedReaddirSync).toHaveBeenCalledTimes(2);\n\n expect(results).toHaveLength(3);\n expect(results[0].projectDir).toBe('/projects/app-a');\n expect(results[1].projectDir).toBe('/projects/app-a');\n expect(results[2].projectDir).toBe('/projects/app-b');\n });\n\n it('should skip files where statSync fails', () => {\n mockedReaddirSync.mockReturnValue([\n 'good.jsonl',\n 'gone.jsonl',\n ] as unknown as ReturnType<typeof fs.readdirSync>);\n mockedStatSync\n .mockReturnValueOnce({ birthtimeMs: 1710800324000 } as fs.Stats)\n .mockImplementationOnce(() => { throw new Error('ENOENT'); });\n\n const results = batchGetSessionFileBirthtimes(['/dir']);\n expect(results).toHaveLength(1);\n expect(results[0].sessionId).toBe('good');\n });\n});\n"],"names":["fs","batchGetSessionFileBirthtimes","vi","mock","readdirSync","fn","statSync","mockedReaddirSync","mockedStatSync","describe","beforeEach","mockReset","it","mockReturnValue","mockReturnValueOnce","birthtimeMs","results","expect","toHaveLength","toEqual","sessionId","filePath","projectDir","resolvedCwd","toBe","not","toHaveBeenCalled","mockImplementation","Error","toHaveBeenCalledTimes","mockImplementationOnce"],"mappings":"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"}
@@ -7,7 +7,7 @@
7
7
  /**
8
8
  * Type of AI agent
9
9
  */
10
- export type AgentType = 'claude' | 'gemini_cli' | 'codex' | 'opencode' | 'other';
10
+ export type AgentType = 'claude' | 'gemini_cli' | 'codex' | 'opencode' | 'copilot' | 'pi' | 'other';
11
11
  /**
12
12
  * Current status of an agent
13
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AgentAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/AgentAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjF;;GAEG;AACH,oBAAY,WAAW;IACnB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,OAAO,YAAY;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IAEb,oBAAoB;IACpB,IAAI,EAAE,SAAS,CAAC;IAEhB,qBAAqB;IACrB,MAAM,EAAE,WAAW,CAAC;IAEpB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAEhB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IAEZ,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IAEpB,mBAAmB;IACnB,SAAS,EAAE,MAAM,CAAC;IAElB,iCAAiC;IACjC,UAAU,EAAE,IAAI,CAAC;IAEjB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IAEZ,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAEhB,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IAEZ,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IAEZ,uDAAuD;IACvD,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC3B,sCAAsC;IACtC,IAAI,EAAE,SAAS,CAAC;IAEhB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB,+EAA+E;IAC/E,UAAU,EAAE,IAAI,CAAC;IAEjB,oFAAoF;IACpF,SAAS,EAAE,IAAI,CAAC;IAEhB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IACzB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAEzB;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAErC;;;;OAIG;IACH,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC;IAE7C;;;;;OAKG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE,CAAC;IAEjG;;;;;;;;;OASG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CACvE"}
1
+ {"version":3,"file":"AgentAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/AgentAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC;AAEpG;;GAEG;AACH,oBAAY,WAAW;IACnB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,OAAO,YAAY;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IAEb,oBAAoB;IACpB,IAAI,EAAE,SAAS,CAAC;IAEhB,qBAAqB;IACrB,MAAM,EAAE,WAAW,CAAC;IAEpB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAEhB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IAEZ,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IAEpB,mBAAmB;IACnB,SAAS,EAAE,MAAM,CAAC;IAElB,iCAAiC;IACjC,UAAU,EAAE,IAAI,CAAC;IAEjB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IAEZ,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAEhB,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IAEZ,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IAEZ,uDAAuD;IACvD,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC3B,sCAAsC;IACtC,IAAI,EAAE,SAAS,CAAC;IAEhB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB,+EAA+E;IAC/E,UAAU,EAAE,IAAI,CAAC;IAEjB,oFAAoF;IACpF,SAAS,EAAE,IAAI,CAAC;IAEhB,oEAAoE;IACpE,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAChC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IACzB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAEzB;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAErC;;;;OAIG;IACH,SAAS,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC;IAE7C;;;;;OAKG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE,CAAC;IAEjG;;;;;;;;;OASG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CACvE"}
@@ -1,17 +1,18 @@
1
1
  /**
2
2
  * Agent Adapter Interface
3
- *
3
+ *
4
4
  * Defines the contract for detecting and managing different types of AI agents.
5
5
  * Each adapter is responsible for detecting agents of a specific type (e.g., claude).
6
- */
7
- /**
6
+ */ /**
7
+ * Type of AI agent
8
+ */ /**
8
9
  * Current status of an agent
9
- */
10
- export var AgentStatus;
11
- (function (AgentStatus) {
10
+ */ export var AgentStatus = /*#__PURE__*/ function(AgentStatus) {
12
11
  AgentStatus["RUNNING"] = "running";
13
12
  AgentStatus["WAITING"] = "waiting";
14
13
  AgentStatus["IDLE"] = "idle";
15
14
  AgentStatus["UNKNOWN"] = "unknown";
16
- })(AgentStatus || (AgentStatus = {}));
15
+ return AgentStatus;
16
+ }({});
17
+
17
18
  //# sourceMappingURL=AgentAdapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AgentAdapter.js","sourceRoot":"","sources":["../../src/adapters/AgentAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACnB,kCAAmB,CAAA;IACnB,kCAAmB,CAAA;IACnB,4BAAa,CAAA;IACb,kCAAmB,CAAA;AACvB,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB"}
1
+ {"version":3,"sources":["../../src/adapters/AgentAdapter.ts"],"sourcesContent":["/**\n * Agent Adapter Interface\n * \n * Defines the contract for detecting and managing different types of AI agents.\n * Each adapter is responsible for detecting agents of a specific type (e.g., claude).\n */\n\n/**\n * Type of AI agent\n */\nexport type AgentType = 'claude' | 'gemini_cli' | 'codex' | 'opencode' | 'copilot' | 'pi' | 'other';\n\n/**\n * Current status of an agent\n */\nexport enum AgentStatus {\n RUNNING = 'running',\n WAITING = 'waiting',\n IDLE = 'idle',\n UNKNOWN = 'unknown'\n}\n\n/**\n * Information about a detected agent\n */\nexport interface AgentInfo {\n /** Project-based name (e.g., \"ai-devkit\" or \"ai-devkit (merry)\") */\n name: string;\n\n /** Type of agent */\n type: AgentType;\n\n /** Current status */\n status: AgentStatus;\n\n /** Last user prompt from history */\n summary: string;\n\n /** Process ID */\n pid: number;\n\n /** Working directory/project path */\n projectPath: string;\n\n /** Session UUID */\n sessionId: string;\n\n /** Timestamp of last activity */\n lastActive: Date;\n\n /** Path to the session JSONL file on disk */\n sessionFilePath?: string;\n}\n\n/**\n * Information about a running process\n */\nexport interface ProcessInfo {\n /** Process ID */\n pid: number;\n\n /** Process command */\n command: string;\n\n /** Working directory */\n cwd: string;\n\n /** Terminal TTY (e.g., \"ttys030\") */\n tty: string;\n\n /** Process start time, populated by enrichProcesses */\n startTime?: Date;\n}\n\n/**\n * A single message in a conversation\n */\nexport interface ConversationMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp?: string;\n}\n\n/**\n * A historical session discovered on disk (running or not).\n *\n * Used by `listSessions` to surface enough context for a user to identify\n * a session and resume it via the originating tool's resume command.\n */\nexport interface SessionSummary {\n /** Tool that produced this session */\n type: AgentType;\n\n /**\n * ID accepted by the tool's resume command. Adapters MUST pass this\n * through verbatim — no normalization, no encoding/decoding — so it\n * round-trips into `claude --resume <id>` (and equivalents).\n */\n sessionId: string;\n\n /** Working directory the session was started in (best-known value) */\n cwd: string;\n\n /**\n * Trimmed first user message; empty string if none. Adapters apply\n * the same noise-filter their existing parsers use (skip tool_result\n * blocks, request-interruption notices, system-injected skill\n * content). The CLI table renderer substitutes a placeholder for\n * empty values; JSON output keeps the empty string raw.\n */\n firstUserMessage: string;\n\n /** Last activity timestamp (from session content; falls back to file mtime) */\n lastActive: Date;\n\n /** Session start time (from session content; falls back to file birthtime/mtime) */\n startedAt: Date;\n\n /** Absolute path to the session file on disk (debug/diagnostics) */\n sessionFilePath: string;\n}\n\n/**\n * Filters passed by the CLI to {@link AgentAdapter.listSessions}.\n *\n * The CLI is the source of truth for filter defaults and semantics\n * (e.g. cwd defaults to process.cwd(); --all clears it). Adapters apply\n * the values they receive — they don't invent defaults.\n */\nexport interface ListSessionsOptions {\n /**\n * Filter to sessions whose recorded cwd matches this path using strict\n * equality (no prefix/ancestor matching in v1). Undefined = no cwd\n * filter.\n */\n cwd?: string;\n\n /**\n * Filter to a single tool. Enforced by `AgentManager.listSessions`,\n * which skips adapters whose `type` doesn't match. Adapters MAY\n * ignore this field — by the time their `listSessions` runs, the\n * type filter is already satisfied. Undefined = include every\n * registered adapter.\n */\n type?: AgentType;\n}\n\n/**\n * Agent Adapter Interface\n *\n * Implementations must provide detection logic for a specific agent type.\n */\nexport interface AgentAdapter {\n /** Type of agent this adapter handles */\n readonly type: AgentType;\n\n /**\n * Detect running agents of this type\n * @returns List of detected agents\n */\n detectAgents(): Promise<AgentInfo[]>;\n\n /**\n * Check if this adapter can handle the given process\n * @param processInfo Process information\n * @returns True if this adapter can handle the process\n */\n canHandle(processInfo: ProcessInfo): boolean;\n\n /**\n * Read the full conversation from a session file\n * @param sessionFilePath Path to the session JSONL file\n * @param options.verbose Include tool call/result details\n * @returns Array of conversation messages\n */\n getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[];\n\n /**\n * Enumerate historical sessions for this tool from disk.\n *\n * Applies `opts.cwd` as a strict-equality filter when set. Returns\n * {@link SessionSummary} entries unsorted; sorting and global filters\n * are handled by `AgentManager` and the CLI.\n *\n * @param opts Filter options computed by the CLI\n * @returns Array of sessions discovered on disk\n */\n listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]>;\n}\n"],"names":["AgentStatus"],"mappings":"AAAA;;;;;CAKC,GAED;;CAEC,GAGD;;CAEC,GACD,OAAO,IAAA,AAAKA,qCAAAA;;;;;WAAAA;MAKX"}
@@ -5,8 +5,7 @@ import { listAgentProcesses, enrichProcesses } from '../utils/process.js';
5
5
  import { batchGetSessionFileBirthtimes, isDirectory, listJsonl, safeReaddir, safeStat } from '../utils/session.js';
6
6
  import { matchProcessesToSessions, generateAgentName } from '../utils/matching.js';
7
7
  import { ClaudeSessionParser } from '../utils/ClaudeSessionParser.js';
8
- /** Maximum allowed delta (ms) between process start time and PID file startedAt. */
9
- const PID_FILE_STALENESS_MS = 60000;
8
+ /** Maximum allowed delta (ms) between process start time and PID file startedAt. */ const PID_FILE_STALENESS_MS = 60000;
10
9
  /**
11
10
  * Claude Code Adapter
12
11
  *
@@ -16,13 +15,12 @@ const PID_FILE_STALENESS_MS = 60000;
16
15
  * 3. Attempting authoritative PID-file matching via ~/.claude/sessions/<pid>.json
17
16
  * 4. Falling back to CWD+birthtime heuristic (matchProcessesToSessions) for processes without a PID file
18
17
  * 5. Extracting summary from last user message in session JSONL
19
- */
20
- export class ClaudeCodeAdapter {
18
+ */ export class ClaudeCodeAdapter {
21
19
  type = 'claude';
22
20
  projectsDir;
23
21
  sessionsDir;
24
22
  parser;
25
- constructor() {
23
+ constructor(){
26
24
  const homeDir = process.env.HOME || process.env.USERPROFILE || '';
27
25
  this.projectsDir = path.join(homeDir, '.claude', 'projects');
28
26
  this.sessionsDir = path.join(homeDir, '.claude', 'sessions');
@@ -47,43 +45,42 @@ export class ClaudeCodeAdapter {
47
45
  const { direct: resumeDirect, fallback: noResume } = this.tryResumeMatching(processes);
48
46
  // Step 2: try authoritative PID-file matching for the rest
49
47
  const { direct: pidDirect, fallback } = this.tryPidFileMatching(noResume);
50
- const direct = [...resumeDirect, ...pidDirect];
48
+ const direct = [
49
+ ...resumeDirect,
50
+ ...pidDirect
51
+ ];
51
52
  // Step 3: run legacy CWD+birthtime matching only for processes without a PID file
52
53
  const legacySessions = this.discoverSessions(fallback);
53
- const legacyMatches = fallback.length > 0 && legacySessions.length > 0
54
- ? matchProcessesToSessions(fallback, legacySessions)
55
- : [];
54
+ const legacyMatches = fallback.length > 0 && legacySessions.length > 0 ? matchProcessesToSessions(fallback, legacySessions) : [];
56
55
  const matchedPids = new Set([
57
- ...direct.map((d) => d.process.pid),
58
- ...legacyMatches.map((m) => m.process.pid),
56
+ ...direct.map((d)=>d.process.pid),
57
+ ...legacyMatches.map((m)=>m.process.pid)
59
58
  ]);
60
59
  const agents = [];
61
60
  // Build agents from direct (resume + PID-file) matches
62
- for (const match of direct) {
61
+ for (const match of direct){
63
62
  const { process: proc, sessionFile } = match;
64
63
  const sessionData = this.parser.readSession(sessionFile.filePath, sessionFile.resolvedCwd);
65
64
  if (sessionData) {
66
65
  agents.push(this.mapSessionToAgent(sessionData, proc, sessionFile, {
67
66
  pidStatus: match.pidStatus,
68
- waitingFor: match.waitingFor,
67
+ waitingFor: match.waitingFor
69
68
  }));
70
- }
71
- else {
69
+ } else {
72
70
  matchedPids.delete(proc.pid);
73
71
  }
74
72
  }
75
73
  // Build agents from legacy matches
76
- for (const match of legacyMatches) {
74
+ for (const match of legacyMatches){
77
75
  const sessionData = this.parser.readSession(match.session.filePath, match.session.resolvedCwd);
78
76
  if (sessionData) {
79
77
  agents.push(this.mapSessionToAgent(sessionData, match.process, match.session));
80
- }
81
- else {
78
+ } else {
82
79
  matchedPids.delete(match.process.pid);
83
80
  }
84
81
  }
85
82
  // Any process with no match (direct or legacy) appears as IDLE
86
- for (const proc of processes) {
83
+ for (const proc of processes){
87
84
  if (!matchedPids.has(proc.pid)) {
88
85
  agents.push(this.mapProcessOnlyAgent(proc));
89
86
  }
@@ -96,28 +93,24 @@ export class ClaudeCodeAdapter {
96
93
  * For each unique process CWD, encodes it to derive the expected
97
94
  * ~/.claude/projects/<encoded>/ directory, then gets session file birthtimes
98
95
  * via a single batched stat call across all directories.
99
- */
100
- discoverSessions(processes) {
96
+ */ discoverSessions(processes) {
101
97
  const dirToCwd = new Map();
102
- for (const proc of processes) {
103
- if (!proc.cwd)
104
- continue;
98
+ for (const proc of processes){
99
+ if (!proc.cwd) continue;
105
100
  const projectDir = this.getProjectDir(proc.cwd);
106
- if (dirToCwd.has(projectDir))
107
- continue;
101
+ if (dirToCwd.has(projectDir)) continue;
108
102
  try {
109
- if (!fs.statSync(projectDir).isDirectory())
110
- continue;
111
- }
112
- catch {
103
+ if (!fs.statSync(projectDir).isDirectory()) continue;
104
+ } catch {
113
105
  continue;
114
106
  }
115
107
  dirToCwd.set(projectDir, proc.cwd);
116
108
  }
117
- if (dirToCwd.size === 0)
118
- return [];
119
- const files = batchGetSessionFileBirthtimes([...dirToCwd.keys()]);
120
- for (const file of files) {
109
+ if (dirToCwd.size === 0) return [];
110
+ const files = batchGetSessionFileBirthtimes([
111
+ ...dirToCwd.keys()
112
+ ]);
113
+ for (const file of files){
121
114
  file.resolvedCwd = dirToCwd.get(file.projectDir) || '';
122
115
  }
123
116
  return files;
@@ -127,11 +120,10 @@ export class ClaudeCodeAdapter {
127
120
  * This works for resumed sessions, where the JSONL was created earlier
128
121
  * (so its birthtime is far from the process startTime and the legacy
129
122
  * matcher can't pair them) and the PID file may also be misaligned.
130
- */
131
- tryResumeMatching(processes) {
123
+ */ tryResumeMatching(processes) {
132
124
  const direct = [];
133
125
  const fallback = [];
134
- for (const proc of processes) {
126
+ for (const proc of processes){
135
127
  const sessionId = this.extractResumeSessionId(proc.command);
136
128
  if (!sessionId || !proc.cwd) {
137
129
  fallback.push(proc);
@@ -156,13 +148,16 @@ export class ClaudeCodeAdapter {
156
148
  filePath: jsonlPath,
157
149
  projectDir,
158
150
  birthtimeMs: stat.birthtimeMs,
159
- resolvedCwd: proc.cwd,
151
+ resolvedCwd: proc.cwd
160
152
  },
161
153
  pidStatus: this.mapPidStatus(pidEntry?.status),
162
- waitingFor: pidEntry?.waitingFor,
154
+ waitingFor: pidEntry?.waitingFor
163
155
  });
164
156
  }
165
- return { direct, fallback };
157
+ return {
158
+ direct,
159
+ fallback
160
+ };
166
161
  }
167
162
  extractResumeSessionId(command) {
168
163
  const match = command.match(/--resume\s+([0-9a-f-]{36})/i);
@@ -176,8 +171,7 @@ export class ClaudeCodeAdapter {
176
171
  * "Stale" means the PID file's startedAt diverges from the process's
177
172
  * start time by more than {@link PID_FILE_STALENESS_MS} — typically
178
173
  * a previous Claude Code process recycled the same PID without cleanup.
179
- */
180
- readMatchingPidFile(pid, procStartTime) {
174
+ */ readMatchingPidFile(pid, procStartTime) {
181
175
  const pidFilePath = path.join(this.sessionsDir, `${pid}.json`);
182
176
  try {
183
177
  const entry = JSON.parse(fs.readFileSync(pidFilePath, 'utf-8'));
@@ -188,8 +182,7 @@ export class ClaudeCodeAdapter {
188
182
  }
189
183
  }
190
184
  return entry;
191
- }
192
- catch {
185
+ } catch {
193
186
  return null;
194
187
  }
195
188
  }
@@ -198,9 +191,8 @@ export class ClaudeCodeAdapter {
198
191
  *
199
192
  * Returns undefined for missing / unrecognized values so the caller
200
193
  * can fall back to JSONL-derived heuristics.
201
- */
202
- mapPidStatus(status) {
203
- switch (status) {
194
+ */ mapPidStatus(status) {
195
+ switch(status){
204
196
  case 'running':
205
197
  return AgentStatus.RUNNING;
206
198
  case 'waiting':
@@ -220,11 +212,10 @@ export class ClaudeCodeAdapter {
220
212
  *
221
213
  * Per-process fallback triggers on: file absent, malformed JSON,
222
214
  * stale startedAt (>60s from proc.startTime), or missing JSONL.
223
- */
224
- tryPidFileMatching(processes) {
215
+ */ tryPidFileMatching(processes) {
225
216
  const direct = [];
226
217
  const fallback = [];
227
- for (const proc of processes) {
218
+ for (const proc of processes){
228
219
  const entry = this.readMatchingPidFile(proc.pid, proc.startTime);
229
220
  if (!entry) {
230
221
  fallback.push(proc);
@@ -243,13 +234,16 @@ export class ClaudeCodeAdapter {
243
234
  filePath: jsonlPath,
244
235
  projectDir,
245
236
  birthtimeMs: entry.startedAt,
246
- resolvedCwd: entry.cwd,
237
+ resolvedCwd: entry.cwd
247
238
  },
248
239
  pidStatus: this.mapPidStatus(entry.status),
249
- waitingFor: entry.waitingFor,
240
+ waitingFor: entry.waitingFor
250
241
  });
251
242
  }
252
- return { direct, fallback };
243
+ return {
244
+ direct,
245
+ fallback
246
+ };
253
247
  }
254
248
  /**
255
249
  * Derive the Claude Code project directory for a given CWD.
@@ -263,8 +257,7 @@ export class ClaudeCodeAdapter {
263
257
  * The encoding is lossy — multiple real paths can collide on the
264
258
  * same encoded dir. Callers that need to disambiguate must read the
265
259
  * `cwd` field inside each session JSONL.
266
- */
267
- getProjectDir(cwd) {
260
+ */ getProjectDir(cwd) {
268
261
  const encoded = cwd.replace(/[^a-zA-Z0-9]/g, '-');
269
262
  return path.join(this.projectsDir, encoded);
270
263
  }
@@ -274,9 +267,7 @@ export class ClaudeCodeAdapter {
274
267
  // event like `permission-mode` or `ai-title`.
275
268
  const status = liveInfo?.pidStatus ?? this.parser.determineStatus(session);
276
269
  const baseSummary = session.lastUserMessage || 'Session started';
277
- const summary = status === AgentStatus.WAITING && liveInfo?.waitingFor
278
- ? `${baseSummary} — waiting for ${liveInfo.waitingFor}`
279
- : baseSummary;
270
+ const summary = status === AgentStatus.WAITING && liveInfo?.waitingFor ? `${baseSummary} — waiting for ${liveInfo.waitingFor}` : baseSummary;
280
271
  return {
281
272
  name: generateAgentName(processInfo.cwd, processInfo.pid),
282
273
  type: this.type,
@@ -286,7 +277,7 @@ export class ClaudeCodeAdapter {
286
277
  projectPath: sessionFile.resolvedCwd || processInfo.cwd || '',
287
278
  sessionId: sessionFile.sessionId,
288
279
  lastActive: session.lastActive,
289
- sessionFilePath: sessionFile.filePath,
280
+ sessionFilePath: sessionFile.filePath
290
281
  };
291
282
  }
292
283
  mapProcessOnlyAgent(processInfo) {
@@ -298,7 +289,7 @@ export class ClaudeCodeAdapter {
298
289
  pid: processInfo.pid,
299
290
  projectPath: processInfo.cwd || '',
300
291
  sessionId: `pid-${processInfo.pid}`,
301
- lastActive: new Date(),
292
+ lastActive: new Date()
302
293
  };
303
294
  }
304
295
  getConversation(sessionFilePath, options) {
@@ -308,19 +299,16 @@ export class ClaudeCodeAdapter {
308
299
  const filterCwd = opts?.cwd;
309
300
  const candidates = this.discoverSessionFiles();
310
301
  const summaries = [];
311
- for (const { filePath, defaultCwd } of candidates) {
302
+ for (const { filePath, defaultCwd } of candidates){
312
303
  const session = this.parser.readSession(filePath, defaultCwd);
313
- if (!session)
314
- continue;
304
+ if (!session) continue;
315
305
  // Drop sessions whose JSONL had no parseable conversation entries.
316
306
  // readSession is permissive (returns a shell record even when every
317
307
  // line fails to parse); listSessions needs at least one real entry
318
308
  // so we don't surface garbage files.
319
- if (!session.lastEntryType)
320
- continue;
309
+ if (!session.lastEntryType) continue;
321
310
  const recordedCwd = session.lastCwd || defaultCwd;
322
- if (filterCwd !== undefined && recordedCwd !== filterCwd)
323
- continue;
311
+ if (filterCwd !== undefined && recordedCwd !== filterCwd) continue;
324
312
  const stat = safeStat(filePath);
325
313
  summaries.push({
326
314
  type: 'claude',
@@ -329,7 +317,7 @@ export class ClaudeCodeAdapter {
329
317
  firstUserMessage: session.firstUserMessage || '',
330
318
  lastActive: session.lastActive ?? stat?.mtime ?? new Date(),
331
319
  startedAt: session.sessionStart ?? stat?.birthtime ?? stat?.mtime ?? new Date(),
332
- sessionFilePath: filePath,
320
+ sessionFilePath: filePath
333
321
  });
334
322
  }
335
323
  return summaries;
@@ -344,25 +332,26 @@ export class ClaudeCodeAdapter {
344
332
  * worktrees and similar setups. The cwd filter is applied later
345
333
  * against `session.lastCwd` so callers see exactly the sessions whose
346
334
  * recorded cwd matches.
347
- */
348
- discoverSessionFiles() {
335
+ */ discoverSessionFiles() {
349
336
  const out = [];
350
- if (!isDirectory(this.projectsDir))
351
- return out;
352
- for (const dirName of safeReaddir(this.projectsDir)) {
337
+ if (!isDirectory(this.projectsDir)) return out;
338
+ for (const dirName of safeReaddir(this.projectsDir)){
353
339
  const projectDir = path.join(this.projectsDir, dirName);
354
- if (!isDirectory(projectDir))
355
- continue;
340
+ if (!isDirectory(projectDir)) continue;
356
341
  // Best-effort decode for the rare case session content has no
357
342
  // recorded cwd: '-Users-foo-bar' → '/Users/foo/bar'. Lossy for
358
343
  // paths containing '-'; session content's lastCwd overrides
359
344
  // this when available.
360
345
  const decoded = dirName.replace(/-/g, '/');
361
- for (const name of listJsonl(projectDir)) {
362
- out.push({ filePath: path.join(projectDir, name), defaultCwd: decoded });
346
+ for (const name of listJsonl(projectDir)){
347
+ out.push({
348
+ filePath: path.join(projectDir, name),
349
+ defaultCwd: decoded
350
+ });
363
351
  }
364
352
  }
365
353
  return out;
366
354
  }
367
355
  }
356
+
368
357
  //# sourceMappingURL=ClaudeCodeAdapter.js.map