@ai-devkit/agent-manager 0.34.0 → 0.36.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 (211) hide show
  1. package/dist/AgentManager.d.ts +2 -0
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +25 -0
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +74 -0
  6. package/dist/__tests__/AgentManager.test.js.map +1 -1
  7. package/dist/__tests__/adapters/AntigravityCliAdapter.test.js +381 -0
  8. package/dist/__tests__/adapters/AntigravityCliAdapter.test.js.map +1 -0
  9. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +28 -0
  10. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
  11. package/dist/__tests__/adapters/CodexAdapter.test.js +7 -0
  12. package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
  13. package/dist/__tests__/adapters/KiroAdapter.test.js +607 -0
  14. package/dist/__tests__/adapters/KiroAdapter.test.js.map +1 -0
  15. package/dist/__tests__/capacity/claude.test.js +485 -0
  16. package/dist/__tests__/capacity/claude.test.js.map +1 -0
  17. package/dist/__tests__/capacity/openai.test.js +672 -0
  18. package/dist/__tests__/capacity/openai.test.js.map +1 -0
  19. package/dist/__tests__/capacity/wham.test.js +144 -0
  20. package/dist/__tests__/capacity/wham.test.js.map +1 -0
  21. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js +18 -0
  22. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +1 -1
  23. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js +36 -0
  24. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +1 -1
  25. package/dist/__tests__/providers/grok/GrokAgentMapper.test.js +56 -0
  26. package/dist/__tests__/providers/grok/GrokAgentMapper.test.js.map +1 -0
  27. package/dist/__tests__/{adapters → providers/grok}/GrokCliAdapter.test.js +19 -6
  28. package/dist/__tests__/providers/grok/GrokCliAdapter.test.js.map +1 -0
  29. package/dist/__tests__/providers/grok/GrokSessionLocator.test.js +133 -0
  30. package/dist/__tests__/providers/grok/GrokSessionLocator.test.js.map +1 -0
  31. package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js +24 -0
  32. package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js.map +1 -1
  33. package/dist/__tests__/providers/pi/PiAdapter.test.js +30 -0
  34. package/dist/__tests__/providers/pi/PiAdapter.test.js.map +1 -1
  35. package/dist/__tests__/utils/agents.test.js +6 -0
  36. package/dist/__tests__/utils/agents.test.js.map +1 -1
  37. package/dist/__tests__/utils/session.test.js +18 -1
  38. package/dist/__tests__/utils/session.test.js.map +1 -1
  39. package/dist/adapters/AgentAdapter.d.ts +9 -1
  40. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  41. package/dist/adapters/AgentAdapter.js.map +1 -1
  42. package/dist/adapters/AntigravityCliAdapter.d.ts +57 -0
  43. package/dist/adapters/AntigravityCliAdapter.d.ts.map +1 -0
  44. package/dist/adapters/AntigravityCliAdapter.js +273 -0
  45. package/dist/adapters/AntigravityCliAdapter.js.map +1 -0
  46. package/dist/adapters/KiroAdapter.d.ts +46 -0
  47. package/dist/adapters/KiroAdapter.d.ts.map +1 -0
  48. package/dist/adapters/KiroAdapter.js +344 -0
  49. package/dist/adapters/KiroAdapter.js.map +1 -0
  50. package/dist/adapters/index.d.ts +3 -1
  51. package/dist/adapters/index.d.ts.map +1 -1
  52. package/dist/adapters/index.js +3 -1
  53. package/dist/adapters/index.js.map +1 -1
  54. package/dist/capacity/claude.d.ts +17 -0
  55. package/dist/capacity/claude.d.ts.map +1 -0
  56. package/dist/capacity/claude.js +271 -0
  57. package/dist/capacity/claude.js.map +1 -0
  58. package/dist/capacity/codex.d.ts +1 -2
  59. package/dist/capacity/codex.d.ts.map +1 -1
  60. package/dist/capacity/codex.js +5 -47
  61. package/dist/capacity/codex.js.map +1 -1
  62. package/dist/capacity/index.d.ts +11 -0
  63. package/dist/capacity/index.d.ts.map +1 -1
  64. package/dist/capacity/index.js +17 -0
  65. package/dist/capacity/index.js.map +1 -1
  66. package/dist/capacity/openai.d.ts +48 -0
  67. package/dist/capacity/openai.d.ts.map +1 -0
  68. package/dist/capacity/openai.js +312 -0
  69. package/dist/capacity/openai.js.map +1 -0
  70. package/dist/capacity/wham.d.ts +16 -0
  71. package/dist/capacity/wham.d.ts.map +1 -0
  72. package/dist/capacity/wham.js +66 -0
  73. package/dist/capacity/wham.js.map +1 -0
  74. package/dist/index.d.ts +5 -3
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +4 -2
  77. package/dist/index.js.map +1 -1
  78. package/dist/providers/claude/ClaudeCodeAdapter.d.ts +2 -0
  79. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
  80. package/dist/providers/claude/ClaudeCodeAdapter.js +22 -19
  81. package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
  82. package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -0
  83. package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
  84. package/dist/providers/claude/ClaudeSessionLocator.js +18 -1
  85. package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
  86. package/dist/providers/codex/CodexAdapter.d.ts +1 -0
  87. package/dist/providers/codex/CodexAdapter.d.ts.map +1 -1
  88. package/dist/providers/codex/CodexAdapter.js +8 -0
  89. package/dist/providers/codex/CodexAdapter.js.map +1 -1
  90. package/dist/providers/copilot/CopilotAdapter.d.ts +2 -0
  91. package/dist/providers/copilot/CopilotAdapter.d.ts.map +1 -1
  92. package/dist/providers/copilot/CopilotAdapter.js +24 -9
  93. package/dist/providers/copilot/CopilotAdapter.js.map +1 -1
  94. package/dist/providers/copilot/CopilotSessionLocator.d.ts +1 -0
  95. package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +1 -1
  96. package/dist/providers/copilot/CopilotSessionLocator.js +9 -1
  97. package/dist/providers/copilot/CopilotSessionLocator.js.map +1 -1
  98. package/dist/providers/gemini/GeminiCliAdapter.d.ts +1 -0
  99. package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +1 -1
  100. package/dist/providers/gemini/GeminiCliAdapter.js +9 -0
  101. package/dist/providers/gemini/GeminiCliAdapter.js.map +1 -1
  102. package/dist/providers/grok/GrokAgentMapper.d.ts +14 -0
  103. package/dist/providers/grok/GrokAgentMapper.d.ts.map +1 -0
  104. package/dist/providers/grok/GrokAgentMapper.js +36 -0
  105. package/dist/providers/grok/GrokAgentMapper.js.map +1 -0
  106. package/dist/providers/grok/GrokCliAdapter.d.ts +36 -0
  107. package/dist/providers/grok/GrokCliAdapter.d.ts.map +1 -0
  108. package/dist/providers/grok/GrokCliAdapter.js +98 -0
  109. package/dist/providers/grok/GrokCliAdapter.js.map +1 -0
  110. package/dist/providers/grok/GrokSessionLocator.d.ts +62 -0
  111. package/dist/providers/grok/GrokSessionLocator.d.ts.map +1 -0
  112. package/dist/providers/grok/GrokSessionLocator.js +140 -0
  113. package/dist/providers/grok/GrokSessionLocator.js.map +1 -0
  114. package/dist/providers/grok/GrokSessionParser.d.ts +54 -0
  115. package/dist/providers/grok/GrokSessionParser.d.ts.map +1 -0
  116. package/dist/providers/grok/GrokSessionParser.js +122 -0
  117. package/dist/providers/grok/GrokSessionParser.js.map +1 -0
  118. package/dist/providers/opencode/OpenCodeAdapter.d.ts +1 -0
  119. package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +1 -1
  120. package/dist/providers/opencode/OpenCodeAdapter.js +3 -0
  121. package/dist/providers/opencode/OpenCodeAdapter.js.map +1 -1
  122. package/dist/providers/opencode/OpenCodeSessionLocator.d.ts +2 -0
  123. package/dist/providers/opencode/OpenCodeSessionLocator.d.ts.map +1 -1
  124. package/dist/providers/opencode/OpenCodeSessionLocator.js +31 -12
  125. package/dist/providers/opencode/OpenCodeSessionLocator.js.map +1 -1
  126. package/dist/providers/pi/PiAdapter.d.ts +1 -0
  127. package/dist/providers/pi/PiAdapter.d.ts.map +1 -1
  128. package/dist/providers/pi/PiAdapter.js +10 -0
  129. package/dist/providers/pi/PiAdapter.js.map +1 -1
  130. package/dist/providers/pi/PiSessionLocator.d.ts +1 -0
  131. package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -1
  132. package/dist/providers/pi/PiSessionLocator.js +8 -1
  133. package/dist/providers/pi/PiSessionLocator.js.map +1 -1
  134. package/dist/readiness/AgentReadiness.d.ts +1 -1
  135. package/dist/readiness/AgentReadiness.d.ts.map +1 -1
  136. package/dist/readiness/AgentReadiness.js.map +1 -1
  137. package/dist/runtime/ManagedAgentRuntime.js +3 -1
  138. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  139. package/dist/runtime/herdr/HerdrAgentDiscovery.js +10 -0
  140. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  141. package/dist/utils/agents.d.ts +1 -1
  142. package/dist/utils/agents.d.ts.map +1 -1
  143. package/dist/utils/agents.js +11 -0
  144. package/dist/utils/agents.js.map +1 -1
  145. package/dist/utils/session.d.ts +2 -0
  146. package/dist/utils/session.d.ts.map +1 -1
  147. package/dist/utils/session.js +3 -0
  148. package/dist/utils/session.js.map +1 -1
  149. package/package.json +1 -1
  150. package/src/AgentManager.ts +34 -0
  151. package/src/__tests__/AgentManager.test.ts +60 -0
  152. package/src/__tests__/adapters/AntigravityCliAdapter.test.ts +324 -0
  153. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +23 -0
  154. package/src/__tests__/adapters/CodexAdapter.test.ts +7 -0
  155. package/src/__tests__/adapters/KiroAdapter.test.ts +534 -0
  156. package/src/__tests__/capacity/claude.test.ts +467 -0
  157. package/src/__tests__/capacity/fixtures/claude-credentials.json +7 -0
  158. package/src/__tests__/capacity/fixtures/claude-usage-malformed.json +1 -0
  159. package/src/__tests__/capacity/fixtures/claude-usage-partial.json +15 -0
  160. package/src/__tests__/capacity/fixtures/claude-usage.json +63 -0
  161. package/src/__tests__/capacity/fixtures/openai-auth.json +6 -0
  162. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +9 -0
  163. package/src/__tests__/capacity/fixtures/openai-usage-completions.json +67 -0
  164. package/src/__tests__/capacity/fixtures/openai-usage-responses.json +20 -0
  165. package/src/__tests__/capacity/fixtures/wham-usage.json +32 -0
  166. package/src/__tests__/capacity/openai.test.ts +570 -0
  167. package/src/__tests__/capacity/wham.test.ts +104 -0
  168. package/src/__tests__/providers/copilot/CopilotAdapter.test.ts +12 -0
  169. package/src/__tests__/providers/gemini/GeminiCliAdapter.test.ts +21 -0
  170. package/src/__tests__/providers/grok/GrokAgentMapper.test.ts +57 -0
  171. package/src/__tests__/{adapters → providers/grok}/GrokCliAdapter.test.ts +18 -9
  172. package/src/__tests__/providers/grok/GrokSessionLocator.test.ts +106 -0
  173. package/src/__tests__/providers/opencode/OpenCodeAdapter.test.ts +18 -0
  174. package/src/__tests__/providers/pi/PiAdapter.test.ts +15 -0
  175. package/src/__tests__/utils/agents.test.ts +7 -0
  176. package/src/__tests__/utils/session.test.ts +11 -1
  177. package/src/adapters/AgentAdapter.ts +11 -0
  178. package/src/adapters/AntigravityCliAdapter.ts +356 -0
  179. package/src/adapters/KiroAdapter.ts +456 -0
  180. package/src/adapters/index.ts +3 -1
  181. package/src/capacity/claude.ts +313 -0
  182. package/src/capacity/codex.ts +25 -134
  183. package/src/capacity/index.ts +33 -4
  184. package/src/capacity/openai.ts +361 -0
  185. package/src/capacity/wham.ts +84 -0
  186. package/src/index.ts +11 -2
  187. package/src/providers/claude/ClaudeCodeAdapter.ts +28 -23
  188. package/src/providers/claude/ClaudeSessionLocator.ts +20 -0
  189. package/src/providers/codex/CodexAdapter.ts +8 -0
  190. package/src/providers/copilot/CopilotAdapter.ts +26 -10
  191. package/src/providers/copilot/CopilotSessionLocator.ts +7 -1
  192. package/src/providers/gemini/GeminiCliAdapter.ts +8 -0
  193. package/src/providers/grok/GrokAgentMapper.ts +41 -0
  194. package/src/providers/grok/GrokCliAdapter.ts +125 -0
  195. package/src/providers/grok/GrokSessionLocator.ts +179 -0
  196. package/src/providers/grok/GrokSessionParser.ts +166 -0
  197. package/src/providers/opencode/OpenCodeAdapter.ts +4 -0
  198. package/src/providers/opencode/OpenCodeSessionLocator.ts +43 -15
  199. package/src/providers/pi/PiAdapter.ts +12 -0
  200. package/src/providers/pi/PiSessionLocator.ts +16 -1
  201. package/src/readiness/AgentReadiness.ts +4 -1
  202. package/src/runtime/ManagedAgentRuntime.ts +2 -0
  203. package/src/runtime/herdr/HerdrAgentDiscovery.ts +5 -1
  204. package/src/utils/agents.ts +11 -1
  205. package/src/utils/session.ts +11 -0
  206. package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +0 -1
  207. package/dist/adapters/GrokCliAdapter.d.ts +0 -80
  208. package/dist/adapters/GrokCliAdapter.d.ts.map +0 -1
  209. package/dist/adapters/GrokCliAdapter.js +0 -310
  210. package/dist/adapters/GrokCliAdapter.js.map +0 -1
  211. package/src/adapters/GrokCliAdapter.ts +0 -408
