@ai-devkit/agent-manager 0.32.0 → 0.33.1

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 (572) hide show
  1. package/dist/AgentManager.d.ts +13 -4
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +116 -84
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +623 -391
  6. package/dist/__tests__/AgentManager.test.js.map +1 -1
  7. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +642 -642
  8. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +1 -1
  9. package/dist/__tests__/adapters/CodexAdapter.test.js +322 -2321
  10. package/dist/__tests__/adapters/CodexAdapter.test.js.map +1 -1
  11. package/dist/__tests__/adapters/GrokCliAdapter.test.js +114 -114
  12. package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +1 -1
  13. package/dist/__tests__/adapters/OpenCodeAdapter.test.js +170 -169
  14. package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
  15. package/dist/__tests__/capacity/codex.test.js +93 -93
  16. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  17. package/dist/__tests__/capacity/index.test.js +17 -17
  18. package/dist/__tests__/capacity/index.test.js.map +1 -1
  19. package/dist/__tests__/durable/CodexCliProbe.test.js +60 -60
  20. package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -1
  21. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +28 -28
  22. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -1
  23. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +30 -30
  24. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -1
  25. package/dist/__tests__/durable/CodexPrintAgentService.test.js +71 -71
  26. package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -1
  27. package/dist/__tests__/durable/CodexPrintRunner.test.js +125 -125
  28. package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -1
  29. package/dist/__tests__/print/ClaudeCliProbe.test.js +20 -20
  30. package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
  31. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +20 -20
  32. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
  33. package/dist/__tests__/print/ClaudePrintAgentService.test.js +58 -58
  34. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
  35. package/dist/__tests__/print/ClaudePrintRunner.test.js +55 -55
  36. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
  37. package/dist/__tests__/print/DurableAgent.test.js +9 -9
  38. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  39. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +40 -40
  40. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -1
  41. package/dist/__tests__/print/DurableAgentRepository.test.js +66 -66
  42. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  43. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +34 -34
  44. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -1
  45. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +132 -132
  46. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -1
  47. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +194 -0
  48. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +1 -0
  49. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +86 -0
  50. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +1 -0
  51. package/dist/__tests__/providers/codex/CodexSessionParser.test.js +254 -0
  52. package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +1 -0
  53. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js +641 -0
  54. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +1 -0
  55. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js +1398 -0
  56. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +1 -0
  57. package/dist/__tests__/providers/pi/PiAdapter.test.js +337 -0
  58. package/dist/__tests__/providers/pi/PiAdapter.test.js.map +1 -0
  59. package/dist/__tests__/providers/pi/PiSessionParser.test.js +246 -0
  60. package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +1 -0
  61. package/dist/__tests__/providers/pi/PiSessionTracker.test.js +108 -0
  62. package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +1 -0
  63. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +33 -33
  64. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +1 -1
  65. package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js +16 -16
  66. package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +1 -1
  67. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +52 -52
  68. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +1 -1
  69. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +44 -44
  70. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +1 -1
  71. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +126 -126
  72. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +1 -1
  73. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +14 -14
  74. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +1 -1
  75. package/dist/__tests__/readiness/AgentReadiness.test.js +134 -134
  76. package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -1
  77. package/dist/__tests__/runtime/AgentRuntime.test.js +13 -0
  78. package/dist/__tests__/runtime/AgentRuntime.test.js.map +1 -0
  79. package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js +164 -0
  80. package/dist/__tests__/runtime/HerdrAgentDiscovery.test.js.map +1 -0
  81. package/dist/__tests__/runtime/HerdrAgentRuntime.test.js +488 -0
  82. package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -0
  83. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +588 -0
  84. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -0
  85. package/dist/__tests__/terminal/TerminalFocusManager.test.js +100 -100
  86. package/dist/__tests__/terminal/TerminalFocusManager.test.js.map +1 -1
  87. package/dist/__tests__/terminal/TmuxManager.test.js +101 -101
  88. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  89. package/dist/__tests__/terminal/TtyWriter.test.js +185 -185
  90. package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -1
  91. package/dist/__tests__/utils/AgentRegistry.test.js +343 -218
  92. package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
  93. package/dist/__tests__/utils/ClaudeSessionParser.test.js +103 -101
  94. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
  95. package/dist/__tests__/utils/agent-requests.test.js +43 -43
  96. package/dist/__tests__/utils/agent-requests.test.js.map +1 -1
  97. package/dist/__tests__/utils/agents.test.js +17 -17
  98. package/dist/__tests__/utils/agents.test.js.map +1 -1
  99. package/dist/__tests__/utils/matching.test.js +92 -92
  100. package/dist/__tests__/utils/matching.test.js.map +1 -1
  101. package/dist/__tests__/utils/process.test.js +108 -108
  102. package/dist/__tests__/utils/process.test.js.map +1 -1
  103. package/dist/__tests__/utils/session.test.js +53 -53
  104. package/dist/__tests__/utils/session.test.js.map +1 -1
  105. package/dist/adapters/AgentAdapter.d.ts +2 -2
  106. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  107. package/dist/adapters/AgentAdapter.js +1 -1
  108. package/dist/adapters/AgentAdapter.js.map +1 -1
  109. package/dist/adapters/GrokCliAdapter.d.ts +1 -1
  110. package/dist/adapters/GrokCliAdapter.d.ts.map +1 -1
  111. package/dist/adapters/GrokCliAdapter.js +80 -80
  112. package/dist/adapters/GrokCliAdapter.js.map +1 -1
  113. package/dist/adapters/OpenCodeAdapter.d.ts +2 -1
  114. package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
  115. package/dist/adapters/OpenCodeAdapter.js +41 -37
  116. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  117. package/dist/adapters/index.d.ts +9 -9
  118. package/dist/adapters/index.d.ts.map +1 -1
  119. package/dist/adapters/index.js +8 -8
  120. package/dist/adapters/index.js.map +1 -1
  121. package/dist/capacity/codex.d.ts +3 -3
  122. package/dist/capacity/codex.d.ts.map +1 -1
  123. package/dist/capacity/codex.js +57 -57
  124. package/dist/capacity/codex.js.map +1 -1
  125. package/dist/capacity/index.d.ts +3 -3
  126. package/dist/capacity/index.d.ts.map +1 -1
  127. package/dist/capacity/index.js +8 -8
  128. package/dist/capacity/index.js.map +1 -1
  129. package/dist/capacity/types.d.ts +1 -1
  130. package/dist/capacity/types.js.map +1 -1
  131. package/dist/database/connection.d.ts +1 -1
  132. package/dist/database/connection.d.ts.map +1 -1
  133. package/dist/database/connection.js +15 -15
  134. package/dist/database/connection.js.map +1 -1
  135. package/dist/database/index.d.ts +3 -3
  136. package/dist/database/index.d.ts.map +1 -1
  137. package/dist/database/index.js +2 -2
  138. package/dist/database/index.js.map +1 -1
  139. package/dist/database/migrations/005_agent_runtime.sql +2 -0
  140. package/dist/database/schema.d.ts +1 -1
  141. package/dist/database/schema.d.ts.map +1 -1
  142. package/dist/database/schema.js +7 -7
  143. package/dist/database/schema.js.map +1 -1
  144. package/dist/durable/DurableAgent.d.ts +9 -9
  145. package/dist/durable/DurableAgent.d.ts.map +1 -1
  146. package/dist/durable/DurableAgent.js +16 -16
  147. package/dist/durable/DurableAgent.js.map +1 -1
  148. package/dist/durable/DurableAgentRepository.d.ts +4 -4
  149. package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
  150. package/dist/durable/DurableAgentRepository.js +49 -48
  151. package/dist/durable/DurableAgentRepository.js.map +1 -1
  152. package/dist/durable/process.d.ts +1 -1
  153. package/dist/durable/process.d.ts.map +1 -1
  154. package/dist/durable/process.js +14 -14
  155. package/dist/durable/process.js.map +1 -1
  156. package/dist/durable/run.d.ts +2 -2
  157. package/dist/durable/run.d.ts.map +1 -1
  158. package/dist/durable/run.js +6 -6
  159. package/dist/durable/run.js.map +1 -1
  160. package/dist/durable/utils.d.ts +1 -1
  161. package/dist/durable/utils.d.ts.map +1 -1
  162. package/dist/durable/utils.js +4 -4
  163. package/dist/durable/utils.js.map +1 -1
  164. package/dist/index.d.ts +48 -43
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +28 -26
  167. package/dist/index.js.map +1 -1
  168. package/dist/providers/claude/ClaudeAgentMapper.d.ts +4 -4
  169. package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -1
  170. package/dist/providers/claude/ClaudeAgentMapper.js +10 -10
  171. package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -1
  172. package/dist/providers/claude/ClaudeCodeAdapter.d.ts +1 -1
  173. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
  174. package/dist/providers/claude/ClaudeCodeAdapter.js +14 -14
  175. package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
  176. package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -4
  177. package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
  178. package/dist/providers/claude/ClaudeSessionLocator.js +79 -79
  179. package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
  180. package/dist/providers/claude/ClaudeSessionParser.d.ts +2 -2
  181. package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -1
  182. package/dist/providers/claude/ClaudeSessionParser.js +99 -99
  183. package/dist/providers/claude/ClaudeSessionParser.js.map +1 -1
  184. package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
  185. package/dist/providers/claude/durable/ClaudeCliProbe.js +16 -16
  186. package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -1
  187. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts +5 -5
  188. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
  189. package/dist/providers/claude/durable/ClaudePrintAgentService.js +10 -10
  190. package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -1
  191. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts +4 -4
  192. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
  193. package/dist/providers/claude/durable/ClaudePrintRunner.js +18 -18
  194. package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -1
  195. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +2 -2
  196. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
  197. package/dist/providers/claude/durable/ClaudeStreamParser.js +17 -17
  198. package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -1
  199. package/dist/providers/codex/CodexAdapter.d.ts +27 -0
  200. package/dist/providers/codex/CodexAdapter.d.ts.map +1 -0
  201. package/dist/providers/codex/CodexAdapter.js +162 -0
  202. package/dist/providers/codex/CodexAdapter.js.map +1 -0
  203. package/dist/providers/codex/CodexAgentMapper.d.ts +9 -0
  204. package/dist/providers/codex/CodexAgentMapper.d.ts.map +1 -0
  205. package/dist/providers/codex/CodexAgentMapper.js +35 -0
  206. package/dist/providers/codex/CodexAgentMapper.js.map +1 -0
  207. package/dist/providers/codex/CodexSessionLocator.d.ts +44 -0
  208. package/dist/providers/codex/CodexSessionLocator.d.ts.map +1 -0
  209. package/dist/providers/codex/CodexSessionLocator.js +207 -0
  210. package/dist/providers/codex/CodexSessionLocator.js.map +1 -0
  211. package/dist/providers/codex/CodexSessionMapping.d.ts +23 -0
  212. package/dist/providers/codex/CodexSessionMapping.d.ts.map +1 -0
  213. package/dist/providers/codex/CodexSessionMapping.js +68 -0
  214. package/dist/providers/codex/CodexSessionMapping.js.map +1 -0
  215. package/dist/providers/codex/CodexSessionParser.d.ts +58 -0
  216. package/dist/providers/codex/CodexSessionParser.d.ts.map +1 -0
  217. package/dist/providers/codex/CodexSessionParser.js +262 -0
  218. package/dist/providers/codex/CodexSessionParser.js.map +1 -0
  219. package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -1
  220. package/dist/providers/codex/durable/CodexCliProbe.js +22 -22
  221. package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -1
  222. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +6 -6
  223. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
  224. package/dist/providers/codex/durable/CodexPrintAgentService.js +10 -10
  225. package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -1
  226. package/dist/providers/codex/durable/CodexPrintRunner.d.ts +4 -4
  227. package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -1
  228. package/dist/providers/codex/durable/CodexPrintRunner.js +20 -20
  229. package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -1
  230. package/dist/providers/codex/durable/CodexStreamParser.d.ts +2 -2
  231. package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -1
  232. package/dist/providers/codex/durable/CodexStreamParser.js +21 -21
  233. package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -1
  234. package/dist/{adapters → providers/copilot}/CopilotAdapter.d.ts +11 -25
  235. package/dist/providers/copilot/CopilotAdapter.d.ts.map +1 -0
  236. package/dist/providers/copilot/CopilotAdapter.js +108 -0
  237. package/dist/providers/copilot/CopilotAdapter.js.map +1 -0
  238. package/dist/providers/copilot/CopilotAgentMapper.d.ts +9 -0
  239. package/dist/providers/copilot/CopilotAgentMapper.d.ts.map +1 -0
  240. package/dist/providers/copilot/CopilotAgentMapper.js +37 -0
  241. package/dist/providers/copilot/CopilotAgentMapper.js.map +1 -0
  242. package/dist/providers/copilot/CopilotSessionLocator.d.ts +19 -0
  243. package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +1 -0
  244. package/dist/providers/copilot/CopilotSessionLocator.js +41 -0
  245. package/dist/providers/copilot/CopilotSessionLocator.js.map +1 -0
  246. package/dist/providers/copilot/CopilotSessionParser.d.ts +30 -0
  247. package/dist/providers/copilot/CopilotSessionParser.d.ts.map +1 -0
  248. package/dist/providers/copilot/CopilotSessionParser.js +181 -0
  249. package/dist/providers/copilot/CopilotSessionParser.js.map +1 -0
  250. package/dist/providers/gemini/GeminiAgentMapper.d.ts +9 -0
  251. package/dist/providers/gemini/GeminiAgentMapper.d.ts.map +1 -0
  252. package/dist/providers/gemini/GeminiAgentMapper.js +37 -0
  253. package/dist/providers/gemini/GeminiAgentMapper.js.map +1 -0
  254. package/dist/providers/gemini/GeminiCliAdapter.d.ts +52 -0
  255. package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +1 -0
  256. package/dist/providers/gemini/GeminiCliAdapter.js +188 -0
  257. package/dist/providers/gemini/GeminiCliAdapter.js.map +1 -0
  258. package/dist/providers/gemini/GeminiSessionLocator.d.ts +30 -0
  259. package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +1 -0
  260. package/dist/providers/gemini/GeminiSessionLocator.js +142 -0
  261. package/dist/providers/gemini/GeminiSessionLocator.js.map +1 -0
  262. package/dist/providers/gemini/GeminiSessionParser.d.ts +94 -0
  263. package/dist/providers/gemini/GeminiSessionParser.d.ts.map +1 -0
  264. package/dist/providers/gemini/GeminiSessionParser.js +166 -0
  265. package/dist/providers/gemini/GeminiSessionParser.js.map +1 -0
  266. package/dist/providers/pi/PiAdapter.d.ts +28 -0
  267. package/dist/providers/pi/PiAdapter.d.ts.map +1 -0
  268. package/dist/providers/pi/PiAdapter.js +153 -0
  269. package/dist/providers/pi/PiAdapter.js.map +1 -0
  270. package/dist/providers/pi/PiAgentMapper.d.ts +9 -0
  271. package/dist/providers/pi/PiAgentMapper.d.ts.map +1 -0
  272. package/dist/providers/pi/PiAgentMapper.js +37 -0
  273. package/dist/providers/pi/PiAgentMapper.js.map +1 -0
  274. package/dist/providers/pi/PiSessionLocator.d.ts +23 -0
  275. package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -0
  276. package/dist/providers/pi/PiSessionLocator.js +79 -0
  277. package/dist/providers/pi/PiSessionLocator.js.map +1 -0
  278. package/dist/providers/pi/PiSessionParser.d.ts +36 -0
  279. package/dist/providers/pi/PiSessionParser.d.ts.map +1 -0
  280. package/dist/providers/pi/PiSessionParser.js +191 -0
  281. package/dist/providers/pi/PiSessionParser.js.map +1 -0
  282. package/dist/providers/pi/PiSessionTracker.d.ts +23 -0
  283. package/dist/providers/pi/PiSessionTracker.d.ts.map +1 -0
  284. package/dist/providers/pi/PiSessionTracker.js +69 -0
  285. package/dist/providers/pi/PiSessionTracker.js.map +1 -0
  286. package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -1
  287. package/dist/providers/pi/durable/PiCliProbe.js +15 -15
  288. package/dist/providers/pi/durable/PiCliProbe.js.map +1 -1
  289. package/dist/providers/pi/durable/PiPrintAgentService.d.ts +6 -6
  290. package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -1
  291. package/dist/providers/pi/durable/PiPrintAgentService.js +10 -10
  292. package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -1
  293. package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -1
  294. package/dist/providers/pi/durable/PiPrintProtocol.js +18 -18
  295. package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -1
  296. package/dist/providers/pi/durable/PiPrintRunner.d.ts +4 -4
  297. package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -1
  298. package/dist/providers/pi/durable/PiPrintRunner.js +15 -15
  299. package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -1
  300. package/dist/providers/pi/durable/PiStreamParser.d.ts +1 -1
  301. package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -1
  302. package/dist/providers/pi/durable/PiStreamParser.js +16 -16
  303. package/dist/providers/pi/durable/PiStreamParser.js.map +1 -1
  304. package/dist/readiness/AgentReadiness.d.ts +6 -6
  305. package/dist/readiness/AgentReadiness.d.ts.map +1 -1
  306. package/dist/readiness/AgentReadiness.js +130 -130
  307. package/dist/readiness/AgentReadiness.js.map +1 -1
  308. package/dist/runtime/ManagedAgentRuntime.d.ts +69 -0
  309. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -0
  310. package/dist/runtime/ManagedAgentRuntime.js +156 -0
  311. package/dist/runtime/ManagedAgentRuntime.js.map +1 -0
  312. package/dist/runtime/RuntimeFactory.d.ts +4 -0
  313. package/dist/runtime/RuntimeFactory.d.ts.map +1 -0
  314. package/dist/runtime/RuntimeFactory.js +11 -0
  315. package/dist/runtime/RuntimeFactory.js.map +1 -0
  316. package/dist/runtime/errors.d.ts +27 -0
  317. package/dist/runtime/errors.d.ts.map +1 -0
  318. package/dist/runtime/errors.js +42 -0
  319. package/dist/runtime/errors.js.map +1 -0
  320. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts +18 -0
  321. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -0
  322. package/dist/runtime/herdr/HerdrAgentDiscovery.js +183 -0
  323. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -0
  324. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +36 -0
  325. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -0
  326. package/dist/runtime/herdr/HerdrAgentRuntime.js +202 -0
  327. package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -0
  328. package/dist/runtime/herdr/HerdrCliClient.d.ts +13 -0
  329. package/dist/runtime/herdr/HerdrCliClient.d.ts.map +1 -0
  330. package/dist/runtime/herdr/HerdrCliClient.js +60 -0
  331. package/dist/runtime/herdr/HerdrCliClient.js.map +1 -0
  332. package/dist/runtime/herdr/HerdrErrors.d.ts +7 -0
  333. package/dist/runtime/herdr/HerdrErrors.d.ts.map +1 -0
  334. package/dist/runtime/herdr/HerdrErrors.js +10 -0
  335. package/dist/runtime/herdr/HerdrErrors.js.map +1 -0
  336. package/dist/runtime/herdr/HerdrResponseParsers.d.ts +16 -0
  337. package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -0
  338. package/dist/runtime/herdr/HerdrResponseParsers.js +107 -0
  339. package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -0
  340. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts +9 -0
  341. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts.map +1 -0
  342. package/dist/runtime/herdr/HerdrRuntimeRef.js +33 -0
  343. package/dist/runtime/herdr/HerdrRuntimeRef.js.map +1 -0
  344. package/dist/runtime/tmux/PidPolling.d.ts +5 -0
  345. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -0
  346. package/dist/runtime/tmux/PidPolling.js +24 -0
  347. package/dist/runtime/tmux/PidPolling.js.map +1 -0
  348. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +17 -0
  349. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -0
  350. package/dist/runtime/tmux/TmuxAgentRuntime.js +80 -0
  351. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -0
  352. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts +5 -0
  353. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts.map +1 -0
  354. package/dist/runtime/tmux/TmuxRuntimeRef.js +9 -0
  355. package/dist/runtime/tmux/TmuxRuntimeRef.js.map +1 -0
  356. package/dist/runtime/types.d.ts +54 -0
  357. package/dist/runtime/types.d.ts.map +1 -0
  358. package/dist/runtime/types.js +3 -0
  359. package/dist/runtime/types.js.map +1 -0
  360. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  361. package/dist/terminal/TerminalFocusManager.js +50 -50
  362. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  363. package/dist/terminal/TmuxManager.d.ts.map +1 -1
  364. package/dist/terminal/TmuxManager.js +47 -47
  365. package/dist/terminal/TmuxManager.js.map +1 -1
  366. package/dist/terminal/TtyWriter.d.ts +1 -1
  367. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  368. package/dist/terminal/TtyWriter.js +89 -89
  369. package/dist/terminal/TtyWriter.js.map +1 -1
  370. package/dist/terminal/index.d.ts +4 -4
  371. package/dist/terminal/index.js +3 -3
  372. package/dist/terminal/index.js.map +1 -1
  373. package/dist/utils/AgentRegistry.d.ts +10 -2
  374. package/dist/utils/AgentRegistry.d.ts.map +1 -1
  375. package/dist/utils/AgentRegistry.js +59 -26
  376. package/dist/utils/AgentRegistry.js.map +1 -1
  377. package/dist/utils/agent-requests.d.ts.map +1 -1
  378. package/dist/utils/agent-requests.js +5 -5
  379. package/dist/utils/agent-requests.js.map +1 -1
  380. package/dist/utils/agents.d.ts +2 -2
  381. package/dist/utils/agents.d.ts.map +1 -1
  382. package/dist/utils/agents.js +15 -15
  383. package/dist/utils/agents.js.map +1 -1
  384. package/dist/utils/applescript.js +1 -1
  385. package/dist/utils/applescript.js.map +1 -1
  386. package/dist/utils/index.d.ts +6 -6
  387. package/dist/utils/index.d.ts.map +1 -1
  388. package/dist/utils/index.js +4 -4
  389. package/dist/utils/index.js.map +1 -1
  390. package/dist/utils/matching.d.ts +2 -2
  391. package/dist/utils/matching.d.ts.map +1 -1
  392. package/dist/utils/matching.js +4 -4
  393. package/dist/utils/matching.js.map +1 -1
  394. package/dist/utils/process.d.ts +1 -1
  395. package/dist/utils/process.d.ts.map +1 -1
  396. package/dist/utils/process.js +74 -74
  397. package/dist/utils/process.js.map +1 -1
  398. package/dist/utils/session.d.ts +1 -1
  399. package/dist/utils/session.d.ts.map +1 -1
  400. package/dist/utils/session.js +7 -7
  401. package/dist/utils/session.js.map +1 -1
  402. package/dist/utils/sortAgents.d.ts +2 -2
  403. package/dist/utils/sortAgents.d.ts.map +1 -1
  404. package/dist/utils/sortAgents.js +5 -5
  405. package/dist/utils/sortAgents.js.map +1 -1
  406. package/package.json +18 -19
  407. package/src/AgentManager.ts +338 -274
  408. package/src/__tests__/AgentManager.test.ts +1143 -907
  409. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1657 -1368
  410. package/src/__tests__/adapters/CodexAdapter.test.ts +365 -1698
  411. package/src/__tests__/adapters/GrokCliAdapter.test.ts +325 -272
  412. package/src/__tests__/adapters/OpenCodeAdapter.test.ts +511 -455
  413. package/src/__tests__/capacity/codex.test.ts +178 -91
  414. package/src/__tests__/capacity/index.test.ts +27 -18
  415. package/src/__tests__/durable/CodexCliProbe.test.ts +75 -53
  416. package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +51 -40
  417. package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +89 -64
  418. package/src/__tests__/durable/CodexPrintAgentService.test.ts +196 -118
  419. package/src/__tests__/durable/CodexPrintRunner.test.ts +282 -162
  420. package/src/__tests__/fixtures/fake-claude.cjs +20 -13
  421. package/src/__tests__/fixtures/fake-codex.cjs +41 -30
  422. package/src/__tests__/print/ClaudeCliProbe.test.ts +27 -21
  423. package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +48 -40
  424. package/src/__tests__/print/ClaudePrintAgentService.test.ts +118 -67
  425. package/src/__tests__/print/ClaudePrintRunner.test.ts +136 -83
  426. package/src/__tests__/print/DurableAgent.test.ts +19 -16
  427. package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +109 -86
  428. package/src/__tests__/print/DurableAgentRepository.test.ts +170 -137
  429. package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +65 -65
  430. package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +400 -377
  431. package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +182 -0
  432. package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +63 -0
  433. package/src/__tests__/providers/codex/CodexSessionParser.test.ts +192 -0
  434. package/src/__tests__/providers/copilot/CopilotAdapter.test.ts +602 -0
  435. package/src/__tests__/providers/gemini/GeminiCliAdapter.test.ts +1299 -0
  436. package/src/__tests__/providers/pi/PiAdapter.test.ts +310 -0
  437. package/src/__tests__/providers/pi/PiSessionParser.test.ts +190 -0
  438. package/src/__tests__/providers/pi/PiSessionTracker.test.ts +79 -0
  439. package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +48 -32
  440. package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +24 -23
  441. package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +131 -59
  442. package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +66 -28
  443. package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +236 -90
  444. package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +20 -18
  445. package/src/__tests__/readiness/AgentReadiness.test.ts +217 -169
  446. package/src/__tests__/runtime/AgentRuntime.test.ts +8 -0
  447. package/src/__tests__/runtime/HerdrAgentDiscovery.test.ts +131 -0
  448. package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +377 -0
  449. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +555 -0
  450. package/src/__tests__/terminal/TerminalFocusManager.test.ts +254 -253
  451. package/src/__tests__/terminal/TmuxManager.test.ts +157 -157
  452. package/src/__tests__/terminal/TtyWriter.test.ts +423 -419
  453. package/src/__tests__/utils/AgentRegistry.test.ts +516 -402
  454. package/src/__tests__/utils/ClaudeSessionParser.test.ts +276 -242
  455. package/src/__tests__/utils/agent-requests.test.ts +76 -56
  456. package/src/__tests__/utils/agents.test.ts +20 -20
  457. package/src/__tests__/utils/matching.test.ts +206 -171
  458. package/src/__tests__/utils/process.test.ts +276 -262
  459. package/src/__tests__/utils/session.test.ts +133 -139
  460. package/src/adapters/AgentAdapter.ts +134 -126
  461. package/src/adapters/GrokCliAdapter.ts +353 -342
  462. package/src/adapters/OpenCodeAdapter.ts +289 -259
  463. package/src/adapters/index.ts +15 -9
  464. package/src/capacity/codex.ts +137 -84
  465. package/src/capacity/index.ts +18 -13
  466. package/src/capacity/types.ts +1 -1
  467. package/src/database/connection.ts +73 -68
  468. package/src/database/index.ts +6 -6
  469. package/src/database/migrations/005_agent_runtime.sql +2 -0
  470. package/src/database/schema.ts +40 -38
  471. package/src/durable/DurableAgent.ts +85 -85
  472. package/src/durable/DurableAgentRepository.ts +409 -260
  473. package/src/durable/process.ts +22 -21
  474. package/src/durable/run.ts +61 -51
  475. package/src/durable/utils.ts +46 -41
  476. package/src/index.ts +151 -103
  477. package/src/providers/claude/ClaudeAgentMapper.ts +51 -50
  478. package/src/providers/claude/ClaudeCodeAdapter.ts +144 -136
  479. package/src/providers/claude/ClaudeSessionLocator.ts +291 -293
  480. package/src/providers/claude/ClaudeSessionParser.ts +322 -338
  481. package/src/providers/claude/durable/ClaudeCliProbe.ts +42 -37
  482. package/src/providers/claude/durable/ClaudePrintAgentService.ts +63 -50
  483. package/src/providers/claude/durable/ClaudePrintRunner.ts +79 -69
  484. package/src/providers/claude/durable/ClaudeStreamParser.ts +91 -62
  485. package/src/providers/codex/CodexAdapter.ts +205 -0
  486. package/src/providers/codex/CodexAgentMapper.ts +35 -0
  487. package/src/providers/codex/CodexSessionLocator.ts +279 -0
  488. package/src/providers/codex/CodexSessionMapping.ts +89 -0
  489. package/src/providers/codex/CodexSessionParser.ts +385 -0
  490. package/src/providers/codex/durable/CodexCliProbe.ts +50 -42
  491. package/src/providers/codex/durable/CodexPrintAgentService.ts +63 -49
  492. package/src/providers/codex/durable/CodexPrintRunner.ts +79 -69
  493. package/src/providers/codex/durable/CodexStreamParser.ts +97 -84
  494. package/src/providers/copilot/CopilotAdapter.ts +145 -0
  495. package/src/providers/copilot/CopilotAgentMapper.ts +36 -0
  496. package/src/providers/copilot/CopilotSessionLocator.ts +57 -0
  497. package/src/providers/copilot/CopilotSessionParser.ts +289 -0
  498. package/src/providers/gemini/GeminiAgentMapper.ts +36 -0
  499. package/src/providers/gemini/GeminiCliAdapter.ts +266 -0
  500. package/src/providers/gemini/GeminiSessionLocator.ts +183 -0
  501. package/src/providers/gemini/GeminiSessionParser.ts +271 -0
  502. package/src/providers/pi/PiAdapter.ts +183 -0
  503. package/src/providers/pi/PiAgentMapper.ts +36 -0
  504. package/src/providers/pi/PiSessionLocator.ts +95 -0
  505. package/src/providers/pi/PiSessionParser.ts +284 -0
  506. package/src/providers/pi/PiSessionTracker.ts +87 -0
  507. package/src/providers/pi/durable/PiCliProbe.ts +42 -34
  508. package/src/providers/pi/durable/PiPrintAgentService.ts +61 -53
  509. package/src/providers/pi/durable/PiPrintProtocol.ts +31 -29
  510. package/src/providers/pi/durable/PiPrintRunner.ts +75 -68
  511. package/src/providers/pi/durable/PiStreamParser.ts +82 -72
  512. package/src/readiness/AgentReadiness.ts +585 -513
  513. package/src/runtime/ManagedAgentRuntime.ts +266 -0
  514. package/src/runtime/RuntimeFactory.ts +13 -0
  515. package/src/runtime/errors.ts +50 -0
  516. package/src/runtime/herdr/HerdrAgentDiscovery.ts +178 -0
  517. package/src/runtime/herdr/HerdrAgentRuntime.ts +216 -0
  518. package/src/runtime/herdr/HerdrCliClient.ts +78 -0
  519. package/src/runtime/herdr/HerdrErrors.ts +9 -0
  520. package/src/runtime/herdr/HerdrResponseParsers.ts +86 -0
  521. package/src/runtime/herdr/HerdrRuntimeRef.ts +41 -0
  522. package/src/runtime/tmux/PidPolling.ts +34 -0
  523. package/src/runtime/tmux/TmuxAgentRuntime.ts +113 -0
  524. package/src/runtime/tmux/TmuxRuntimeRef.ts +9 -0
  525. package/src/runtime/types.ts +56 -0
  526. package/src/terminal/TerminalFocusManager.ts +215 -212
  527. package/src/terminal/TmuxManager.ts +99 -92
  528. package/src/terminal/TtyWriter.ts +203 -194
  529. package/src/terminal/index.ts +4 -4
  530. package/src/utils/AgentRegistry.ts +301 -238
  531. package/src/utils/agent-requests.ts +16 -16
  532. package/src/utils/agents.ts +41 -38
  533. package/src/utils/applescript.ts +4 -4
  534. package/src/utils/index.ts +12 -6
  535. package/src/utils/matching.ts +43 -43
  536. package/src/utils/process.ts +261 -258
  537. package/src/utils/session.ts +66 -66
  538. package/src/utils/sortAgents.ts +35 -33
  539. package/tsconfig.json +2 -8
  540. package/vitest.config.ts +16 -16
  541. package/.eslintrc.json +0 -31
  542. package/dist/__tests__/adapters/CopilotAdapter.test.js +0 -630
  543. package/dist/__tests__/adapters/CopilotAdapter.test.js.map +0 -1
  544. package/dist/__tests__/adapters/GeminiCliAdapter.test.js +0 -1384
  545. package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +0 -1
  546. package/dist/__tests__/adapters/PiAdapter.test.js +0 -618
  547. package/dist/__tests__/adapters/PiAdapter.test.js.map +0 -1
  548. package/dist/__tests__/database/DurableAgentsDatabase.test.js +0 -128
  549. package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +0 -1
  550. package/dist/adapters/CodexAdapter.d.ts +0 -109
  551. package/dist/adapters/CodexAdapter.d.ts.map +0 -1
  552. package/dist/adapters/CodexAdapter.js +0 -710
  553. package/dist/adapters/CodexAdapter.js.map +0 -1
  554. package/dist/adapters/CopilotAdapter.d.ts.map +0 -1
  555. package/dist/adapters/CopilotAdapter.js +0 -329
  556. package/dist/adapters/CopilotAdapter.js.map +0 -1
  557. package/dist/adapters/GeminiCliAdapter.d.ts +0 -98
  558. package/dist/adapters/GeminiCliAdapter.d.ts.map +0 -1
  559. package/dist/adapters/GeminiCliAdapter.js +0 -513
  560. package/dist/adapters/GeminiCliAdapter.js.map +0 -1
  561. package/dist/adapters/PiAdapter.d.ts +0 -63
  562. package/dist/adapters/PiAdapter.d.ts.map +0 -1
  563. package/dist/adapters/PiAdapter.js +0 -453
  564. package/dist/adapters/PiAdapter.js.map +0 -1
  565. package/src/__tests__/adapters/CopilotAdapter.test.ts +0 -510
  566. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +0 -1259
  567. package/src/__tests__/adapters/PiAdapter.test.ts +0 -458
  568. package/src/__tests__/database/DurableAgentsDatabase.test.ts +0 -102
  569. package/src/adapters/CodexAdapter.ts +0 -923
  570. package/src/adapters/CopilotAdapter.ts +0 -473
  571. package/src/adapters/GeminiCliAdapter.ts +0 -701
  572. package/src/adapters/PiAdapter.ts +0 -598