@@ -0,0 +1,381 @@
1
+ /**
2
+ * Tests for AntigravityCliAdapter
3
+ *
4
+ * The adapter resolves a live `agy` process to its conversation via
5
+ * ~/.gemini/antigravity-cli/cache/last_conversations.json (cwd -> conversationId)
6
+ * and reads session details from brain/<id>/.system_generated/logs/transcript.jsonl.
7
+ */ import * as fs from "fs";
8
+ import * as os from "os";
9
+ import * as path from "path";
10
+ import { AntigravityCliAdapter } from "../../adapters/AntigravityCliAdapter.js";
11
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
12
+ import { listAgentProcesses, enrichProcesses } from "../../utils/process.js";
13
+ import { generateAgentName } from "../../utils/matching.js";
14
+ vi.mock("../../utils/process.js", async (importOriginal)=>{
15
+ const actual = await importOriginal();
16
+ return {
17
+ ...actual,
18
+ listAgentProcesses: vi.fn(),
19
+ enrichProcesses: vi.fn()
20
+ };
21
+ });
22
+ vi.mock("../../utils/matching.js", async (importOriginal)=>{
23
+ const actual = await importOriginal();
24
+ return {
25
+ ...actual,
26
+ generateAgentName: vi.fn()
27
+ };
28
+ });
29
+ const mockedListAgentProcesses = listAgentProcesses;
30
+ const mockedEnrichProcesses = enrichProcesses;
31
+ const mockedGenerateAgentName = generateAgentName;
32
+ const CONVERSATION_ID = "10485e13-2742-4e9e-b286-ac0606f0cb1e";
33
+ const iso = (d)=>d.toISOString().replace(/\.\d+Z$/, "Z");
34
+ /** A user transcript record: real prompt wrapped in <USER_REQUEST> like agy writes it. */ const userRecord = (text, at)=>({
35
+ source: "USER_EXPLICIT",
36
+ type: "USER_INPUT",
37
+ created_at: iso(at ?? new Date()),
38
+ content: `<USER_REQUEST>\n${text}\n</USER_REQUEST>\n<ADDITIONAL_CONTEXT>ignored</ADDITIONAL_CONTEXT>`
39
+ });
40
+ const modelRecord = (text, at)=>({
41
+ source: "MODEL",
42
+ type: "PLANNER_RESPONSE",
43
+ created_at: iso(at ?? new Date()),
44
+ content: text
45
+ });
46
+ /** A MODEL tool-call record (e.g. RUN_COMMAND) — execution detail, not a reply. */ const toolRecord = (text, at)=>({
47
+ source: "MODEL",
48
+ type: "RUN_COMMAND",
49
+ created_at: iso(at ?? new Date()),
50
+ content: text
51
+ });
52
+ const systemRecord = (text, at)=>({
53
+ source: "SYSTEM",
54
+ type: "CHECKPOINT",
55
+ created_at: iso(at ?? new Date()),
56
+ content: text
57
+ });
58
+ describe("AntigravityCliAdapter", ()=>{
59
+ let adapter;
60
+ let base;
61
+ let cwd;
62
+ beforeEach(()=>{
63
+ base = fs.mkdtempSync(path.join(os.tmpdir(), "agy-adapter-test-"));
64
+ process.env.ANTIGRAVITY_CLI_HOME = base;
65
+ cwd = "/Users/dev/my-project";
66
+ adapter = new AntigravityCliAdapter();
67
+ mockedListAgentProcesses.mockReset();
68
+ mockedEnrichProcesses.mockReset();
69
+ mockedGenerateAgentName.mockReset();
70
+ mockedEnrichProcesses.mockImplementation((procs)=>procs);
71
+ mockedGenerateAgentName.mockImplementation((c, pid)=>`${path.basename(c) || "unknown"}-${pid}`);
72
+ });
73
+ afterEach(()=>{
74
+ delete process.env.ANTIGRAVITY_CLI_HOME;
75
+ fs.rmSync(base, {
76
+ recursive: true,
77
+ force: true
78
+ });
79
+ });
80
+ /** Write brain/<id>/.system_generated/logs/transcript.jsonl. */ function writeTranscript(opts) {
81
+ const id = opts.id ?? CONVERSATION_ID;
82
+ const dir = path.join(base, "brain", id, ".system_generated", "logs");
83
+ fs.mkdirSync(dir, {
84
+ recursive: true
85
+ });
86
+ if (opts.transcript !== false) {
87
+ const records = opts.records ?? [
88
+ userRecord("fix the bug")
89
+ ];
90
+ fs.writeFileSync(path.join(dir, "transcript.jsonl"), records.map((r)=>JSON.stringify(r)).join("\n"));
91
+ }
92
+ return path.join(dir, "transcript.jsonl");
93
+ }
94
+ /** Write cache/last_conversations.json (cwd -> conversationId). */ function writeRegistry(map) {
95
+ const dir = path.join(base, "cache");
96
+ fs.mkdirSync(dir, {
97
+ recursive: true
98
+ });
99
+ fs.writeFileSync(path.join(dir, "last_conversations.json"), JSON.stringify(map));
100
+ }
101
+ function proc(overrides = {}) {
102
+ return {
103
+ pid: 4242,
104
+ ppid: 1,
105
+ command: "agy",
106
+ cwd,
107
+ tty: "ttys010",
108
+ startTime: new Date(),
109
+ ...overrides
110
+ };
111
+ }
112
+ describe("initialization", ()=>{
113
+ it("exposes the antigravity_cli type", ()=>{
114
+ expect(adapter.type).toBe("antigravity_cli");
115
+ });
116
+ });
117
+ describe("canHandle", ()=>{
118
+ it("returns true for a plain agy command", ()=>{
119
+ expect(adapter.canHandle(proc({
120
+ command: "agy"
121
+ }))).toBe(true);
122
+ });
123
+ it("returns true for agy with a full path and args", ()=>{
124
+ expect(adapter.canHandle(proc({
125
+ command: "/Users/dev/.local/bin/agy --dangerously-skip-permissions"
126
+ }))).toBe(true);
127
+ });
128
+ it("returns false for non-agy processes", ()=>{
129
+ expect(adapter.canHandle(proc({
130
+ command: "node app.js"
131
+ }))).toBe(false);
132
+ });
133
+ it('returns false when "agy" appears only in an argument path', ()=>{
134
+ expect(adapter.canHandle(proc({
135
+ command: "node /path/to/agy-thing.js"
136
+ }))).toBe(false);
137
+ });
138
+ });
139
+ describe("detectAgents", ()=>{
140
+ it("returns [] when there are no agy processes", async ()=>{
141
+ mockedListAgentProcesses.mockReturnValue([]);
142
+ expect(await adapter.detectAgents()).toEqual([]);
143
+ });
144
+ it("resolves the conversation via last_conversations.json (cwd -> id)", async ()=>{
145
+ writeTranscript({});
146
+ writeRegistry({
147
+ [cwd]: CONVERSATION_ID
148
+ });
149
+ mockedListAgentProcesses.mockReturnValue([
150
+ proc()
151
+ ]);
152
+ const agents = await adapter.detectAgents();
153
+ expect(agents).toHaveLength(1);
154
+ expect(agents[0]).toMatchObject({
155
+ type: "antigravity_cli",
156
+ pid: 4242,
157
+ projectPath: cwd,
158
+ sessionId: CONVERSATION_ID,
159
+ summary: "fix the bug"
160
+ });
161
+ expect(agents[0].sessionFilePath).toBe(path.join(base, "brain", CONVERSATION_ID, ".system_generated", "logs", "transcript.jsonl"));
162
+ });
163
+ it("falls back to a process-only RUNNING agent when the cwd is not in the registry", async ()=>{
164
+ writeTranscript({});
165
+ writeRegistry({
166
+ "/some/other/cwd": CONVERSATION_ID
167
+ });
168
+ mockedListAgentProcesses.mockReturnValue([
169
+ proc()
170
+ ]);
171
+ const agents = await adapter.detectAgents();
172
+ expect(agents).toHaveLength(1);
173
+ expect(agents[0].status).toBe(AgentStatus.RUNNING);
174
+ expect(agents[0].sessionId).toBe("pid-4242");
175
+ expect(agents[0].sessionFilePath).toBeUndefined();
176
+ });
177
+ it("is process-only when the mapped conversation has no transcript", async ()=>{
178
+ writeTranscript({
179
+ transcript: false
180
+ });
181
+ writeRegistry({
182
+ [cwd]: CONVERSATION_ID
183
+ });
184
+ mockedListAgentProcesses.mockReturnValue([
185
+ proc()
186
+ ]);
187
+ const agents = await adapter.detectAgents();
188
+ expect(agents[0].sessionId).toBe("pid-4242");
189
+ });
190
+ });
191
+ describe("getConversation", ()=>{
192
+ it("maps USER_INPUT (<USER_REQUEST>) and MODEL records to roles", ()=>{
193
+ const file = writeTranscript({
194
+ records: [
195
+ userRecord("hi"),
196
+ modelRecord("hello")
197
+ ]
198
+ });
199
+ expect(adapter.getConversation(file)).toEqual([
200
+ {
201
+ role: "user",
202
+ content: "hi"
203
+ },
204
+ {
205
+ role: "assistant",
206
+ content: "hello"
207
+ }
208
+ ]);
209
+ });
210
+ it("accepts a bare conversation id and skips malformed lines", ()=>{
211
+ const file = writeTranscript({
212
+ records: [
213
+ userRecord("hi")
214
+ ]
215
+ });
216
+ fs.appendFileSync(file, "\n{bad json");
217
+ expect(adapter.getConversation(CONVERSATION_ID)).toEqual([
218
+ {
219
+ role: "user",
220
+ content: "hi"
221
+ }
222
+ ]);
223
+ });
224
+ it("excludes SYSTEM records unless verbose", ()=>{
225
+ const file = writeTranscript({
226
+ records: [
227
+ systemRecord("checkpoint"),
228
+ userRecord("go")
229
+ ]
230
+ });
231
+ expect(adapter.getConversation(file)).toEqual([
232
+ {
233
+ role: "user",
234
+ content: "go"
235
+ }
236
+ ]);
237
+ expect(adapter.getConversation(file, {
238
+ verbose: true
239
+ }).map((m)=>m.role)).toEqual([
240
+ "system",
241
+ "user"
242
+ ]);
243
+ });
244
+ it("excludes MODEL tool-call (RUN_COMMAND) records except in verbose", ()=>{
245
+ const file = writeTranscript({
246
+ records: [
247
+ userRecord("go"),
248
+ toolRecord("ran: echo hi"),
249
+ modelRecord("done")
250
+ ]
251
+ });
252
+ // A tool call is not an assistant reply; only USER_INPUT + PLANNER_RESPONSE show.
253
+ expect(adapter.getConversation(file)).toEqual([
254
+ {
255
+ role: "user",
256
+ content: "go"
257
+ },
258
+ {
259
+ role: "assistant",
260
+ content: "done"
261
+ }
262
+ ]);
263
+ expect(adapter.getConversation(file, {
264
+ verbose: true
265
+ }).map((m)=>m.role)).toEqual([
266
+ "user",
267
+ "system",
268
+ "assistant"
269
+ ]);
270
+ });
271
+ });
272
+ describe("detectAgents status + summary mapping", ()=>{
273
+ const detectFirst = async ()=>(await adapter.detectAgents())[0];
274
+ it("marks WAITING when the last reply is a PLANNER_RESPONSE (after a tool call)", async ()=>{
275
+ writeTranscript({
276
+ records: [
277
+ userRecord("go"),
278
+ toolRecord("ran: echo hi"),
279
+ modelRecord("done")
280
+ ]
281
+ });
282
+ writeRegistry({
283
+ [cwd]: CONVERSATION_ID
284
+ });
285
+ mockedListAgentProcesses.mockReturnValue([
286
+ proc()
287
+ ]);
288
+ expect((await detectFirst()).status).toBe(AgentStatus.WAITING);
289
+ });
290
+ it("marks RUNNING when the last transcript turn is a USER_INPUT message", async ()=>{
291
+ writeTranscript({
292
+ records: [
293
+ userRecord("still there?")
294
+ ]
295
+ });
296
+ writeRegistry({
297
+ [cwd]: CONVERSATION_ID
298
+ });
299
+ mockedListAgentProcesses.mockReturnValue([
300
+ proc()
301
+ ]);
302
+ expect((await detectFirst()).status).toBe(AgentStatus.RUNNING);
303
+ });
304
+ it("marks IDLE when the last created_at is older than the threshold", async ()=>{
305
+ const old = new Date(Date.now() - 10 * 60 * 1000);
306
+ writeTranscript({
307
+ records: [
308
+ userRecord("go", old)
309
+ ]
310
+ });
311
+ writeRegistry({
312
+ [cwd]: CONVERSATION_ID
313
+ });
314
+ mockedListAgentProcesses.mockReturnValue([
315
+ proc()
316
+ ]);
317
+ expect((await detectFirst()).status).toBe(AgentStatus.IDLE);
318
+ });
319
+ it("uses the last user request as the agent summary", async ()=>{
320
+ writeTranscript({
321
+ records: [
322
+ userRecord("refactor the parser"),
323
+ modelRecord("on it")
324
+ ]
325
+ });
326
+ writeRegistry({
327
+ [cwd]: CONVERSATION_ID
328
+ });
329
+ mockedListAgentProcesses.mockReturnValue([
330
+ proc()
331
+ ]);
332
+ expect((await detectFirst()).summary).toBe("refactor the parser");
333
+ });
334
+ });
335
+ describe("listSessions", ()=>{
336
+ it("returns [] when there is no registry", async ()=>{
337
+ expect(await adapter.listSessions()).toEqual([]);
338
+ });
339
+ it("lists sessions from the registry with cwd + first user message", async ()=>{
340
+ writeTranscript({});
341
+ writeRegistry({
342
+ [cwd]: CONVERSATION_ID
343
+ });
344
+ const summaries = await adapter.listSessions();
345
+ expect(summaries).toHaveLength(1);
346
+ expect(summaries[0]).toMatchObject({
347
+ type: "antigravity_cli",
348
+ sessionId: CONVERSATION_ID,
349
+ cwd,
350
+ firstUserMessage: "fix the bug"
351
+ });
352
+ });
353
+ it("applies the cwd filter", async ()=>{
354
+ writeTranscript({
355
+ id: "aaa0000a-0000-4000-8000-00000000000a",
356
+ records: [
357
+ userRecord("a")
358
+ ]
359
+ });
360
+ writeTranscript({
361
+ id: "bbb0000b-0000-4000-8000-00000000000b",
362
+ records: [
363
+ userRecord("b")
364
+ ]
365
+ });
366
+ writeRegistry({
367
+ "/Users/dev/project-a": "aaa0000a-0000-4000-8000-00000000000a",
368
+ "/Users/dev/project-b": "bbb0000b-0000-4000-8000-00000000000b"
369
+ });
370
+ const all = await adapter.listSessions();
371
+ expect(all).toHaveLength(2);
372
+ const filtered = await adapter.listSessions({
373
+ cwd: "/Users/dev/project-a"
374
+ });
375
+ expect(filtered).toHaveLength(1);
376
+ expect(filtered[0].cwd).toBe("/Users/dev/project-a");
377
+ });
378
+ });
379
+ });
380
+
381
+ //# sourceMappingURL=AntigravityCliAdapter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/__tests__/adapters/AntigravityCliAdapter.test.ts"],"sourcesContent":["/**\n * Tests for AntigravityCliAdapter\n *\n * The adapter resolves a live `agy` process to its conversation via\n * ~/.gemini/antigravity-cli/cache/last_conversations.json (cwd -> conversationId)\n * and reads session details from brain/<id>/.system_generated/logs/transcript.jsonl.\n */\n\nimport type { MockedFunction } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\n\nimport { AntigravityCliAdapter } from \"../../adapters/AntigravityCliAdapter.js\";\nimport type { ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { AgentStatus } from \"../../adapters/AgentAdapter.js\";\nimport { listAgentProcesses, enrichProcesses } from \"../../utils/process.js\";\nimport { generateAgentName } from \"../../utils/matching.js\";\n\nvi.mock(\"../../utils/process.js\", async (importOriginal) => {\n const actual = (await importOriginal()) as typeof import(\"../../utils/process.js\");\n return {\n ...actual,\n listAgentProcesses: vi.fn(),\n enrichProcesses: vi.fn(),\n };\n});\n\nvi.mock(\"../../utils/matching.js\", async (importOriginal) => {\n const actual = (await importOriginal()) as typeof import(\"../../utils/matching.js\");\n return {\n ...actual,\n generateAgentName: vi.fn(),\n };\n});\n\nconst mockedListAgentProcesses = listAgentProcesses as MockedFunction<typeof listAgentProcesses>;\nconst mockedEnrichProcesses = enrichProcesses as MockedFunction<typeof enrichProcesses>;\nconst mockedGenerateAgentName = generateAgentName as MockedFunction<typeof generateAgentName>;\n\nconst CONVERSATION_ID = \"10485e13-2742-4e9e-b286-ac0606f0cb1e\";\n\nconst iso = (d: Date) => d.toISOString().replace(/\\.\\d+Z$/, \"Z\");\n/** A user transcript record: real prompt wrapped in <USER_REQUEST> like agy writes it. */\nconst userRecord = (text: string, at?: Date) => ({\n source: \"USER_EXPLICIT\",\n type: \"USER_INPUT\",\n created_at: iso(at ?? new Date()),\n content: `<USER_REQUEST>\\n${text}\\n</USER_REQUEST>\\n<ADDITIONAL_CONTEXT>ignored</ADDITIONAL_CONTEXT>`,\n});\nconst modelRecord = (text: string, at?: Date) => ({\n source: \"MODEL\",\n type: \"PLANNER_RESPONSE\",\n created_at: iso(at ?? new Date()),\n content: text,\n});\n/** A MODEL tool-call record (e.g. RUN_COMMAND) — execution detail, not a reply. */\nconst toolRecord = (text: string, at?: Date) => ({\n source: \"MODEL\",\n type: \"RUN_COMMAND\",\n created_at: iso(at ?? new Date()),\n content: text,\n});\nconst systemRecord = (text: string, at?: Date) => ({\n source: \"SYSTEM\",\n type: \"CHECKPOINT\",\n created_at: iso(at ?? new Date()),\n content: text,\n});\n\ndescribe(\"AntigravityCliAdapter\", () => {\n let adapter: AntigravityCliAdapter;\n let base: string;\n let cwd: string;\n\n beforeEach(() => {\n base = fs.mkdtempSync(path.join(os.tmpdir(), \"agy-adapter-test-\"));\n process.env.ANTIGRAVITY_CLI_HOME = base;\n cwd = \"/Users/dev/my-project\";\n\n adapter = new AntigravityCliAdapter();\n\n mockedListAgentProcesses.mockReset();\n mockedEnrichProcesses.mockReset();\n mockedGenerateAgentName.mockReset();\n\n mockedEnrichProcesses.mockImplementation((procs) => procs);\n mockedGenerateAgentName.mockImplementation(\n (c: string, pid: number) => `${path.basename(c) || \"unknown\"}-${pid}`,\n );\n });\n\n afterEach(() => {\n delete process.env.ANTIGRAVITY_CLI_HOME;\n fs.rmSync(base, { recursive: true, force: true });\n });\n\n /** Write brain/<id>/.system_generated/logs/transcript.jsonl. */\n function writeTranscript(opts: {\n id?: string;\n records?: object[];\n transcript?: boolean;\n }): string {\n const id = opts.id ?? CONVERSATION_ID;\n const dir = path.join(base, \"brain\", id, \".system_generated\", \"logs\");\n fs.mkdirSync(dir, { recursive: true });\n if (opts.transcript !== false) {\n const records = opts.records ?? [userRecord(\"fix the bug\")];\n fs.writeFileSync(\n path.join(dir, \"transcript.jsonl\"),\n records.map((r) => JSON.stringify(r)).join(\"\\n\"),\n );\n }\n return path.join(dir, \"transcript.jsonl\");\n }\n\n /** Write cache/last_conversations.json (cwd -> conversationId). */\n function writeRegistry(map: Record<string, string>): void {\n const dir = path.join(base, \"cache\");\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(path.join(dir, \"last_conversations.json\"), JSON.stringify(map));\n }\n\n function proc(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 4242,\n ppid: 1,\n command: \"agy\",\n cwd,\n tty: \"ttys010\",\n startTime: new Date(),\n ...overrides,\n };\n }\n\n describe(\"initialization\", () => {\n it(\"exposes the antigravity_cli type\", () => {\n expect(adapter.type).toBe(\"antigravity_cli\");\n });\n });\n\n describe(\"canHandle\", () => {\n it(\"returns true for a plain agy command\", () => {\n expect(adapter.canHandle(proc({ command: \"agy\" }))).toBe(true);\n });\n\n it(\"returns true for agy with a full path and args\", () => {\n expect(\n adapter.canHandle(\n proc({ command: \"/Users/dev/.local/bin/agy --dangerously-skip-permissions\" }),\n ),\n ).toBe(true);\n });\n\n it(\"returns false for non-agy processes\", () => {\n expect(adapter.canHandle(proc({ command: \"node app.js\" }))).toBe(false);\n });\n\n it('returns false when \"agy\" appears only in an argument path', () => {\n expect(adapter.canHandle(proc({ command: \"node /path/to/agy-thing.js\" }))).toBe(false);\n });\n });\n\n describe(\"detectAgents\", () => {\n it(\"returns [] when there are no agy processes\", async () => {\n mockedListAgentProcesses.mockReturnValue([]);\n expect(await adapter.detectAgents()).toEqual([]);\n });\n\n it(\"resolves the conversation via last_conversations.json (cwd -> id)\", async () => {\n writeTranscript({});\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n\n const agents = await adapter.detectAgents();\n\n expect(agents).toHaveLength(1);\n expect(agents[0]).toMatchObject({\n type: \"antigravity_cli\",\n pid: 4242,\n projectPath: cwd,\n sessionId: CONVERSATION_ID,\n summary: \"fix the bug\",\n });\n expect(agents[0].sessionFilePath).toBe(\n path.join(base, \"brain\", CONVERSATION_ID, \".system_generated\", \"logs\", \"transcript.jsonl\"),\n );\n });\n\n it(\"falls back to a process-only RUNNING agent when the cwd is not in the registry\", async () => {\n writeTranscript({});\n writeRegistry({ \"/some/other/cwd\": CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n\n const agents = await adapter.detectAgents();\n\n expect(agents).toHaveLength(1);\n expect(agents[0].status).toBe(AgentStatus.RUNNING);\n expect(agents[0].sessionId).toBe(\"pid-4242\");\n expect(agents[0].sessionFilePath).toBeUndefined();\n });\n\n it(\"is process-only when the mapped conversation has no transcript\", async () => {\n writeTranscript({ transcript: false });\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n\n const agents = await adapter.detectAgents();\n\n expect(agents[0].sessionId).toBe(\"pid-4242\");\n });\n });\n\n describe(\"getConversation\", () => {\n it(\"maps USER_INPUT (<USER_REQUEST>) and MODEL records to roles\", () => {\n const file = writeTranscript({ records: [userRecord(\"hi\"), modelRecord(\"hello\")] });\n expect(adapter.getConversation(file)).toEqual([\n { role: \"user\", content: \"hi\" },\n { role: \"assistant\", content: \"hello\" },\n ]);\n });\n\n it(\"accepts a bare conversation id and skips malformed lines\", () => {\n const file = writeTranscript({ records: [userRecord(\"hi\")] });\n fs.appendFileSync(file, \"\\n{bad json\");\n expect(adapter.getConversation(CONVERSATION_ID)).toEqual([{ role: \"user\", content: \"hi\" }]);\n });\n\n it(\"excludes SYSTEM records unless verbose\", () => {\n const file = writeTranscript({ records: [systemRecord(\"checkpoint\"), userRecord(\"go\")] });\n expect(adapter.getConversation(file)).toEqual([{ role: \"user\", content: \"go\" }]);\n expect(adapter.getConversation(file, { verbose: true }).map((m) => m.role)).toEqual([\n \"system\",\n \"user\",\n ]);\n });\n\n it(\"excludes MODEL tool-call (RUN_COMMAND) records except in verbose\", () => {\n const file = writeTranscript({\n records: [userRecord(\"go\"), toolRecord(\"ran: echo hi\"), modelRecord(\"done\")],\n });\n // A tool call is not an assistant reply; only USER_INPUT + PLANNER_RESPONSE show.\n expect(adapter.getConversation(file)).toEqual([\n { role: \"user\", content: \"go\" },\n { role: \"assistant\", content: \"done\" },\n ]);\n expect(adapter.getConversation(file, { verbose: true }).map((m) => m.role)).toEqual([\n \"user\",\n \"system\",\n \"assistant\",\n ]);\n });\n });\n\n describe(\"detectAgents status + summary mapping\", () => {\n const detectFirst = async () => (await adapter.detectAgents())[0];\n\n it(\"marks WAITING when the last reply is a PLANNER_RESPONSE (after a tool call)\", async () => {\n writeTranscript({\n records: [userRecord(\"go\"), toolRecord(\"ran: echo hi\"), modelRecord(\"done\")],\n });\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n expect((await detectFirst()).status).toBe(AgentStatus.WAITING);\n });\n\n it(\"marks RUNNING when the last transcript turn is a USER_INPUT message\", async () => {\n writeTranscript({ records: [userRecord(\"still there?\")] });\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n expect((await detectFirst()).status).toBe(AgentStatus.RUNNING);\n });\n\n it(\"marks IDLE when the last created_at is older than the threshold\", async () => {\n const old = new Date(Date.now() - 10 * 60 * 1000);\n writeTranscript({ records: [userRecord(\"go\", old)] });\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n expect((await detectFirst()).status).toBe(AgentStatus.IDLE);\n });\n\n it(\"uses the last user request as the agent summary\", async () => {\n writeTranscript({ records: [userRecord(\"refactor the parser\"), modelRecord(\"on it\")] });\n writeRegistry({ [cwd]: CONVERSATION_ID });\n mockedListAgentProcesses.mockReturnValue([proc()]);\n expect((await detectFirst()).summary).toBe(\"refactor the parser\");\n });\n });\n\n describe(\"listSessions\", () => {\n it(\"returns [] when there is no registry\", async () => {\n expect(await adapter.listSessions()).toEqual([]);\n });\n\n it(\"lists sessions from the registry with cwd + first user message\", async () => {\n writeTranscript({});\n writeRegistry({ [cwd]: CONVERSATION_ID });\n const summaries = await adapter.listSessions();\n expect(summaries).toHaveLength(1);\n expect(summaries[0]).toMatchObject({\n type: \"antigravity_cli\",\n sessionId: CONVERSATION_ID,\n cwd,\n firstUserMessage: \"fix the bug\",\n });\n });\n\n it(\"applies the cwd filter\", async () => {\n writeTranscript({ id: \"aaa0000a-0000-4000-8000-00000000000a\", records: [userRecord(\"a\")] });\n writeTranscript({ id: \"bbb0000b-0000-4000-8000-00000000000b\", records: [userRecord(\"b\")] });\n writeRegistry({\n \"/Users/dev/project-a\": \"aaa0000a-0000-4000-8000-00000000000a\",\n \"/Users/dev/project-b\": \"bbb0000b-0000-4000-8000-00000000000b\",\n });\n\n const all = await adapter.listSessions();\n expect(all).toHaveLength(2);\n\n const filtered = await adapter.listSessions({ cwd: \"/Users/dev/project-a\" });\n expect(filtered).toHaveLength(1);\n expect(filtered[0].cwd).toBe(\"/Users/dev/project-a\");\n });\n });\n});\n"],"names":["fs","os","path","AntigravityCliAdapter","AgentStatus","listAgentProcesses","enrichProcesses","generateAgentName","vi","mock","importOriginal","actual","fn","mockedListAgentProcesses","mockedEnrichProcesses","mockedGenerateAgentName","CONVERSATION_ID","iso","d","toISOString","replace","userRecord","text","at","source","type","created_at","Date","content","modelRecord","toolRecord","systemRecord","describe","adapter","base","cwd","beforeEach","mkdtempSync","join","tmpdir","process","env","ANTIGRAVITY_CLI_HOME","mockReset","mockImplementation","procs","c","pid","basename","afterEach","rmSync","recursive","force","writeTranscript","opts","id","dir","mkdirSync","transcript","records","writeFileSync","map","r","JSON","stringify","writeRegistry","proc","overrides","ppid","command","tty","startTime","it","expect","toBe","canHandle","mockReturnValue","detectAgents","toEqual","agents","toHaveLength","toMatchObject","projectPath","sessionId","summary","sessionFilePath","status","RUNNING","toBeUndefined","file","getConversation","role","appendFileSync","verbose","m","detectFirst","WAITING","old","now","IDLE","listSessions","summaries","firstUserMessage","all","filtered"],"mappings":"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"}
@@ -1682,6 +1682,34 @@ describe("ClaudeCodeAdapter", ()=>{
1682
1682
  cwdB
1683
1683
  ]);