@@ -0,0 +1,183 @@
1
+ import * as crypto from "crypto";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import type { ProcessInfo } from "../../adapters/AgentAdapter.js";
5
+ import type { SessionFile } from "../../utils/session.js";
6
+ import { isDirectory, safeReaddir } from "../../utils/session.js";
7
+
8
+ export interface GeminiSessionDiscovery {
9
+ sessions: SessionFile[];
10
+ contentCache: Map<string, string>;
11
+ }
12
+
13
+ export interface GeminiSessionLocatorOptions {
14
+ geminiTmpDir?: string;
15
+ }
16
+
17
+ interface GeminiSessionMetadata {
18
+ sessionId?: string;
19
+ projectHash?: string;
20
+ }
21
+
22
+ const SESSION_FILE_PREFIX = "session-";
23
+ const CHATS_DIR_NAME = "chats";
24
+
25
+ export class GeminiSessionLocator {
26
+ private readonly geminiTmpDir: string;
27
+
28
+ constructor(options: GeminiSessionLocatorOptions = {}) {
29
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
30
+ this.geminiTmpDir = options.geminiTmpDir ?? path.join(homeDir, ".gemini", "tmp");
31
+ }
32
+
33
+ /**
34
+ * Discover session files for the given processes.
35
+ *
36
+ * Gemini CLI writes sessions to ~/.gemini/tmp/<shortId>/chats/session-*.json
37
+ * where <shortId> is opaque (managed by a project registry). We scan every
38
+ * shortId directory and filter by matching session.projectHash against
39
+ * sha256(process.cwd) to bind each session to a candidate process CWD.
40
+ */
41
+ discoverSessions(processes: ProcessInfo[]): GeminiSessionDiscovery {
42
+ const empty = { sessions: [] as SessionFile[], contentCache: new Map<string, string>() };
43
+ if (!fs.existsSync(this.geminiTmpDir)) return empty;
44
+
45
+ const cwdHashMap = this.buildCwdHashMap(processes);
46
+ if (cwdHashMap.size === 0) return empty;
47
+
48
+ const contentCache = new Map<string, string>();
49
+ const sessions: SessionFile[] = [];
50
+
51
+ let shortIdEntries: string[];
52
+ try {
53
+ shortIdEntries = fs.readdirSync(this.geminiTmpDir);
54
+ } catch {
55
+ return empty;
56
+ }
57
+
58
+ for (const shortId of shortIdEntries) {
59
+ const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);
60
+ if (!isDirectory(chatsDir)) continue;
61
+
62
+ for (const fileName of safeReaddir(chatsDir)) {
63
+ if (!this.isSessionFile(fileName)) continue;
64
+
65
+ const session = this.readCandidateSession(chatsDir, fileName, cwdHashMap);
66
+ if (!session) continue;
67
+
68
+ contentCache.set(session.filePath, session.content);
69
+ sessions.push(session.sessionFile);
70
+ }
71
+ }
72
+
73
+ return { sessions, contentCache };
74
+ }
75
+
76
+ discoverHistoricalSessionFiles(): string[] {
77
+ if (!isDirectory(this.geminiTmpDir)) return [];
78
+
79
+ const files: string[] = [];
80
+ for (const shortId of safeReaddir(this.geminiTmpDir)) {
81
+ const chatsDir = path.join(this.geminiTmpDir, shortId, CHATS_DIR_NAME);
82
+ if (!isDirectory(chatsDir)) continue;
83
+
84
+ for (const fileName of safeReaddir(chatsDir)) {
85
+ if (this.isSessionFile(fileName)) {
86
+ files.push(path.join(chatsDir, fileName));
87
+ }
88
+ }
89
+ }
90
+
91
+ return files;
92
+ }
93
+
94
+ private readCandidateSession(
95
+ chatsDir: string,
96
+ fileName: string,
97
+ cwdHashMap: Map<string, string>,
98
+ ): { filePath: string; content: string; sessionFile: SessionFile } | null {
99
+ const filePath = path.join(chatsDir, fileName);
100
+
101
+ let content: string;
102
+ try {
103
+ content = fs.readFileSync(filePath, "utf-8");
104
+ } catch {
105
+ return null;
106
+ }
107
+
108
+ const parsed = this.parseSessionMetadata(content);
109
+ if (!parsed?.projectHash) return null;
110
+
111
+ const resolvedCwd = cwdHashMap.get(parsed.projectHash);
112
+ if (!resolvedCwd) return null;
113
+
114
+ let birthtimeMs = 0;
115
+ try {
116
+ birthtimeMs = fs.statSync(filePath).birthtimeMs;
117
+ } catch {
118
+ return null;
119
+ }
120
+
121
+ return {
122
+ filePath,
123
+ content,
124
+ sessionFile: {
125
+ sessionId: parsed.sessionId || fileName.replace(/\.json$/, ""),
126
+ filePath,
127
+ projectDir: chatsDir,
128
+ birthtimeMs,
129
+ resolvedCwd,
130
+ },
131
+ };
132
+ }
133
+
134
+ private buildCwdHashMap(processes: ProcessInfo[]): Map<string, string> {
135
+ const map = new Map<string, string>();
136
+ for (const proc of processes) {
137
+ if (!proc.cwd) continue;
138
+
139
+ // Gemini CLI resolves its project root by walking up from the
140
+ // startup directory looking for a `.git` boundary marker. A
141
+ // session's projectHash therefore tracks that ancestor rather
142
+ // than the process' actual CWD. Enumerate every ancestor as a
143
+ // candidate so subdirectory invocations still line up with the
144
+ // session the Gemini process wrote.
145
+ for (const candidate of this.candidateProjectRoots(proc.cwd)) {
146
+ const hash = this.hashProjectRoot(candidate);
147
+ if (!map.has(hash)) {
148
+ map.set(hash, proc.cwd);
149
+ }
150
+ }
151
+ }
152
+ return map;
153
+ }
154
+
155
+ private candidateProjectRoots(cwd: string): string[] {
156
+ const roots: string[] = [];
157
+ let current = path.resolve(cwd);
158
+ let parent = path.dirname(current);
159
+ while (parent !== current) {
160
+ roots.push(current);
161
+ current = parent;
162
+ parent = path.dirname(current);
163
+ }
164
+ roots.push(current);
165
+ return roots;
166
+ }
167
+
168
+ private hashProjectRoot(projectRoot: string): string {
169
+ return crypto.createHash("sha256").update(projectRoot).digest("hex");
170
+ }
171
+
172
+ private isSessionFile(fileName: string): boolean {
173
+ return fileName.startsWith(SESSION_FILE_PREFIX) && fileName.endsWith(".json");
174
+ }
175
+
176
+ private parseSessionMetadata(content: string): GeminiSessionMetadata | null {
177
+ try {
178
+ return JSON.parse(content) as GeminiSessionMetadata;
179
+ } catch {
180
+ return null;
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,271 @@
1
+ import * as fs from "fs";
2
+ import type { ConversationMessage, SessionSummary } from "../../adapters/AgentAdapter.js";
3
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
4
+ import { safeReadFile, safeStat } from "../../utils/session.js";
5
+
6
+ /**
7
+ * A single Gemini CLI message content part. Mirrors the `{text?: string}`
8
+ * shape that Gemini writes for user message parts (derived from the
9
+ * Gemini API `Content.parts[]` schema). Non-text part variants (data,
10
+ * file, etc.) are preserved via the index signature but ignored by
11
+ * `resolveContent` since the adapter only surfaces human-readable text.
12
+ */
13
+ interface GeminiContentPart {
14
+ text?: string;
15
+ [key: string]: unknown;
16
+ }
17
+
18
+ type GeminiMessageContent = string | GeminiContentPart[];
19
+
20
+ export interface GeminiMessageEntry {
21
+ id?: string;
22
+ timestamp?: string;
23
+ type?: string;
24
+ /**
25
+ * Gemini CLI stores two different content shapes depending on the
26
+ * message origin:
27
+ * - `type: "user"` messages carry the raw Part[] from userContent.parts
28
+ * (e.g. `[{ text: "hello" }]`).
29
+ * - `type: "gemini"` (assistant) messages carry a pre-joined string
30
+ * built from `consolidatedParts.filter(p => p.text).join('').trim()`.
31
+ * Both forms must be normalized via resolveContent before any string
32
+ * operation is applied.
33
+ */
34
+ content?: GeminiMessageContent;
35
+ displayContent?: GeminiMessageContent;
36
+ }
37
+
38
+ export interface GeminiSessionFile {
39
+ sessionId?: string;
40
+ projectHash?: string;
41
+ startTime?: string;
42
+ lastUpdated?: string;
43
+ messages?: GeminiMessageEntry[];
44
+ directories?: string[];
45
+ kind?: string;
46
+ }
47
+
48
+ export interface GeminiSession {
49
+ sessionId: string;
50
+ projectPath: string;
51
+ summary: string;
52
+ sessionStart: Date;
53
+ lastActive: Date;
54
+ lastMessageType?: string;
55
+ }
56
+
57
+ const IDLE_THRESHOLD_MINUTES = 5;
58
+
59
+ export class GeminiSessionParser {
60
+ /**
61
+ * Parse session file content into GeminiSession.
62
+ * Uses cached content if available, otherwise reads from disk.
63
+ */
64
+ parseSession(cachedContent: string | undefined, filePath: string): GeminiSession | null {
65
+ const content = cachedContent ?? this.readSessionFile(filePath);
66
+ if (content === null) return null;
67
+
68
+ const parsed = this.parseSessionJson(content);
69
+ if (!parsed?.sessionId) return null;
70
+
71
+ const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
72
+ const lastEntry = messages.length > 0 ? messages[messages.length - 1] : undefined;
73
+ const fileStat = safeStat(filePath);
74
+
75
+ const lastActive =
76
+ this.parseTimestamp(parsed.lastUpdated) ||
77
+ this.parseTimestamp(lastEntry?.timestamp) ||
78
+ fileStat?.mtime ||
79
+ new Date();
80
+
81
+ const sessionStart = this.parseTimestamp(parsed.startTime) || lastActive;
82
+ const projectPath =
83
+ Array.isArray(parsed.directories) && parsed.directories.length > 0
84
+ ? parsed.directories[0]
85
+ : "";
86
+
87
+ return {
88
+ sessionId: parsed.sessionId,
89
+ projectPath,
90
+ summary: this.extractSummary(messages),
91
+ sessionStart,
92
+ lastActive,
93
+ lastMessageType: lastEntry?.type,
94
+ };
95
+ }
96
+
97
+ determineStatus(session: GeminiSession): AgentStatus {
98
+ const diffMs = Date.now() - session.lastActive.getTime();
99
+ const diffMinutes = diffMs / 60000;
100
+
101
+ if (diffMinutes > IDLE_THRESHOLD_MINUTES) {
102
+ return AgentStatus.IDLE;
103
+ }
104
+
105
+ if (session.lastMessageType === "gemini" || session.lastMessageType === "assistant") {
106
+ return AgentStatus.WAITING;
107
+ }
108
+
109
+ return AgentStatus.RUNNING;
110
+ }
111
+
112
+ /**
113
+ * Read the full conversation from a Gemini CLI session JSON file.
114
+ *
115
+ * Gemini sessions store messages in an array with `type` field — typically
116
+ * 'user' or 'gemini' for visible turns, with tool and system entries mixed in.
117
+ */
118
+ getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {
119
+ const verbose = options?.verbose ?? false;
120
+ const content = safeReadFile(sessionFilePath);
121
+ if (content === undefined) return [];
122
+
123
+ const parsed = this.parseSessionJson(content);
124
+ if (!Array.isArray(parsed?.messages)) return [];
125
+
126
+ const messages: ConversationMessage[] = [];
127
+ for (const entry of parsed.messages) {
128
+ const role = this.roleForEntry(entry?.type, verbose);
129
+ if (!role) continue;
130
+
131
+ const text = this.messageText(entry).trim();
132
+ if (!text) continue;
133
+
134
+ messages.push({
135
+ role,
136
+ content: text,
137
+ timestamp: entry.timestamp,
138
+ });
139
+ }
140
+
141
+ return messages;
142
+ }
143
+
144
+ /**
145
+ * Read a Gemini session JSON file and produce a {@link SessionSummary}.
146
+ * Returns null when the file is unreadable, the JSON doesn't parse,
147
+ * or the body lacks a sessionId.
148
+ */
149
+ fileToSessionSummary(filePath: string): SessionSummary | null {
150
+ const content = safeReadFile(filePath);
151
+ if (content === undefined) return null;
152
+
153
+ const parsed = this.parseSessionJson(content);
154
+ if (!parsed?.sessionId) return null;
155
+
156
+ const messages = Array.isArray(parsed.messages) ? parsed.messages : [];
157
+ const firstUserMessage = this.extractFirstUserMessage(messages);
158
+ const cwd =
159
+ Array.isArray(parsed.directories) && parsed.directories.length > 0
160
+ ? parsed.directories[0]
161
+ : "";
162
+
163
+ const stat = safeStat(filePath);
164
+ const lastEntryTimestamp = this.parseTimestamp(
165
+ messages.length > 0 ? messages[messages.length - 1]?.timestamp : undefined,
166
+ );
167
+ const lastActive =
168
+ this.parseTimestamp(parsed.lastUpdated) || lastEntryTimestamp || stat?.mtime || new Date();
169
+ const startedAt =
170
+ this.parseTimestamp(parsed.startTime) || stat?.birthtime || stat?.mtime || lastActive;
171
+
172
+ return {
173
+ type: "gemini_cli",
174
+ sessionId: parsed.sessionId,
175
+ cwd,
176
+ firstUserMessage,
177
+ lastActive,
178
+ startedAt,
179
+ sessionFilePath: filePath,
180
+ };
181
+ }
182
+
183
+ private parseSessionJson(content: string): GeminiSessionFile | null {
184
+ try {
185
+ return JSON.parse(content) as GeminiSessionFile;
186
+ } catch {
187
+ return null;
188
+ }
189
+ }
190
+
191
+ private readSessionFile(filePath: string): string | null {
192
+ try {
193
+ return fs.readFileSync(filePath, "utf-8");
194
+ } catch {
195
+ return null;
196
+ }
197
+ }
198
+
199
+ private roleForEntry(
200
+ entryType: string | undefined,
201
+ verbose: boolean,
202
+ ): ConversationMessage["role"] | null {
203
+ if (entryType === "user") return "user";
204
+ if (entryType === "gemini" || entryType === "assistant") return "assistant";
205
+ if (verbose && entryType) return "system";
206
+ return null;
207
+ }
208
+
209
+ private extractSummary(messages: GeminiMessageEntry[]): string {
210
+ for (let i = messages.length - 1; i >= 0; i--) {
211
+ const entry = messages[i];
212
+ if (entry?.type !== "user") continue;
213
+ const text = this.messageText(entry).trim();
214
+ if (text) return this.truncate(text, 120);
215
+ }
216
+
217
+ return "Gemini CLI session active";
218
+ }
219
+
220
+ /**
221
+ * Normalize an entry's content/displayContent into a plain string.
222
+ * Prefers displayContent when both are present (matches Gemini CLI's
223
+ * own rendering priority for the /chat UI).
224
+ */
225
+ private messageText(entry: GeminiMessageEntry): string {
226
+ const displayText = this.resolveContent(entry.displayContent);
227
+ if (displayText) return displayText;
228
+ return this.resolveContent(entry.content);
229
+ }
230
+
231
+ /**
232
+ * Collapse a Gemini message content field into plain text.
233
+ * Accepts either a pre-joined string (assistant turns) or a Part[]
234
+ * list (user turns carrying `[{text: "..."}]`). Non-text part
235
+ * variants (data, file) are dropped since this helper is only used
236
+ * for summary/conversation rendering.
237
+ */
238
+ private resolveContent(content: GeminiMessageContent | undefined): string {
239
+ if (!content) return "";
240
+ if (typeof content === "string") return content;
241
+ if (!Array.isArray(content)) return "";
242
+
243
+ const parts: string[] = [];
244
+ for (const part of content) {
245
+ if (part && typeof part.text === "string" && part.text) {
246
+ parts.push(part.text);
247
+ }
248
+ }
249
+ return parts.join("");
250
+ }
251
+
252
+ private extractFirstUserMessage(messages: GeminiMessageEntry[]): string {
253
+ for (const entry of messages) {
254
+ if (entry?.type !== "user") continue;
255
+ const text = this.messageText(entry).trim();
256
+ if (text) return text;
257
+ }
258
+ return "";
259
+ }
260
+
261
+ private parseTimestamp(value?: string): Date | null {
262
+ if (!value) return null;
263
+ const timestamp = new Date(value);
264
+ return Number.isNaN(timestamp.getTime()) ? null : timestamp;
265
+ }
266
+
267
+ private truncate(value: string, maxLength: number): string {
268
+ if (value.length <= maxLength) return value;
269
+ return `${value.slice(0, maxLength - 3)}...`;
270
+ }
271
+ }
@@ -0,0 +1,183 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import type {
4
+ AgentAdapter,
5
+ AgentInfo,
6
+ ProcessInfo,
7
+ ConversationMessage,
8
+ SessionSummary,
9
+ ListSessionsOptions,
10
+ AgentDetectionContext,
11
+ } from "../../adapters/AgentAdapter.js";
12
+ import {
13
+ captureProcessSnapshot,
14
+ executableBasename,
15
+ filterByProcessNames,
16
+ } from "../../utils/process.js";
17
+ import { AgentRegistry } from "../../utils/AgentRegistry.js";
18
+ import { PiAgentMapper } from "./PiAgentMapper.js";
19
+ import { PiSessionLocator } from "./PiSessionLocator.js";
20
+ import { PiSessionParser } from "./PiSessionParser.js";
21
+ import { PiSessionTracker } from "./PiSessionTracker.js";
22
+
23
+ interface MappedAgentResult {
24
+ agents: AgentInfo[];
25
+ fallback: ProcessInfo[];
26
+ }
27
+
28
+ interface SessionFileMatch {
29
+ process: ProcessInfo;
30
+ filePath: string;
31
+ }
32
+
33
+ export class PiAdapter implements AgentAdapter {
34
+ readonly type = "pi" as const;
35
+ readonly processNames = ["pi", "node"] as const;
36
+
37
+ private readonly piSessionsDir: string;
38
+ private readonly trackerPath: string;
39
+ private readonly registry: AgentRegistry;
40
+ private readonly parser: PiSessionParser;
41
+ private readonly mapper: PiAgentMapper;
42
+
43
+ constructor(registry: AgentRegistry = AgentRegistry.default()) {
44
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "";
45
+ const piAgentDir = path.join(homeDir, ".pi", "agent");
46
+ this.piSessionsDir = path.join(piAgentDir, "sessions");
47
+ this.trackerPath = path.join(piAgentDir, "sessions.json");
48
+ this.registry = registry;
49
+ this.parser = new PiSessionParser();
50
+ this.mapper = new PiAgentMapper(this.parser);
51
+ }
52
+
53
+ canHandle(processInfo: ProcessInfo): boolean {
54
+ return this.isPiExecutable(processInfo.command);
55
+ }
56
+
57
+ async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {
58
+ const processes = await this.getPiProcesses(context);
59
+ if (processes.length === 0) return [];
60
+
61
+ const cacheResult = this.mapRegistryCache(processes);
62
+ const trackerResult = this.mapTrackerMatches(cacheResult.fallback);
63
+ const locatorResult = this.createLocator().matchRunningProcesses(trackerResult.fallback);
64
+ const legacyResult = this.mapLegacyMatches(locatorResult.legacyMatches);
65
+ const unmatchedProcesses = this.findUnmatchedProcesses(
66
+ locatorResult.fallback,
67
+ legacyResult.agents,
68
+ );
69
+
70
+ return [
71
+ ...cacheResult.agents,
72
+ ...trackerResult.agents,
73
+ ...legacyResult.agents,
74
+ ...unmatchedProcesses.map((processInfo) => this.mapper.mapProcessOnlyAgent(processInfo)),
75
+ ];
76
+ }
77
+
78
+ getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {
79
+ return this.parser.getConversation(sessionFilePath, options);
80
+ }
81
+
82
+ async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {
83
+ const summaries: SessionSummary[] = [];
84
+
85
+ for (const filePath of this.createLocator().discoverHistoricalSessionFiles()) {
86
+ const summary = this.parser.fileToSessionSummary(filePath);
87
+ if (!summary) continue;
88
+ if (opts?.cwd !== undefined && summary.cwd !== opts.cwd) continue;
89
+ summaries.push(summary);
90
+ }
91
+
92
+ return summaries;
93
+ }
94
+
95
+ private async getPiProcesses(context?: AgentDetectionContext): Promise<ProcessInfo[]> {
96
+ const snapshot = context?.processes ?? (await captureProcessSnapshot(this.processNames));
97
+ const relevant = filterByProcessNames(snapshot, this.processNames);
98
+
99
+ const byPid = new Map<number, ProcessInfo>();
100
+ for (const processInfo of relevant) {
101
+ if (this.canHandle(processInfo)) byPid.set(processInfo.pid, processInfo);
102
+ }
103
+ return Array.from(byPid.values());
104
+ }
105
+
106
+ private createLocator(): PiSessionLocator {
107
+ return new PiSessionLocator({ sessionsDir: this.piSessionsDir }, this.parser);
108
+ }
109
+
110
+ private createTracker(): PiSessionTracker {
111
+ return new PiSessionTracker({
112
+ sessionsDir: this.piSessionsDir,
113
+ trackerPath: this.trackerPath,
114
+ });
115
+ }
116
+
117
+ private mapRegistryCache(processes: ProcessInfo[]): MappedAgentResult {
118
+ const matches: SessionFileMatch[] = [];
119
+ const fallback: ProcessInfo[] = [];
120
+ const byPid = new Map(this.registry.list().map((entry) => [entry.pid, entry]));
121
+
122
+ for (const processInfo of processes) {
123
+ const entry = byPid.get(processInfo.pid);
124
+ if (
125
+ !entry ||
126
+ entry.type !== this.type ||
127
+ !entry.sessionFilePath ||
128
+ !fs.existsSync(entry.sessionFilePath)
129
+ ) {
130
+ fallback.push(processInfo);
131
+ continue;
132
+ }
133
+
134
+ matches.push({ process: processInfo, filePath: entry.sessionFilePath });
135
+ }
136
+
137
+ const mapped = this.mapSessionFileMatches(matches);
138
+ return { agents: mapped.agents, fallback: [...fallback, ...mapped.fallback] };
139
+ }
140
+
141
+ private mapTrackerMatches(processes: ProcessInfo[]): MappedAgentResult {
142
+ const { matches, fallback } = this.createTracker().match(processes);
143
+ const mapped = this.mapSessionFileMatches(matches);
144
+ return { agents: mapped.agents, fallback: [...fallback, ...mapped.fallback] };
145
+ }
146
+
147
+ private mapLegacyMatches(
148
+ matches: Array<{ process: ProcessInfo; session: { filePath: string } }>,
149
+ ): MappedAgentResult {
150
+ return this.mapSessionFileMatches(
151
+ matches.map((match) => ({ process: match.process, filePath: match.session.filePath })),
152
+ );
153
+ }
154
+
155
+ private mapSessionFileMatches(matches: SessionFileMatch[]): MappedAgentResult {
156
+ const agents: AgentInfo[] = [];
157
+ const fallback: ProcessInfo[] = [];
158
+
159
+ for (const match of matches) {
160
+ const session = this.parser.readSession(match.filePath, match.process.cwd);
161
+ if (session) {
162
+ agents.push(this.mapper.mapSessionToAgent(session, match.process, match.filePath));
163
+ } else {
164
+ fallback.push(match.process);
165
+ }
166
+ }
167
+
168
+ return { agents, fallback };
169
+ }
170
+
171
+ private findUnmatchedProcesses(processes: ProcessInfo[], agents: AgentInfo[]): ProcessInfo[] {
172
+ const matchedPids = new Set(agents.map((agent) => agent.pid));
173
+ return processes.filter((processInfo) => !matchedPids.has(processInfo.pid));
174
+ }
175
+
176
+ private isPiExecutable(command: string): boolean {
177
+ for (const token of command.trim().split(/\s+/)) {
178
+ const base = executableBasename(token);
179
+ if (base === "pi" || base === "pi.exe" || base === "pi.js") return true;
180
+ }
181
+ return false;
182
+ }
183
+ }
@@ -0,0 +1,36 @@
1
+ import type { AgentInfo, ProcessInfo } from "../../adapters/AgentAdapter.js";
2
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
3
+ import { generateAgentName } from "../../utils/matching.js";
4
+ import { type PiSession, PiSessionParser } from "./PiSessionParser.js";
5
+
6
+ export class PiAgentMapper {
7
+ constructor(private readonly parser: PiSessionParser = new PiSessionParser()) {}
8
+
9
+ mapSessionToAgent(session: PiSession, processInfo: ProcessInfo, filePath: string): AgentInfo {
10
+ const projectPath = session.projectPath || processInfo.cwd || "";
11
+ return {
12
+ name: generateAgentName(projectPath, processInfo.pid),
13
+ type: "pi",
14
+ status: this.parser.determineStatus(session),
15
+ summary: session.summary || "Pi session active",
16
+ pid: processInfo.pid,
17
+ projectPath,
18
+ sessionId: session.sessionId,
19
+ lastActive: session.lastActive,
20
+ sessionFilePath: filePath,
21
+ };
22
+ }
23
+
24
+ mapProcessOnlyAgent(processInfo: ProcessInfo): AgentInfo {
25
+ return {
26
+ name: generateAgentName(processInfo.cwd || "", processInfo.pid),
27
+ type: "pi",
28
+ status: AgentStatus.RUNNING,
29
+ summary: "Pi process running",
30
+ pid: processInfo.pid,
31
+ projectPath: processInfo.cwd || "",
32
+ sessionId: `pid-${processInfo.pid}`,
33
+ lastActive: new Date(),
34
+ };
35
+ }
36
+ }