1684
1684
  });
1685
+ it("finds an exact session ID without returning other project sessions", async ()=>{
1686
+ const wantedPath = writeSession(path.join(projectsDir, "-repo-a"), "wanted", [
1687
+ {
1688
+ type: "user",
1689
+ timestamp: "2025-01-01T00:00:00Z",
1690
+ cwd: "/repo-a",
1691
+ message: {
1692
+ content: "wanted prompt"
1693
+ }
1694
+ }
1695
+ ]);
1696
+ writeSession(path.join(projectsDir, "-repo-b"), "other", [
1697
+ {
1698
+ type: "user",
1699
+ timestamp: "2025-01-01T00:00:00Z",
1700
+ cwd: "/repo-b",
1701
+ message: {
1702
+ content: "other prompt"
1703
+ }
1704
+ }
1705
+ ]);
1706
+ await expect(adapter.findSessionsById("wanted")).resolves.toEqual([
1707
+ expect.objectContaining({
1708
+ sessionId: "wanted",
1709
+ sessionFilePath: wantedPath
1710
+ })
1711
+ ]);
1712
+ });
1685
1713
  it("drops sessions whose recorded cwd does not match opts.cwd (strict equality)", async ()=>{
1686
1714
  const cwdReal = "/Users/test/foo";
1687
1715
  const cwdRequested = "/Users/test/foo/sub";