@ai-devkit/agent-manager 0.31.0 → 0.33.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 (519) hide show
  1. package/dist/AgentManager.d.ts +3 -3
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +80 -79
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +413 -388
  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/CopilotAdapter.test.js +254 -248
  12. package/dist/__tests__/adapters/CopilotAdapter.test.js.map +1 -1
  13. package/dist/__tests__/adapters/GeminiCliAdapter.test.js +564 -558
  14. package/dist/__tests__/adapters/GeminiCliAdapter.test.js.map +1 -1
  15. package/dist/__tests__/adapters/GrokCliAdapter.test.js +114 -114
  16. package/dist/__tests__/adapters/GrokCliAdapter.test.js.map +1 -1
  17. package/dist/__tests__/adapters/OpenCodeAdapter.test.js +169 -169
  18. package/dist/__tests__/adapters/OpenCodeAdapter.test.js.map +1 -1
  19. package/dist/__tests__/capacity/codex.test.js +93 -93
  20. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  21. package/dist/__tests__/capacity/index.test.js +17 -17
  22. package/dist/__tests__/capacity/index.test.js.map +1 -1
  23. package/dist/__tests__/durable/CodexCliProbe.test.js +60 -60
  24. package/dist/__tests__/durable/CodexCliProbe.test.js.map +1 -1
  25. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +28 -28
  26. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +1 -1
  27. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +30 -30
  28. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +1 -1
  29. package/dist/__tests__/durable/CodexPrintAgentService.test.js +71 -71
  30. package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +1 -1
  31. package/dist/__tests__/durable/CodexPrintRunner.test.js +125 -125
  32. package/dist/__tests__/durable/CodexPrintRunner.test.js.map +1 -1
  33. package/dist/__tests__/print/ClaudeCliProbe.test.js +20 -20
  34. package/dist/__tests__/print/ClaudeCliProbe.test.js.map +1 -1
  35. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +20 -20
  36. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +1 -1
  37. package/dist/__tests__/print/ClaudePrintAgentService.test.js +58 -58
  38. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +1 -1
  39. package/dist/__tests__/print/ClaudePrintRunner.test.js +55 -55
  40. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +1 -1
  41. package/dist/__tests__/print/DurableAgent.test.js +9 -9
  42. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  43. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js +40 -40
  44. package/dist/__tests__/print/DurableAgentRepository.sqlite.test.js.map +1 -1
  45. package/dist/__tests__/print/DurableAgentRepository.test.js +66 -66
  46. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  47. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +34 -34
  48. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +1 -1
  49. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +132 -132
  50. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +1 -1
  51. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +194 -0
  52. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +1 -0
  53. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +86 -0
  54. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +1 -0
  55. package/dist/__tests__/providers/codex/CodexSessionParser.test.js +254 -0
  56. package/dist/__tests__/providers/codex/CodexSessionParser.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 +301 -0
  76. package/dist/__tests__/readiness/AgentReadiness.test.js.map +1 -0
  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/HerdrAgentRuntime.test.js +452 -0
  80. package/dist/__tests__/runtime/HerdrAgentRuntime.test.js.map +1 -0
  81. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +588 -0
  82. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -0
  83. package/dist/__tests__/terminal/TerminalFocusManager.test.js +100 -100
  84. package/dist/__tests__/terminal/TerminalFocusManager.test.js.map +1 -1
  85. package/dist/__tests__/terminal/TmuxManager.test.js +101 -101
  86. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  87. package/dist/__tests__/terminal/TtyWriter.test.js +185 -185
  88. package/dist/__tests__/terminal/TtyWriter.test.js.map +1 -1
  89. package/dist/__tests__/utils/AgentRegistry.test.js +335 -217
  90. package/dist/__tests__/utils/AgentRegistry.test.js.map +1 -1
  91. package/dist/__tests__/utils/ClaudeSessionParser.test.js +103 -101
  92. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +1 -1
  93. package/dist/__tests__/utils/agent-requests.test.js +43 -43
  94. package/dist/__tests__/utils/agent-requests.test.js.map +1 -1
  95. package/dist/__tests__/utils/agents.test.js +17 -17
  96. package/dist/__tests__/utils/agents.test.js.map +1 -1
  97. package/dist/__tests__/utils/matching.test.js +92 -92
  98. package/dist/__tests__/utils/matching.test.js.map +1 -1
  99. package/dist/__tests__/utils/process.test.js +108 -108
  100. package/dist/__tests__/utils/process.test.js.map +1 -1
  101. package/dist/__tests__/utils/session.test.js +53 -53
  102. package/dist/__tests__/utils/session.test.js.map +1 -1
  103. package/dist/adapters/AgentAdapter.d.ts +2 -2
  104. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  105. package/dist/adapters/AgentAdapter.js +1 -1
  106. package/dist/adapters/AgentAdapter.js.map +1 -1
  107. package/dist/adapters/CopilotAdapter.d.ts +2 -2
  108. package/dist/adapters/CopilotAdapter.d.ts.map +1 -1
  109. package/dist/adapters/CopilotAdapter.js +51 -51
  110. package/dist/adapters/CopilotAdapter.js.map +1 -1
  111. package/dist/adapters/GeminiCliAdapter.d.ts +2 -2
  112. package/dist/adapters/GeminiCliAdapter.d.ts.map +1 -1
  113. package/dist/adapters/GeminiCliAdapter.js +86 -86
  114. package/dist/adapters/GeminiCliAdapter.js.map +1 -1
  115. package/dist/adapters/GrokCliAdapter.d.ts +1 -1
  116. package/dist/adapters/GrokCliAdapter.d.ts.map +1 -1
  117. package/dist/adapters/GrokCliAdapter.js +80 -80
  118. package/dist/adapters/GrokCliAdapter.js.map +1 -1
  119. package/dist/adapters/OpenCodeAdapter.d.ts +1 -1
  120. package/dist/adapters/OpenCodeAdapter.d.ts.map +1 -1
  121. package/dist/adapters/OpenCodeAdapter.js +37 -36
  122. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  123. package/dist/adapters/index.d.ts +9 -9
  124. package/dist/adapters/index.d.ts.map +1 -1
  125. package/dist/adapters/index.js +8 -8
  126. package/dist/adapters/index.js.map +1 -1
  127. package/dist/capacity/codex.d.ts +3 -3
  128. package/dist/capacity/codex.d.ts.map +1 -1
  129. package/dist/capacity/codex.js +57 -57
  130. package/dist/capacity/codex.js.map +1 -1
  131. package/dist/capacity/index.d.ts +3 -3
  132. package/dist/capacity/index.d.ts.map +1 -1
  133. package/dist/capacity/index.js +8 -8
  134. package/dist/capacity/index.js.map +1 -1
  135. package/dist/capacity/types.d.ts +1 -1
  136. package/dist/capacity/types.js.map +1 -1
  137. package/dist/database/connection.d.ts +1 -1
  138. package/dist/database/connection.d.ts.map +1 -1
  139. package/dist/database/connection.js +15 -15
  140. package/dist/database/connection.js.map +1 -1
  141. package/dist/database/index.d.ts +3 -3
  142. package/dist/database/index.d.ts.map +1 -1
  143. package/dist/database/index.js +2 -2
  144. package/dist/database/index.js.map +1 -1
  145. package/dist/database/migrations/005_agent_runtime.sql +2 -0
  146. package/dist/database/schema.d.ts +1 -1
  147. package/dist/database/schema.d.ts.map +1 -1
  148. package/dist/database/schema.js +7 -7
  149. package/dist/database/schema.js.map +1 -1
  150. package/dist/durable/DurableAgent.d.ts +9 -9
  151. package/dist/durable/DurableAgent.d.ts.map +1 -1
  152. package/dist/durable/DurableAgent.js +16 -16
  153. package/dist/durable/DurableAgent.js.map +1 -1
  154. package/dist/durable/DurableAgentRepository.d.ts +4 -4
  155. package/dist/durable/DurableAgentRepository.d.ts.map +1 -1
  156. package/dist/durable/DurableAgentRepository.js +49 -48
  157. package/dist/durable/DurableAgentRepository.js.map +1 -1
  158. package/dist/durable/process.d.ts +1 -1
  159. package/dist/durable/process.d.ts.map +1 -1
  160. package/dist/durable/process.js +14 -14
  161. package/dist/durable/process.js.map +1 -1
  162. package/dist/durable/run.d.ts +2 -2
  163. package/dist/durable/run.d.ts.map +1 -1
  164. package/dist/durable/run.js +6 -6
  165. package/dist/durable/run.js.map +1 -1
  166. package/dist/durable/utils.d.ts +1 -1
  167. package/dist/durable/utils.d.ts.map +1 -1
  168. package/dist/durable/utils.js +4 -4
  169. package/dist/durable/utils.js.map +1 -1
  170. package/dist/index.d.ts +46 -41
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +27 -25
  173. package/dist/index.js.map +1 -1
  174. package/dist/providers/claude/ClaudeAgentMapper.d.ts +4 -4
  175. package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +1 -1
  176. package/dist/providers/claude/ClaudeAgentMapper.js +10 -10
  177. package/dist/providers/claude/ClaudeAgentMapper.js.map +1 -1
  178. package/dist/providers/claude/ClaudeCodeAdapter.d.ts +1 -1
  179. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +1 -1
  180. package/dist/providers/claude/ClaudeCodeAdapter.js +14 -14
  181. package/dist/providers/claude/ClaudeCodeAdapter.js.map +1 -1
  182. package/dist/providers/claude/ClaudeSessionLocator.d.ts +4 -4
  183. package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +1 -1
  184. package/dist/providers/claude/ClaudeSessionLocator.js +79 -79
  185. package/dist/providers/claude/ClaudeSessionLocator.js.map +1 -1
  186. package/dist/providers/claude/ClaudeSessionParser.d.ts +2 -2
  187. package/dist/providers/claude/ClaudeSessionParser.d.ts.map +1 -1
  188. package/dist/providers/claude/ClaudeSessionParser.js +99 -99
  189. package/dist/providers/claude/ClaudeSessionParser.js.map +1 -1
  190. package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +1 -1
  191. package/dist/providers/claude/durable/ClaudeCliProbe.js +16 -16
  192. package/dist/providers/claude/durable/ClaudeCliProbe.js.map +1 -1
  193. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts +5 -5
  194. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +1 -1
  195. package/dist/providers/claude/durable/ClaudePrintAgentService.js +10 -10
  196. package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +1 -1
  197. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts +4 -4
  198. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +1 -1
  199. package/dist/providers/claude/durable/ClaudePrintRunner.js +18 -18
  200. package/dist/providers/claude/durable/ClaudePrintRunner.js.map +1 -1
  201. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts +2 -2
  202. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +1 -1
  203. package/dist/providers/claude/durable/ClaudeStreamParser.js +17 -17
  204. package/dist/providers/claude/durable/ClaudeStreamParser.js.map +1 -1
  205. package/dist/providers/codex/CodexAdapter.d.ts +27 -0
  206. package/dist/providers/codex/CodexAdapter.d.ts.map +1 -0
  207. package/dist/providers/codex/CodexAdapter.js +162 -0
  208. package/dist/providers/codex/CodexAdapter.js.map +1 -0
  209. package/dist/providers/codex/CodexAgentMapper.d.ts +9 -0
  210. package/dist/providers/codex/CodexAgentMapper.d.ts.map +1 -0
  211. package/dist/providers/codex/CodexAgentMapper.js +35 -0
  212. package/dist/providers/codex/CodexAgentMapper.js.map +1 -0
  213. package/dist/providers/codex/CodexSessionLocator.d.ts +44 -0
  214. package/dist/providers/codex/CodexSessionLocator.d.ts.map +1 -0
  215. package/dist/providers/codex/CodexSessionLocator.js +207 -0
  216. package/dist/providers/codex/CodexSessionLocator.js.map +1 -0
  217. package/dist/providers/codex/CodexSessionMapping.d.ts +23 -0
  218. package/dist/providers/codex/CodexSessionMapping.d.ts.map +1 -0
  219. package/dist/providers/codex/CodexSessionMapping.js +68 -0
  220. package/dist/providers/codex/CodexSessionMapping.js.map +1 -0
  221. package/dist/providers/codex/CodexSessionParser.d.ts +58 -0
  222. package/dist/providers/codex/CodexSessionParser.d.ts.map +1 -0
  223. package/dist/providers/codex/CodexSessionParser.js +262 -0
  224. package/dist/providers/codex/CodexSessionParser.js.map +1 -0
  225. package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +1 -1
  226. package/dist/providers/codex/durable/CodexCliProbe.js +22 -22
  227. package/dist/providers/codex/durable/CodexCliProbe.js.map +1 -1
  228. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts +6 -6
  229. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +1 -1
  230. package/dist/providers/codex/durable/CodexPrintAgentService.js +10 -10
  231. package/dist/providers/codex/durable/CodexPrintAgentService.js.map +1 -1
  232. package/dist/providers/codex/durable/CodexPrintRunner.d.ts +4 -4
  233. package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +1 -1
  234. package/dist/providers/codex/durable/CodexPrintRunner.js +20 -20
  235. package/dist/providers/codex/durable/CodexPrintRunner.js.map +1 -1
  236. package/dist/providers/codex/durable/CodexStreamParser.d.ts +2 -2
  237. package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +1 -1
  238. package/dist/providers/codex/durable/CodexStreamParser.js +21 -21
  239. package/dist/providers/codex/durable/CodexStreamParser.js.map +1 -1
  240. package/dist/providers/pi/PiAdapter.d.ts +28 -0
  241. package/dist/providers/pi/PiAdapter.d.ts.map +1 -0
  242. package/dist/providers/pi/PiAdapter.js +153 -0
  243. package/dist/providers/pi/PiAdapter.js.map +1 -0
  244. package/dist/providers/pi/PiAgentMapper.d.ts +9 -0
  245. package/dist/providers/pi/PiAgentMapper.d.ts.map +1 -0
  246. package/dist/providers/pi/PiAgentMapper.js +37 -0
  247. package/dist/providers/pi/PiAgentMapper.js.map +1 -0
  248. package/dist/providers/pi/PiSessionLocator.d.ts +23 -0
  249. package/dist/providers/pi/PiSessionLocator.d.ts.map +1 -0
  250. package/dist/providers/pi/PiSessionLocator.js +79 -0
  251. package/dist/providers/pi/PiSessionLocator.js.map +1 -0
  252. package/dist/providers/pi/PiSessionParser.d.ts +36 -0
  253. package/dist/providers/pi/PiSessionParser.d.ts.map +1 -0
  254. package/dist/providers/pi/PiSessionParser.js +191 -0
  255. package/dist/providers/pi/PiSessionParser.js.map +1 -0
  256. package/dist/providers/pi/PiSessionTracker.d.ts +23 -0
  257. package/dist/providers/pi/PiSessionTracker.d.ts.map +1 -0
  258. package/dist/providers/pi/PiSessionTracker.js +69 -0
  259. package/dist/providers/pi/PiSessionTracker.js.map +1 -0
  260. package/dist/providers/pi/durable/PiCliProbe.d.ts.map +1 -1
  261. package/dist/providers/pi/durable/PiCliProbe.js +15 -15
  262. package/dist/providers/pi/durable/PiCliProbe.js.map +1 -1
  263. package/dist/providers/pi/durable/PiPrintAgentService.d.ts +6 -6
  264. package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +1 -1
  265. package/dist/providers/pi/durable/PiPrintAgentService.js +10 -10
  266. package/dist/providers/pi/durable/PiPrintAgentService.js.map +1 -1
  267. package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +1 -1
  268. package/dist/providers/pi/durable/PiPrintProtocol.js +18 -18
  269. package/dist/providers/pi/durable/PiPrintProtocol.js.map +1 -1
  270. package/dist/providers/pi/durable/PiPrintRunner.d.ts +4 -4
  271. package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +1 -1
  272. package/dist/providers/pi/durable/PiPrintRunner.js +15 -15
  273. package/dist/providers/pi/durable/PiPrintRunner.js.map +1 -1
  274. package/dist/providers/pi/durable/PiStreamParser.d.ts +1 -1
  275. package/dist/providers/pi/durable/PiStreamParser.d.ts.map +1 -1
  276. package/dist/providers/pi/durable/PiStreamParser.js +16 -16
  277. package/dist/providers/pi/durable/PiStreamParser.js.map +1 -1
  278. package/dist/readiness/AgentReadiness.d.ts +67 -0
  279. package/dist/readiness/AgentReadiness.d.ts.map +1 -0
  280. package/dist/readiness/AgentReadiness.js +614 -0
  281. package/dist/readiness/AgentReadiness.js.map +1 -0
  282. package/dist/runtime/ManagedAgentRuntime.d.ts +69 -0
  283. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -0
  284. package/dist/runtime/ManagedAgentRuntime.js +156 -0
  285. package/dist/runtime/ManagedAgentRuntime.js.map +1 -0
  286. package/dist/runtime/RuntimeFactory.d.ts +4 -0
  287. package/dist/runtime/RuntimeFactory.d.ts.map +1 -0
  288. package/dist/runtime/RuntimeFactory.js +11 -0
  289. package/dist/runtime/RuntimeFactory.js.map +1 -0
  290. package/dist/runtime/errors.d.ts +27 -0
  291. package/dist/runtime/errors.d.ts.map +1 -0
  292. package/dist/runtime/errors.js +42 -0
  293. package/dist/runtime/errors.js.map +1 -0
  294. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts +31 -0
  295. package/dist/runtime/herdr/HerdrAgentRuntime.d.ts.map +1 -0
  296. package/dist/runtime/herdr/HerdrAgentRuntime.js +184 -0
  297. package/dist/runtime/herdr/HerdrAgentRuntime.js.map +1 -0
  298. package/dist/runtime/herdr/HerdrCliClient.d.ts +13 -0
  299. package/dist/runtime/herdr/HerdrCliClient.d.ts.map +1 -0
  300. package/dist/runtime/herdr/HerdrCliClient.js +60 -0
  301. package/dist/runtime/herdr/HerdrCliClient.js.map +1 -0
  302. package/dist/runtime/herdr/HerdrErrors.d.ts +7 -0
  303. package/dist/runtime/herdr/HerdrErrors.d.ts.map +1 -0
  304. package/dist/runtime/herdr/HerdrErrors.js +10 -0
  305. package/dist/runtime/herdr/HerdrErrors.js.map +1 -0
  306. package/dist/runtime/herdr/HerdrResponseParsers.d.ts +14 -0
  307. package/dist/runtime/herdr/HerdrResponseParsers.d.ts.map +1 -0
  308. package/dist/runtime/herdr/HerdrResponseParsers.js +96 -0
  309. package/dist/runtime/herdr/HerdrResponseParsers.js.map +1 -0
  310. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts +9 -0
  311. package/dist/runtime/herdr/HerdrRuntimeRef.d.ts.map +1 -0
  312. package/dist/runtime/herdr/HerdrRuntimeRef.js +33 -0
  313. package/dist/runtime/herdr/HerdrRuntimeRef.js.map +1 -0
  314. package/dist/runtime/tmux/PidPolling.d.ts +5 -0
  315. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -0
  316. package/dist/runtime/tmux/PidPolling.js +24 -0
  317. package/dist/runtime/tmux/PidPolling.js.map +1 -0
  318. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +17 -0
  319. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -0
  320. package/dist/runtime/tmux/TmuxAgentRuntime.js +80 -0
  321. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -0
  322. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts +5 -0
  323. package/dist/runtime/tmux/TmuxRuntimeRef.d.ts.map +1 -0
  324. package/dist/runtime/tmux/TmuxRuntimeRef.js +9 -0
  325. package/dist/runtime/tmux/TmuxRuntimeRef.js.map +1 -0
  326. package/dist/runtime/types.d.ts +54 -0
  327. package/dist/runtime/types.d.ts.map +1 -0
  328. package/dist/runtime/types.js +3 -0
  329. package/dist/runtime/types.js.map +1 -0
  330. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  331. package/dist/terminal/TerminalFocusManager.js +50 -50
  332. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  333. package/dist/terminal/TmuxManager.d.ts.map +1 -1
  334. package/dist/terminal/TmuxManager.js +47 -47
  335. package/dist/terminal/TmuxManager.js.map +1 -1
  336. package/dist/terminal/TtyWriter.d.ts +1 -1
  337. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  338. package/dist/terminal/TtyWriter.js +89 -89
  339. package/dist/terminal/TtyWriter.js.map +1 -1
  340. package/dist/terminal/index.d.ts +4 -4
  341. package/dist/terminal/index.js +3 -3
  342. package/dist/terminal/index.js.map +1 -1
  343. package/dist/utils/AgentRegistry.d.ts +10 -2
  344. package/dist/utils/AgentRegistry.d.ts.map +1 -1
  345. package/dist/utils/AgentRegistry.js +57 -24
  346. package/dist/utils/AgentRegistry.js.map +1 -1
  347. package/dist/utils/agent-requests.d.ts.map +1 -1
  348. package/dist/utils/agent-requests.js +5 -5
  349. package/dist/utils/agent-requests.js.map +1 -1
  350. package/dist/utils/agents.d.ts +2 -2
  351. package/dist/utils/agents.d.ts.map +1 -1
  352. package/dist/utils/agents.js +15 -15
  353. package/dist/utils/agents.js.map +1 -1
  354. package/dist/utils/applescript.js +1 -1
  355. package/dist/utils/applescript.js.map +1 -1
  356. package/dist/utils/index.d.ts +6 -6
  357. package/dist/utils/index.d.ts.map +1 -1
  358. package/dist/utils/index.js +4 -4
  359. package/dist/utils/index.js.map +1 -1
  360. package/dist/utils/matching.d.ts +2 -2
  361. package/dist/utils/matching.d.ts.map +1 -1
  362. package/dist/utils/matching.js +4 -4
  363. package/dist/utils/matching.js.map +1 -1
  364. package/dist/utils/process.d.ts +1 -1
  365. package/dist/utils/process.d.ts.map +1 -1
  366. package/dist/utils/process.js +74 -74
  367. package/dist/utils/process.js.map +1 -1
  368. package/dist/utils/session.d.ts +1 -1
  369. package/dist/utils/session.d.ts.map +1 -1
  370. package/dist/utils/session.js +7 -7
  371. package/dist/utils/session.js.map +1 -1
  372. package/dist/utils/sortAgents.d.ts +2 -2
  373. package/dist/utils/sortAgents.d.ts.map +1 -1
  374. package/dist/utils/sortAgents.js +5 -5
  375. package/dist/utils/sortAgents.js.map +1 -1
  376. package/package.json +18 -19
  377. package/src/AgentManager.ts +283 -281
  378. package/src/__tests__/AgentManager.test.ts +917 -907
  379. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +1657 -1368
  380. package/src/__tests__/adapters/CodexAdapter.test.ts +365 -1698
  381. package/src/__tests__/adapters/CopilotAdapter.test.ts +576 -481
  382. package/src/__tests__/adapters/GeminiCliAdapter.test.ts +1189 -1157
  383. package/src/__tests__/adapters/GrokCliAdapter.test.ts +325 -272
  384. package/src/__tests__/adapters/OpenCodeAdapter.test.ts +510 -455
  385. package/src/__tests__/capacity/codex.test.ts +178 -91
  386. package/src/__tests__/capacity/index.test.ts +27 -18
  387. package/src/__tests__/durable/CodexCliProbe.test.ts +75 -53
  388. package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +51 -40
  389. package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +89 -64
  390. package/src/__tests__/durable/CodexPrintAgentService.test.ts +196 -118
  391. package/src/__tests__/durable/CodexPrintRunner.test.ts +282 -162
  392. package/src/__tests__/fixtures/fake-claude.cjs +20 -13
  393. package/src/__tests__/fixtures/fake-codex.cjs +41 -30
  394. package/src/__tests__/print/ClaudeCliProbe.test.ts +27 -21
  395. package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +48 -40
  396. package/src/__tests__/print/ClaudePrintAgentService.test.ts +118 -67
  397. package/src/__tests__/print/ClaudePrintRunner.test.ts +136 -83
  398. package/src/__tests__/print/DurableAgent.test.ts +19 -16
  399. package/src/__tests__/print/DurableAgentRepository.sqlite.test.ts +109 -86
  400. package/src/__tests__/print/DurableAgentRepository.test.ts +170 -137
  401. package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +65 -65
  402. package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +400 -377
  403. package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +182 -0
  404. package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +63 -0
  405. package/src/__tests__/providers/codex/CodexSessionParser.test.ts +192 -0
  406. package/src/__tests__/providers/pi/PiAdapter.test.ts +310 -0
  407. package/src/__tests__/providers/pi/PiSessionParser.test.ts +190 -0
  408. package/src/__tests__/providers/pi/PiSessionTracker.test.ts +79 -0
  409. package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +48 -32
  410. package/src/__tests__/providers/pi/durable/PiDurableAgentRepository.test.ts +24 -23
  411. package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +131 -59
  412. package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +66 -28
  413. package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +236 -90
  414. package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +20 -18
  415. package/src/__tests__/readiness/AgentReadiness.test.ts +242 -0
  416. package/src/__tests__/runtime/AgentRuntime.test.ts +8 -0
  417. package/src/__tests__/runtime/HerdrAgentRuntime.test.ts +358 -0
  418. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +555 -0
  419. package/src/__tests__/terminal/TerminalFocusManager.test.ts +254 -253
  420. package/src/__tests__/terminal/TmuxManager.test.ts +157 -157
  421. package/src/__tests__/terminal/TtyWriter.test.ts +423 -419
  422. package/src/__tests__/utils/AgentRegistry.test.ts +506 -402
  423. package/src/__tests__/utils/ClaudeSessionParser.test.ts +276 -242
  424. package/src/__tests__/utils/agent-requests.test.ts +76 -56
  425. package/src/__tests__/utils/agents.test.ts +20 -20
  426. package/src/__tests__/utils/matching.test.ts +206 -171
  427. package/src/__tests__/utils/process.test.ts +276 -262
  428. package/src/__tests__/utils/session.test.ts +133 -139
  429. package/src/adapters/AgentAdapter.ts +134 -126
  430. package/src/adapters/CopilotAdapter.ts +405 -395
  431. package/src/adapters/GeminiCliAdapter.ts +598 -600
  432. package/src/adapters/GrokCliAdapter.ts +353 -342
  433. package/src/adapters/OpenCodeAdapter.ts +285 -259
  434. package/src/adapters/index.ts +15 -9
  435. package/src/capacity/codex.ts +137 -84
  436. package/src/capacity/index.ts +18 -13
  437. package/src/capacity/types.ts +1 -1
  438. package/src/database/connection.ts +73 -68
  439. package/src/database/index.ts +6 -6
  440. package/src/database/migrations/005_agent_runtime.sql +2 -0
  441. package/src/database/schema.ts +40 -38
  442. package/src/durable/DurableAgent.ts +85 -85
  443. package/src/durable/DurableAgentRepository.ts +409 -260
  444. package/src/durable/process.ts +22 -21
  445. package/src/durable/run.ts +61 -51
  446. package/src/durable/utils.ts +46 -41
  447. package/src/index.ts +145 -86
  448. package/src/providers/claude/ClaudeAgentMapper.ts +51 -50
  449. package/src/providers/claude/ClaudeCodeAdapter.ts +144 -136
  450. package/src/providers/claude/ClaudeSessionLocator.ts +291 -293
  451. package/src/providers/claude/ClaudeSessionParser.ts +322 -338
  452. package/src/providers/claude/durable/ClaudeCliProbe.ts +42 -37
  453. package/src/providers/claude/durable/ClaudePrintAgentService.ts +63 -50
  454. package/src/providers/claude/durable/ClaudePrintRunner.ts +79 -69
  455. package/src/providers/claude/durable/ClaudeStreamParser.ts +91 -62
  456. package/src/providers/codex/CodexAdapter.ts +205 -0
  457. package/src/providers/codex/CodexAgentMapper.ts +35 -0
  458. package/src/providers/codex/CodexSessionLocator.ts +279 -0
  459. package/src/providers/codex/CodexSessionMapping.ts +89 -0
  460. package/src/providers/codex/CodexSessionParser.ts +385 -0
  461. package/src/providers/codex/durable/CodexCliProbe.ts +50 -42
  462. package/src/providers/codex/durable/CodexPrintAgentService.ts +63 -49
  463. package/src/providers/codex/durable/CodexPrintRunner.ts +79 -69
  464. package/src/providers/codex/durable/CodexStreamParser.ts +97 -84
  465. package/src/providers/pi/PiAdapter.ts +183 -0
  466. package/src/providers/pi/PiAgentMapper.ts +36 -0
  467. package/src/providers/pi/PiSessionLocator.ts +95 -0
  468. package/src/providers/pi/PiSessionParser.ts +284 -0
  469. package/src/providers/pi/PiSessionTracker.ts +87 -0
  470. package/src/providers/pi/durable/PiCliProbe.ts +42 -34
  471. package/src/providers/pi/durable/PiPrintAgentService.ts +61 -53
  472. package/src/providers/pi/durable/PiPrintProtocol.ts +31 -29
  473. package/src/providers/pi/durable/PiPrintRunner.ts +75 -68
  474. package/src/providers/pi/durable/PiStreamParser.ts +82 -72
  475. package/src/readiness/AgentReadiness.ts +727 -0
  476. package/src/runtime/ManagedAgentRuntime.ts +266 -0
  477. package/src/runtime/RuntimeFactory.ts +13 -0
  478. package/src/runtime/errors.ts +50 -0
  479. package/src/runtime/herdr/HerdrAgentRuntime.ts +190 -0
  480. package/src/runtime/herdr/HerdrCliClient.ts +78 -0
  481. package/src/runtime/herdr/HerdrErrors.ts +9 -0
  482. package/src/runtime/herdr/HerdrResponseParsers.ts +76 -0
  483. package/src/runtime/herdr/HerdrRuntimeRef.ts +41 -0
  484. package/src/runtime/tmux/PidPolling.ts +34 -0
  485. package/src/runtime/tmux/TmuxAgentRuntime.ts +113 -0
  486. package/src/runtime/tmux/TmuxRuntimeRef.ts +9 -0
  487. package/src/runtime/types.ts +56 -0
  488. package/src/terminal/TerminalFocusManager.ts +215 -212
  489. package/src/terminal/TmuxManager.ts +99 -92
  490. package/src/terminal/TtyWriter.ts +203 -194
  491. package/src/terminal/index.ts +4 -4
  492. package/src/utils/AgentRegistry.ts +299 -238
  493. package/src/utils/agent-requests.ts +16 -16
  494. package/src/utils/agents.ts +41 -38
  495. package/src/utils/applescript.ts +4 -4
  496. package/src/utils/index.ts +12 -6
  497. package/src/utils/matching.ts +43 -43
  498. package/src/utils/process.ts +261 -258
  499. package/src/utils/session.ts +66 -66
  500. package/src/utils/sortAgents.ts +35 -33
  501. package/tsconfig.json +2 -8
  502. package/vitest.config.ts +16 -16
  503. package/.eslintrc.json +0 -31
  504. package/dist/__tests__/adapters/PiAdapter.test.js +0 -618
  505. package/dist/__tests__/adapters/PiAdapter.test.js.map +0 -1
  506. package/dist/__tests__/database/DurableAgentsDatabase.test.js +0 -128
  507. package/dist/__tests__/database/DurableAgentsDatabase.test.js.map +0 -1
  508. package/dist/adapters/CodexAdapter.d.ts +0 -109
  509. package/dist/adapters/CodexAdapter.d.ts.map +0 -1
  510. package/dist/adapters/CodexAdapter.js +0 -710
  511. package/dist/adapters/CodexAdapter.js.map +0 -1
  512. package/dist/adapters/PiAdapter.d.ts +0 -63
  513. package/dist/adapters/PiAdapter.d.ts.map +0 -1
  514. package/dist/adapters/PiAdapter.js +0 -453
  515. package/dist/adapters/PiAdapter.js.map +0 -1
  516. package/src/__tests__/adapters/PiAdapter.test.ts +0 -458
  517. package/src/__tests__/database/DurableAgentsDatabase.test.ts +0 -102
  518. package/src/adapters/CodexAdapter.ts +0 -923
  519. package/src/adapters/PiAdapter.ts +0 -598
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Tests for AgentManager
3
- */ import fs from 'fs';
4
- import os from 'os';
5
- import path from 'path';
6
- import { AgentManager } from '../AgentManager.js';
7
- import { AgentStatus } from '../adapters/AgentAdapter.js';
8
- import { AgentRegistry } from '../utils/AgentRegistry.js';
3
+ */ import fs from "fs";
4
+ import os from "os";
5
+ import path from "path";
6
+ import { AgentManager } from "../AgentManager.js";
7
+ import { AgentStatus } from "../adapters/AgentAdapter.js";
8
+ import { AgentRegistry } from "../utils/AgentRegistry.js";
9
9
  // Mock adapter for testing
10
10
  let MockAdapter = class MockAdapter {
11
11
  type;
@@ -56,23 +56,23 @@ let MockAdapter = class MockAdapter {
56
56
  // Helper to create mock agent
57
57
  function createMockAgent(overrides = {}) {
58
58
  return {
59
- name: 'test-agent',
60
- type: 'claude',
59
+ name: "test-agent",
60
+ type: "claude",
61
61
  status: AgentStatus.RUNNING,
62
- summary: 'Test summary',
62
+ summary: "Test summary",
63
63
  pid: 12345,
64
- projectPath: '/test/path',
65
- sessionId: 'test-session-id',
64
+ projectPath: "/test/path",
65
+ sessionId: "test-session-id",
66
66
  lastActive: new Date(),
67
67
  ...overrides
68
68
  };
69
69
  }
70
- describe('AgentManager', ()=>{
70
+ describe("AgentManager", ()=>{
71
71
  let manager;
72
72
  let tmpDir;
73
73
  beforeEach(()=>{
74
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-manager-'));
75
- manager = new AgentManager(new AgentRegistry(path.join(tmpDir, 'agents.json')));
74
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-manager-"));
75
+ manager = new AgentManager(new AgentRegistry(path.join(tmpDir, "agents.json")));
76
76
  });
77
77
  afterEach(()=>{
78
78
  fs.rmSync(tmpDir, {
@@ -80,51 +80,51 @@ describe('AgentManager', ()=>{
80
80
  force: true
81
81
  });
82
82
  });
83
- describe('registerAdapter', ()=>{
84
- it('should register a new adapter', ()=>{
85
- const adapter = new MockAdapter('claude');
83
+ describe("registerAdapter", ()=>{
84
+ it("should register a new adapter", ()=>{
85
+ const adapter = new MockAdapter("claude");
86
86
  manager.registerAdapter(adapter);
87
- expect(manager.hasAdapter('claude')).toBe(true);
87
+ expect(manager.hasAdapter("claude")).toBe(true);
88
88
  expect(manager.getAdapterCount()).toBe(1);
89
89
  });
90
- it('should throw error when registering duplicate adapter type', ()=>{
91
- const adapter1 = new MockAdapter('claude');
92
- const adapter2 = new MockAdapter('claude');
90
+ it("should throw error when registering duplicate adapter type", ()=>{
91
+ const adapter1 = new MockAdapter("claude");
92
+ const adapter2 = new MockAdapter("claude");
93
93
  manager.registerAdapter(adapter1);
94
94
  expect(()=>manager.registerAdapter(adapter2)).toThrow('Adapter for type "claude" is already registered');
95
95
  });
96
- it('should allow registering multiple different adapter types', ()=>{
97
- const adapter1 = new MockAdapter('claude');
98
- const adapter2 = new MockAdapter('gemini_cli');
96
+ it("should allow registering multiple different adapter types", ()=>{
97
+ const adapter1 = new MockAdapter("claude");
98
+ const adapter2 = new MockAdapter("gemini_cli");
99
99
  manager.registerAdapter(adapter1);
100
100
  manager.registerAdapter(adapter2);
101
101
  expect(manager.getAdapterCount()).toBe(2);
102
- expect(manager.hasAdapter('claude')).toBe(true);
103
- expect(manager.hasAdapter('gemini_cli')).toBe(true);
102
+ expect(manager.hasAdapter("claude")).toBe(true);
103
+ expect(manager.hasAdapter("gemini_cli")).toBe(true);
104
104
  });
105
105
  });
106
- describe('unregisterAdapter', ()=>{
107
- it('should unregister an existing adapter', ()=>{
108
- const adapter = new MockAdapter('claude');
106
+ describe("unregisterAdapter", ()=>{
107
+ it("should unregister an existing adapter", ()=>{
108
+ const adapter = new MockAdapter("claude");
109
109
  manager.registerAdapter(adapter);
110
- const removed = manager.unregisterAdapter('claude');
110
+ const removed = manager.unregisterAdapter("claude");
111
111
  expect(removed).toBe(true);
112
- expect(manager.hasAdapter('claude')).toBe(false);
112
+ expect(manager.hasAdapter("claude")).toBe(false);
113
113
  expect(manager.getAdapterCount()).toBe(0);
114
114
  });
115
- it('should return false when unregistering non-existent adapter', ()=>{
116
- const removed = manager.unregisterAdapter('NonExistent');
115
+ it("should return false when unregistering non-existent adapter", ()=>{
116
+ const removed = manager.unregisterAdapter("NonExistent");
117
117
  expect(removed).toBe(false);
118
118
  });
119
119
  });
120
- describe('getAdapters', ()=>{
121
- it('should return empty array when no adapters registered', ()=>{
120
+ describe("getAdapters", ()=>{
121
+ it("should return empty array when no adapters registered", ()=>{
122
122
  const adapters = manager.getAdapters();
123
123
  expect(adapters).toEqual([]);
124
124
  });
125
- it('should return all registered adapters', ()=>{
126
- const adapter1 = new MockAdapter('claude');
127
- const adapter2 = new MockAdapter('gemini_cli');
125
+ it("should return all registered adapters", ()=>{
126
+ const adapter1 = new MockAdapter("claude");
127
+ const adapter2 = new MockAdapter("gemini_cli");
128
128
  manager.registerAdapter(adapter1);
129
129
  manager.registerAdapter(adapter2);
130
130
  const adapters = manager.getAdapters();
@@ -133,20 +133,20 @@ describe('AgentManager', ()=>{
133
133
  expect(adapters).toContain(adapter2);
134
134
  });
135
135
  });
136
- describe('listAgents', ()=>{
137
- it('shares one process capture while giving each adapter only its declared executables', async ()=>{
136
+ describe("listAgents", ()=>{
137
+ it("shares one process capture while giving each adapter only its declared executables", async ()=>{
138
138
  const processes = [
139
139
  {
140
140
  pid: 101,
141
- command: 'claude',
142
- cwd: '/claude',
143
- tty: 's001'
141
+ command: "claude",
142
+ cwd: "/claude",
143
+ tty: "s001"
144
144
  },
145
145
  {
146
146
  pid: 202,
147
- command: 'node /bin/pi',
148
- cwd: '/pi',
149
- tty: 's002'
147
+ command: "node /bin/pi",
148
+ cwd: "/pi",
149
+ tty: "s002"
150
150
  }
151
151
  ];
152
152
  const captureSnapshot = vi.fn(async ()=>processes);
@@ -158,22 +158,22 @@ describe('AgentManager', ()=>{
158
158
  getConversation: ()=>[],
159
159
  listSessions: async ()=>[]
160
160
  });
161
- const claude = createSnapshotAdapter('claude', [
162
- 'claude'
161
+ const claude = createSnapshotAdapter("claude", [
162
+ "claude"
163
163
  ]);
164
- const pi = createSnapshotAdapter('pi', [
165
- 'pi',
166
- 'node'
164
+ const pi = createSnapshotAdapter("pi", [
165
+ "pi",
166
+ "node"
167
167
  ]);
168
- const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, 'snapshot-agents.json')), captureSnapshot);
168
+ const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, "snapshot-agents.json")), captureSnapshot);
169
169
  snapshotManager.registerAdapter(claude);
170
170
  snapshotManager.registerAdapter(pi);
171
171
  await snapshotManager.listAgents();
172
172
  expect(captureSnapshot).toHaveBeenCalledTimes(1);
173
173
  expect(captureSnapshot).toHaveBeenCalledWith([
174
- 'claude',
175
- 'pi',
176
- 'node'
174
+ "claude",
175
+ "pi",
176
+ "node"
177
177
  ]);
178
178
  expect(claude.detectAgents).toHaveBeenCalledWith({
179
179
  processes: [
@@ -186,31 +186,31 @@ describe('AgentManager', ()=>{
186
186
  ]
187
187
  });
188
188
  });
189
- it('does not expose foreign command arguments to broad Pi and Gemini matchers', async ()=>{
189
+ it("does not expose foreign command arguments to broad Pi and Gemini matchers", async ()=>{
190
190
  const processes = [
191
191
  {
192
192
  pid: 100,
193
- command: 'node /usr/local/lib/gemini.js',
194
- cwd: '/g',
195
- tty: 's001'
193
+ command: "node /usr/local/lib/gemini.js",
194
+ cwd: "/g",
195
+ tty: "s001"
196
196
  },
197
197
  {
198
198
  pid: 200,
199
- command: 'codex exec --cd /Users/x/repos/gemini',
200
- cwd: '/c',
201
- tty: 's002'
199
+ command: "codex exec --cd /Users/x/repos/gemini",
200
+ cwd: "/c",
201
+ tty: "s002"
202
202
  },
203
203
  {
204
204
  pid: 300,
205
- command: 'node /usr/local/lib/pi.js',
206
- cwd: '/p',
207
- tty: 's003'
205
+ command: "node /usr/local/lib/pi.js",
206
+ cwd: "/p",
207
+ tty: "s003"
208
208
  },
209
209
  {
210
210
  pid: 400,
211
- command: 'claude --resume /Users/x/pi/session.jsonl',
212
- cwd: '/a',
213
- tty: 's004'
211
+ command: "claude --resume /Users/x/pi/session.jsonl",
212
+ cwd: "/a",
213
+ tty: "s004"
214
214
  }
215
215
  ];
216
216
  const captureSnapshot = vi.fn(async ()=>processes);
@@ -222,20 +222,20 @@ describe('AgentManager', ()=>{
222
222
  getConversation: ()=>[],
223
223
  listSessions: async ()=>[]
224
224
  });
225
- const gemini = createSnapshotAdapter('gemini_cli', [
226
- 'node'
225
+ const gemini = createSnapshotAdapter("gemini_cli", [
226
+ "node"
227
227
  ]);
228
- const codex = createSnapshotAdapter('codex', [
229
- 'codex'
228
+ const codex = createSnapshotAdapter("codex", [
229
+ "codex"
230
230
  ]);
231
- const pi = createSnapshotAdapter('pi', [
232
- 'pi',
233
- 'node'
231
+ const pi = createSnapshotAdapter("pi", [
232
+ "pi",
233
+ "node"
234
234
  ]);
235
- const claude = createSnapshotAdapter('claude', [
236
- 'claude'
235
+ const claude = createSnapshotAdapter("claude", [
236
+ "claude"
237
237
  ]);
238
- const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, 'filtered-snapshot-agents.json')), captureSnapshot);
238
+ const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, "filtered-snapshot-agents.json")), captureSnapshot);
239
239
  snapshotManager.registerAdapter(gemini);
240
240
  snapshotManager.registerAdapter(codex);
241
241
  snapshotManager.registerAdapter(pi);
@@ -243,10 +243,10 @@ describe('AgentManager', ()=>{
243
243
  await snapshotManager.listAgents();
244
244
  expect(captureSnapshot).toHaveBeenCalledTimes(1);
245
245
  expect(captureSnapshot).toHaveBeenCalledWith([
246
- 'node',
247
- 'codex',
248
- 'pi',
249
- 'claude'
246
+ "node",
247
+ "codex",
248
+ "pi",
249
+ "claude"
250
250
  ]);
251
251
  expect(gemini.detectAgents).toHaveBeenCalledWith({
252
252
  processes: [
@@ -271,107 +271,107 @@ describe('AgentManager', ()=>{
271
271
  ]
272
272
  });
273
273
  });
274
- it('does not pass a snapshot context to legacy adapters', async ()=>{
274
+ it("does not pass a snapshot context to legacy adapters", async ()=>{
275
275
  const captureSnapshot = vi.fn(async ()=>[]);
276
- const legacy = new MockAdapter('claude');
277
- const detect = vi.spyOn(legacy, 'detectAgents');
278
- const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, 'legacy-agents.json')), captureSnapshot);
276
+ const legacy = new MockAdapter("claude");
277
+ const detect = vi.spyOn(legacy, "detectAgents");
278
+ const snapshotManager = new AgentManager(new AgentRegistry(path.join(tmpDir, "legacy-agents.json")), captureSnapshot);
279
279
  snapshotManager.registerAdapter(legacy);
280
280
  await snapshotManager.listAgents();
281
281
  expect(captureSnapshot).not.toHaveBeenCalled();
282
282
  expect(detect).toHaveBeenCalledWith();
283
283
  });
284
- it('should return empty array when no adapters registered', async ()=>{
284
+ it("should return empty array when no adapters registered", async ()=>{
285
285
  const agents = await manager.listAgents();
286
286
  expect(agents).toEqual([]);
287
287
  });
288
- it('should return agents from single adapter', async ()=>{
288
+ it("should return agents from single adapter", async ()=>{
289
289
  const mockAgents = [
290
290
  createMockAgent({
291
- name: 'agent1'
291
+ name: "agent1"
292
292
  }),
293
293
  createMockAgent({
294
- name: 'agent2'
294
+ name: "agent2"
295
295
  })
296
296
  ];
297
- const adapter = new MockAdapter('claude', mockAgents);
297
+ const adapter = new MockAdapter("claude", mockAgents);
298
298
  manager.registerAdapter(adapter);
299
299
  const agents = await manager.listAgents();
300
300
  expect(agents).toHaveLength(2);
301
- expect(agents[0].name).toBe('agent1');
302
- expect(agents[1].name).toBe('agent2');
301
+ expect(agents[0].name).toBe("agent1");
302
+ expect(agents[1].name).toBe("agent2");
303
303
  });
304
- it('should aggregate agents from multiple adapters', async ()=>{
304
+ it("should aggregate agents from multiple adapters", async ()=>{
305
305
  const claudeAgents = [
306
306
  createMockAgent({
307
- name: 'claude-agent',
308
- type: 'claude'
307
+ name: "claude-agent",
308
+ type: "claude"
309
309
  })
310
310
  ];
311
311
  const geminiAgents = [
312
312
  createMockAgent({
313
- name: 'gemini-agent',
314
- type: 'gemini_cli'
313
+ name: "gemini-agent",
314
+ type: "gemini_cli"
315
315
  })
316
316
  ];
317
- manager.registerAdapter(new MockAdapter('claude', claudeAgents));
318
- manager.registerAdapter(new MockAdapter('gemini_cli', geminiAgents));
317
+ manager.registerAdapter(new MockAdapter("claude", claudeAgents));
318
+ manager.registerAdapter(new MockAdapter("gemini_cli", geminiAgents));
319
319
  const agents = await manager.listAgents();
320
320
  expect(agents).toHaveLength(2);
321
- expect(agents.find((a)=>a.name === 'claude-agent')).toBeDefined();
322
- expect(agents.find((a)=>a.name === 'gemini-agent')).toBeDefined();
321
+ expect(agents.find((a)=>a.name === "claude-agent")).toBeDefined();
322
+ expect(agents.find((a)=>a.name === "gemini-agent")).toBeDefined();
323
323
  });
324
- it('should sort agents by status priority (waiting first)', async ()=>{
324
+ it("should sort agents by status priority (waiting first)", async ()=>{
325
325
  const mockAgents = [
326
326
  createMockAgent({
327
- name: 'idle-agent',
327
+ name: "idle-agent",
328
328
  status: AgentStatus.IDLE
329
329
  }),
330
330
  createMockAgent({
331
- name: 'waiting-agent',
331
+ name: "waiting-agent",
332
332
  status: AgentStatus.WAITING
333
333
  }),
334
334
  createMockAgent({
335
- name: 'running-agent',
335
+ name: "running-agent",
336
336
  status: AgentStatus.RUNNING
337
337
  }),
338
338
  createMockAgent({
339
- name: 'unknown-agent',
339
+ name: "unknown-agent",
340
340
  status: AgentStatus.UNKNOWN
341
341
  })
342
342
  ];
343
- const adapter = new MockAdapter('claude', mockAgents);
343
+ const adapter = new MockAdapter("claude", mockAgents);
344
344
  manager.registerAdapter(adapter);
345
345
  const agents = await manager.listAgents();
346
- expect(agents[0].name).toBe('waiting-agent');
347
- expect(agents[1].name).toBe('running-agent');
348
- expect(agents[2].name).toBe('idle-agent');
349
- expect(agents[3].name).toBe('unknown-agent');
346
+ expect(agents[0].name).toBe("waiting-agent");
347
+ expect(agents[1].name).toBe("running-agent");
348
+ expect(agents[2].name).toBe("idle-agent");
349
+ expect(agents[3].name).toBe("unknown-agent");
350
350
  });
351
- it('should handle adapter errors gracefully', async ()=>{
352
- const goodAdapter = new MockAdapter('claude', [
351
+ it("should handle adapter errors gracefully", async ()=>{
352
+ const goodAdapter = new MockAdapter("claude", [
353
353
  createMockAgent({
354
- name: 'good-agent'
354
+ name: "good-agent"
355
355
  })
356
356
  ]);
357
- const badAdapter = new MockAdapter('gemini_cli', [], true); // Will fail
357
+ const badAdapter = new MockAdapter("gemini_cli", [], true); // Will fail
358
358
  manager.registerAdapter(goodAdapter);
359
359
  manager.registerAdapter(badAdapter);
360
360
  // Should not throw, should return results from working adapter
361
361
  const agents = await manager.listAgents();
362
362
  expect(agents).toHaveLength(1);
363
- expect(agents[0].name).toBe('good-agent');
363
+ expect(agents[0].name).toBe("good-agent");
364
364
  });
365
- it('should return empty array when all adapters fail', async ()=>{
366
- const adapter1 = new MockAdapter('claude', [], true);
367
- const adapter2 = new MockAdapter('gemini_cli', [], true);
365
+ it("should return empty array when all adapters fail", async ()=>{
366
+ const adapter1 = new MockAdapter("claude", [], true);
367
+ const adapter2 = new MockAdapter("gemini_cli", [], true);
368
368
  manager.registerAdapter(adapter1);
369
369
  manager.registerAdapter(adapter2);
370
370
  const agents = await manager.listAgents();
371
371
  expect(agents).toEqual([]);
372
372
  });
373
373
  });
374
- describe('listAgents — registry persistence', ()=>{
374
+ describe("listAgents — registry persistence", ()=>{
375
375
  let tmpDir;
376
376
  let regPath;
377
377
  let registry;
@@ -379,9 +379,9 @@ describe('AgentManager', ()=>{
379
379
  let nowMs;
380
380
  let databaseOperations;
381
381
  beforeEach(()=>{
382
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-manager-'));
383
- regPath = path.join(tmpDir, 'agents.json');
384
- nowMs = Date.parse('2026-08-14T10:00:00.000Z');
382
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-manager-"));
383
+ regPath = path.join(tmpDir, "agents.json");
384
+ nowMs = Date.parse("2026-08-14T10:00:00.000Z");
385
385
  databaseOperations = [];
386
386
  registry = new AgentRegistry(regPath, {
387
387
  now: ()=>new Date(nowMs),
@@ -398,149 +398,167 @@ describe('AgentManager', ()=>{
398
398
  force: true
399
399
  });
400
400
  });
401
- it('persists every detected agent to the registry', async ()=>{
402
- scopedManager.registerAdapter(new MockAdapter('claude', [
401
+ it("persists every detected agent to the registry", async ()=>{
402
+ scopedManager.registerAdapter(new MockAdapter("claude", [
403
403
  createMockAgent({
404
- name: 'a',
404
+ name: "a",
405
405
  pid: process.pid,
406
- sessionId: 'sid-a',
407
- sessionFilePath: '/path/a.jsonl',
408
- projectPath: '/cwd/a'
406
+ sessionId: "sid-a",
407
+ sessionFilePath: "/path/a.jsonl",
408
+ projectPath: "/cwd/a"
409
409
  })
410
410
  ]));
411
411
  await scopedManager.listAgents();
412
412
  const entries = registry.list();
413
413
  expect(entries).toHaveLength(1);
414
414
  expect(entries[0]).toMatchObject({
415
- name: 'a',
416
- type: 'claude',
415
+ name: "a",
416
+ type: "claude",
417
417
  pid: process.pid,
418
- cwd: '/cwd/a',
419
- sessionId: 'sid-a',
420
- sessionFilePath: '/path/a.jsonl',
421
- tmuxSession: ''
418
+ cwd: "/cwd/a",
419
+ sessionId: "sid-a",
420
+ sessionFilePath: "/path/a.jsonl",
421
+ runtime: "tmux",
422
+ runtimeRef: null
422
423
  });
423
424
  expect(entries[0].startedAt).toMatch(/^\d{4}-\d{2}-\d{2}T/);
424
425
  });
425
- it('prunes entries for dead pids', async ()=>{
426
+ it("prunes entries for dead pids", async ()=>{
426
427
  registry.register({
427
- name: 'dead',
428
- type: 'claude',
428
+ name: "dead",
429
+ type: "claude",
429
430
  pid: 999999,
430
- tmuxSession: '',
431
- cwd: '/cwd/dead',
432
- startedAt: '2026-05-30T00:00:00.000Z',
433
- sessionId: 'sid-dead',
434
- sessionFilePath: '/path/dead.jsonl'
431
+ runtime: "tmux",
432
+ runtimeRef: null,
433
+ cwd: "/cwd/dead",
434
+ startedAt: "2026-05-30T00:00:00.000Z",
435
+ sessionId: "sid-dead",
436
+ sessionFilePath: "/path/dead.jsonl"
435
437
  });
436
- scopedManager.registerAdapter(new MockAdapter('claude', [
438
+ scopedManager.registerAdapter(new MockAdapter("claude", [
437
439
  createMockAgent({
438
- name: 'live',
440
+ name: "live",
439
441
  pid: process.pid
440
442
  })
441
443
  ]));
442
444
  await scopedManager.listAgents();
443
445
  const entries = registry.list();
444
446
  expect(entries.map((e)=>e.name)).toEqual([
445
- 'live'
447
+ "live"
446
448
  ]);
447
449
  });
448
450
  it('preserves an existing name (e.g. user-set "merry") across cycles', async ()=>{
449
451
  registry.register({
450
- name: 'merry',
451
- type: 'claude',
452
+ name: "merry",
453
+ type: "claude",
452
454
  pid: process.pid,
453
- tmuxSession: 'merry',
454
- cwd: '/cwd/merry',
455
- startedAt: '2026-05-30T00:00:00.000Z',
456
- sessionId: 'sid-merry',
457
- sessionFilePath: '/path/merry.jsonl'
455
+ runtime: "tmux",
456
+ runtimeRef: {
457
+ session: "merry"
458
+ },
459
+ cwd: "/cwd/merry",
460
+ startedAt: "2026-05-30T00:00:00.000Z",
461
+ sessionId: "sid-merry",
462
+ sessionFilePath: "/path/merry.jsonl"
458
463
  });
459
- scopedManager.registerAdapter(new MockAdapter('claude', [
464
+ scopedManager.registerAdapter(new MockAdapter("claude", [
460
465
  createMockAgent({
461
- name: 'default-name',
466
+ name: "default-name",
462
467
  pid: process.pid
463
468
  })
464
469
  ]));
465
470
  const agents = await scopedManager.listAgents();
466
- expect(agents[0].name).toBe('merry');
467
- expect(registry.list()[0].name).toBe('merry');
468
- expect(registry.list()[0].tmuxSession).toBe('merry');
469
- expect(registry.list()[0].startedAt).toBe('2026-05-30T00:00:00.000Z');
471
+ expect(agents[0].name).toBe("merry");
472
+ expect(registry.list()[0].name).toBe("merry");
473
+ expect(registry.list()[0].runtimeRef).toEqual({
474
+ session: "merry"
475
+ });
476
+ expect(registry.list()[0].startedAt).toBe("2026-05-30T00:00:00.000Z");
470
477
  });
471
- it('preserves custom name and tmux session across two EPERM refresh cycles', async ()=>{
478
+ it("preserves custom name and tmux runtime ref across two EPERM refresh cycles", async ()=>{
472
479
  registry.register({
473
- name: 'merry',
474
- type: 'claude',
480
+ name: "merry",
481
+ type: "claude",
475
482
  pid: process.pid,
476
- tmuxSession: 'merry-tmux',
477
- cwd: '/cwd/merry',
478
- startedAt: '2026-05-30T00:00:00.000Z',
479
- sessionId: 'sid-merry',
480
- sessionFilePath: '/path/merry.jsonl'
483
+ runtime: "tmux",
484
+ runtimeRef: {
485
+ session: "merry-tmux"
486
+ },
487
+ cwd: "/cwd/merry",
488
+ startedAt: "2026-05-30T00:00:00.000Z",
489
+ sessionId: "sid-merry",
490
+ sessionFilePath: "/path/merry.jsonl"
481
491
  });
482
- scopedManager.registerAdapter(new MockAdapter('claude', [
492
+ scopedManager.registerAdapter(new MockAdapter("claude", [
483
493
  createMockAgent({
484
494
  name: `ai-devkit-${process.pid}`,
485
495
  pid: process.pid
486
496
  })
487
497
  ]));
488
- vi.spyOn(process, 'kill').mockImplementation(()=>{
489
- throw Object.assign(new Error('operation not permitted'), {
490
- code: 'EPERM'
498
+ vi.spyOn(process, "kill").mockImplementation(()=>{
499
+ throw Object.assign(new Error("operation not permitted"), {
500
+ code: "EPERM"
491
501
  });
492
502
  });
493
503
  const firstRefresh = await scopedManager.listAgents();
494
504
  const secondRefresh = await scopedManager.listAgents();
495
- expect(firstRefresh[0].name).toBe('merry');
496
- expect(secondRefresh[0].name).toBe('merry');
497
- expect(registry.lookup('merry')).toMatchObject({
498
- name: 'merry',
499
- tmuxSession: 'merry-tmux'
505
+ expect(firstRefresh[0].name).toBe("merry");
506
+ expect(secondRefresh[0].name).toBe("merry");
507
+ expect(registry.lookup("merry")).toMatchObject({
508
+ name: "merry",
509
+ runtimeRef: {
510
+ session: "merry-tmux"
511
+ }
500
512
  });
501
513
  });
502
- it('preserves a user-managed name when a fallback row was written later for the same pid', async ()=>{
514
+ it("preserves a user-managed name when a fallback row was written later for the same pid", async ()=>{
503
515
  registry.register({
504
- name: 'agent-list-debug',
505
- type: 'codex',
516
+ name: "agent-list-debug",
517
+ type: "codex",
506
518
  pid: process.pid,
507
- tmuxSession: 'agent-list-debug',
508
- cwd: '/cwd/debug',
509
- startedAt: '2026-05-30T00:00:00.000Z',
510
- sessionId: 'pid-debug',
511
- sessionFilePath: ''
519
+ runtime: "tmux",
520
+ runtimeRef: {
521
+ session: "agent-list-debug"
522
+ },
523
+ cwd: "/cwd/debug",
524
+ startedAt: "2026-05-30T00:00:00.000Z",
525
+ sessionId: "pid-debug",
526
+ sessionFilePath: ""
512
527
  });
513
528
  registry.register({
514
529
  name: `ai-devkit-${process.pid}`,
515
- type: 'codex',
530
+ type: "codex",
516
531
  pid: process.pid,
517
- tmuxSession: '',
518
- cwd: '/cwd/debug',
519
- startedAt: '2026-05-31T00:00:00.000Z',
520
- sessionId: 'pid-debug',
521
- sessionFilePath: ''
532
+ runtime: "tmux",
533
+ runtimeRef: null,
534
+ cwd: "/cwd/debug",
535
+ startedAt: "2026-05-31T00:00:00.000Z",
536
+ sessionId: "pid-debug",
537
+ sessionFilePath: ""
522
538
  });
523
- scopedManager.registerAdapter(new MockAdapter('codex', [
539
+ scopedManager.registerAdapter(new MockAdapter("codex", [
524
540
  createMockAgent({
525
541
  name: `ai-devkit-${process.pid}`,
526
- type: 'codex',
542
+ type: "codex",
527
543
  pid: process.pid
528
544
  })
529
545
  ]));
530
546
  const agents = await scopedManager.listAgents();
531
- expect(agents[0].name).toBe('agent-list-debug');
547
+ expect(agents[0].name).toBe("agent-list-debug");
532
548
  expect(registry.list()).toHaveLength(1);
533
549
  expect(registry.list()[0]).toMatchObject({
534
- name: 'agent-list-debug',
550
+ name: "agent-list-debug",
535
551
  pid: process.pid,
536
- tmuxSession: 'agent-list-debug'
552
+ runtimeRef: {
553
+ session: "agent-list-debug"
554
+ }
537
555
  });
538
556
  });
539
- it('writes a fresh startedAt for new entries', async ()=>{
557
+ it("writes a fresh startedAt for new entries", async ()=>{
540
558
  const before = new Date().toISOString();
541
- scopedManager.registerAdapter(new MockAdapter('claude', [
559
+ scopedManager.registerAdapter(new MockAdapter("claude", [
542
560
  createMockAgent({
543
- name: 'new',
561
+ name: "new",
544
562
  pid: process.pid
545
563
  })
546
564
  ]));
@@ -548,36 +566,36 @@ describe('AgentManager', ()=>{
548
566
  const entry = registry.list()[0];
549
567
  expect(entry.startedAt >= before).toBe(true);
550
568
  });
551
- it('batches the write — a single registerBatch call per listAgents', async ()=>{
552
- const spy = vi.spyOn(registry, 'registerBatch');
553
- scopedManager.registerAdapter(new MockAdapter('claude', [
569
+ it("batches the write — a single registerBatch call per listAgents", async ()=>{
570
+ const spy = vi.spyOn(registry, "registerBatch");
571
+ scopedManager.registerAdapter(new MockAdapter("claude", [
554
572
  createMockAgent({
555
- name: 'a',
573
+ name: "a",
556
574
  pid: process.pid
557
575
  })
558
576
  ]));
559
- scopedManager.registerAdapter(new MockAdapter('codex', [
577
+ scopedManager.registerAdapter(new MockAdapter("codex", [
560
578
  createMockAgent({
561
- name: 'b',
562
- type: 'codex',
579
+ name: "b",
580
+ type: "codex",
563
581
  pid: process.pid + 1
564
582
  })
565
583
  ]));
566
584
  await scopedManager.listAgents();
567
585
  expect(spy).toHaveBeenCalledTimes(1);
568
586
  expect(spy.mock.calls[0][0].map((e)=>e.name).sort()).toEqual([
569
- 'a',
570
- 'b'
587
+ "a",
588
+ "b"
571
589
  ]);
572
590
  });
573
- it('performs zero database writes on an unchanged refresh', async ()=>{
574
- const adapter = new MockAdapter('claude', [
591
+ it("performs zero database writes on an unchanged refresh", async ()=>{
592
+ const adapter = new MockAdapter("claude", [
575
593
  createMockAgent({
576
- name: 'stable',
594
+ name: "stable",
577
595
  pid: process.pid,
578
- projectPath: '/cwd/stable',
579
- sessionId: 'stable-session',
580
- sessionFilePath: '/sessions/stable.jsonl'
596
+ projectPath: "/cwd/stable",
597
+ sessionId: "stable-session",
598
+ sessionFilePath: "/sessions/stable.jsonl"
581
599
  })
582
600
  ]);
583
601
  scopedManager.registerAdapter(adapter);
@@ -587,66 +605,66 @@ describe('AgentManager', ()=>{
587
605
  const writes = databaseOperations.filter((sql)=>/^\s*(BEGIN|COMMIT|INSERT|UPDATE|DELETE)/i.test(sql));
588
606
  expect(writes).toEqual([]);
589
607
  });
590
- it('exposes a persisted pin and preserves it across a changed poll refresh', async ()=>{
591
- const adapter = new MockAdapter('claude', [
608
+ it("exposes a persisted pin and preserves it across a changed poll refresh", async ()=>{
609
+ const adapter = new MockAdapter("claude", [
592
610
  createMockAgent({
593
- name: 'pinned',
611
+ name: "pinned",
594
612
  pid: process.pid,
595
- sessionId: 'before'
613
+ sessionId: "before"
596
614
  })
597
615
  ]);
598
616
  scopedManager.registerAdapter(adapter);
599
617
  await scopedManager.listAgents();
600
- registry.togglePin('claude', process.pid);
618
+ registry.togglePin("claude", process.pid);
601
619
  adapter.setAgents([
602
620
  createMockAgent({
603
- name: 'pinned',
621
+ name: "pinned",
604
622
  pid: process.pid,
605
- sessionId: 'after'
623
+ sessionId: "after"
606
624
  })
607
625
  ]);
608
626
  const agents = await scopedManager.listAgents();
609
627
  expect(agents[0].pinned).toBe(true);
610
- expect(registry.lookup('pinned')).toMatchObject({
611
- sessionId: 'after',
628
+ expect(registry.lookup("pinned")).toMatchObject({
629
+ sessionId: "after",
612
630
  pinned: true
613
631
  });
614
632
  });
615
- it('uses registry updated_at as lastActive for pinned recency ordering', async ()=>{
616
- const adapter = new MockAdapter('claude', [
633
+ it("uses registry updated_at as lastActive for pinned recency ordering", async ()=>{
634
+ const adapter = new MockAdapter("claude", [
617
635
  createMockAgent({
618
- name: 'recently-pinned',
636
+ name: "recently-pinned",
619
637
  pid: process.pid,
620
- lastActive: new Date('2026-01-01T00:00:00.000Z')
638
+ lastActive: new Date("2026-01-01T00:00:00.000Z")
621
639
  })
622
640
  ]);
623
641
  scopedManager.registerAdapter(adapter);
624
642
  await scopedManager.listAgents();
625
643
  nowMs += 60_000;
626
- scopedManager.togglePin('recently-pinned');
644
+ scopedManager.togglePin("recently-pinned");
627
645
  const agents = await scopedManager.listAgents();
628
646
  expect(agents[0].pinned).toBe(true);
629
- expect(agents[0].lastActive.toISOString()).toBe('2026-08-14T10:01:00.000Z');
647
+ expect(agents[0].lastActive.toISOString()).toBe("2026-08-14T10:01:00.000Z");
630
648
  });
631
- it('preserves adapter lastActive for unpinned agents', async ()=>{
632
- scopedManager.registerAdapter(new MockAdapter('claude', [
649
+ it("preserves adapter lastActive for unpinned agents", async ()=>{
650
+ scopedManager.registerAdapter(new MockAdapter("claude", [
633
651
  createMockAgent({
634
- name: 'unpinned',
652
+ name: "unpinned",
635
653
  pid: process.pid,
636
- lastActive: new Date('2026-01-01T00:00:00.000Z')
654
+ lastActive: new Date("2026-01-01T00:00:00.000Z")
637
655
  })
638
656
  ]));
639
657
  await scopedManager.listAgents();
640
658
  const agents = await scopedManager.listAgents();
641
659
  expect(agents[0].pinned).toBe(false);
642
- expect(agents[0].lastActive.toISOString()).toBe('2026-01-01T00:00:00.000Z');
660
+ expect(agents[0].lastActive.toISOString()).toBe("2026-01-01T00:00:00.000Z");
643
661
  });
644
- it('persists changed fields once in one write transaction', async ()=>{
645
- const adapter = new MockAdapter('claude', [
662
+ it("persists changed fields once in one write transaction", async ()=>{
663
+ const adapter = new MockAdapter("claude", [
646
664
  createMockAgent({
647
- name: 'changing',
665
+ name: "changing",
648
666
  pid: process.pid,
649
- projectPath: '/cwd/before'
667
+ projectPath: "/cwd/before"
650
668
  })
651
669
  ]);
652
670
  scopedManager.registerAdapter(adapter);
@@ -655,9 +673,9 @@ describe('AgentManager', ()=>{
655
673
  nowMs += 1_000;
656
674
  adapter.setAgents([
657
675
  createMockAgent({
658
- name: 'changing',
676
+ name: "changing",
659
677
  pid: process.pid,
660
- projectPath: '/cwd/after'
678
+ projectPath: "/cwd/after"
661
679
  })
662
680
  ]);
663
681
  await scopedManager.listAgents();
@@ -666,339 +684,346 @@ describe('AgentManager', ()=>{
666
684
  expect(upserts).toHaveLength(1);
667
685
  expect(upserts[0]).toContain("'2026-08-14T10:00:01.000Z'");
668
686
  expect(transactions).toHaveLength(2);
669
- expect(registry.lookup('changing')?.cwd).toBe('/cwd/after');
687
+ expect(registry.lookup("changing")?.cwd).toBe("/cwd/after");
670
688
  });
671
- it('prunes newly dead entries only when the passive cadence is due', async ()=>{
689
+ it("prunes newly dead entries only when the passive cadence is due", async ()=>{
672
690
  registry.register({
673
- name: 'cadenced',
674
- type: 'claude',
691
+ name: "cadenced",
692
+ type: "claude",
675
693
  pid: process.pid,
676
- tmuxSession: '',
677
- cwd: '/cwd/cadenced',
678
- startedAt: '2026-05-30T00:00:00.000Z',
679
- sessionId: 'sid-cadenced',
680
- sessionFilePath: ''
694
+ runtime: "tmux",
695
+ runtimeRef: null,
696
+ cwd: "/cwd/cadenced",
697
+ startedAt: "2026-05-30T00:00:00.000Z",
698
+ sessionId: "sid-cadenced",
699
+ sessionFilePath: ""
681
700
  });
682
- const alive = vi.spyOn(registry, 'isAlive').mockReturnValue(true);
701
+ const alive = vi.spyOn(registry, "isAlive").mockReturnValue(true);
683
702
  await scopedManager.listAgents();
684
703
  expect(alive).toHaveBeenCalledTimes(1);
685
704
  alive.mockReturnValue(false);
686
705
  nowMs += 29_999;
687
706
  await scopedManager.listAgents();
688
707
  expect(alive).toHaveBeenCalledTimes(1);
689
- expect(registry.lookup('cadenced')).not.toBeNull();
708
+ expect(registry.lookup("cadenced")).not.toBeNull();
690
709
  nowMs += 1;
691
710
  await scopedManager.listAgents();
692
711
  expect(alive).toHaveBeenCalledTimes(2);
693
- expect(registry.lookup('cadenced')).toBeNull();
712
+ expect(registry.lookup("cadenced")).toBeNull();
694
713
  });
695
- it('does not inherit a name when the same pid is reused by another agent type', async ()=>{
714
+ it("does not inherit a name when the same pid is reused by another agent type", async ()=>{
696
715
  registry.register({
697
- name: 'old-claude',
698
- type: 'claude',
716
+ name: "old-claude",
717
+ type: "claude",
699
718
  pid: process.pid,
700
- tmuxSession: 'old-claude',
701
- cwd: '/cwd/old',
702
- startedAt: '2026-05-30T00:00:00.000Z',
703
- sessionId: 'old-session',
704
- sessionFilePath: ''
719
+ runtime: "tmux",
720
+ runtimeRef: {
721
+ session: "old-claude"
722
+ },
723
+ cwd: "/cwd/old",
724
+ startedAt: "2026-05-30T00:00:00.000Z",
725
+ sessionId: "old-session",
726
+ sessionFilePath: ""
705
727
  });
706
- scopedManager.registerAdapter(new MockAdapter('codex', [
728
+ scopedManager.registerAdapter(new MockAdapter("codex", [
707
729
  createMockAgent({
708
- name: 'new-codex',
709
- type: 'codex',
730
+ name: "new-codex",
731
+ type: "codex",
710
732
  pid: process.pid,
711
- projectPath: '/cwd/new',
712
- sessionId: 'new-session'
733
+ projectPath: "/cwd/new",
734
+ sessionId: "new-session"
713
735
  })
714
736
  ]));
715
737
  const agents = await scopedManager.listAgents();
716
- expect(agents[0].name).toBe('new-codex');
717
- expect(registry.lookup('old-claude')).toBeNull();
718
- expect(registry.lookup('new-codex')).toMatchObject({
719
- type: 'codex',
738
+ expect(agents[0].name).toBe("new-codex");
739
+ expect(registry.lookup("old-claude")).toBeNull();
740
+ expect(registry.lookup("new-codex")).toMatchObject({
741
+ type: "codex",
720
742
  pid: process.pid
721
743
  });
722
744
  });
723
- it('skips registerBatch when no agents are detected and prune is not due', async ()=>{
724
- const writeSpy = vi.spyOn(registry, 'registerBatch');
725
- const pruneSpy = vi.spyOn(registry, 'pruneIfDue');
726
- scopedManager.registerAdapter(new MockAdapter('claude', []));
745
+ it("skips registerBatch when no agents are detected and prune is not due", async ()=>{
746
+ const writeSpy = vi.spyOn(registry, "registerBatch");
747
+ const pruneSpy = vi.spyOn(registry, "pruneIfDue");
748
+ scopedManager.registerAdapter(new MockAdapter("claude", []));
727
749
  await scopedManager.listAgents();
728
750
  await scopedManager.listAgents();
729
751
  expect(writeSpy).not.toHaveBeenCalled();
730
752
  expect(pruneSpy).toHaveBeenCalledTimes(2);
731
753
  });
732
754
  });
733
- describe('togglePin', ()=>{
734
- it('resolves the agent name to its process identity and toggles the pin', ()=>{
735
- const registry = new AgentRegistry(path.join(tmpDir, 'toggle.json'));
755
+ describe("togglePin", ()=>{
756
+ it("resolves the agent name to its process identity and toggles the pin", ()=>{
757
+ const registry = new AgentRegistry(path.join(tmpDir, "toggle.json"));
736
758
  const scopedManager = new AgentManager(registry);
737
759
  registry.register({
738
- name: 'renamed-agent',
739
- type: 'claude',
760
+ name: "renamed-agent",
761
+ type: "claude",
740
762
  pid: process.pid,
741
- tmuxSession: '',
742
- cwd: '/tmp',
743
- startedAt: '2026-08-16T00:00:00.000Z',
744
- sessionId: 'session',
745
- sessionFilePath: '',
763
+ runtime: "tmux",
764
+ runtimeRef: null,
765
+ cwd: "/tmp",
766
+ startedAt: "2026-08-16T00:00:00.000Z",
767
+ sessionId: "session",
768
+ sessionFilePath: "",
746
769
  pinned: false
747
770
  });
748
- expect(scopedManager.togglePin('renamed-agent')).toBe(true);
749
- expect(registry.lookup('renamed-agent')?.pinned).toBe(true);
771
+ expect(scopedManager.togglePin("renamed-agent")).toBe(true);
772
+ expect(registry.lookup("renamed-agent")?.pinned).toBe(true);
750
773
  });
751
- it('reports when the agent is no longer running', ()=>{
752
- expect(()=>manager.togglePin('missing')).toThrow(/no longer running/i);
774
+ it("reports when the agent is no longer running", ()=>{
775
+ expect(()=>manager.togglePin("missing")).toThrow(/no longer running/i);
753
776
  });
754
- it('rejects a dead process and prunes its row', ()=>{
755
- const registry = new AgentRegistry(path.join(tmpDir, 'dead-toggle.json'));
777
+ it("rejects a dead process and prunes its row", ()=>{
778
+ const registry = new AgentRegistry(path.join(tmpDir, "dead-toggle.json"));
756
779
  const scopedManager = new AgentManager(registry);
757
780
  registry.register({
758
- name: 'dead',
759
- type: 'claude',
781
+ name: "dead",
782
+ type: "claude",
760
783
  pid: 999999,
761
- tmuxSession: '',
762
- cwd: '/tmp',
763
- startedAt: '2026-08-16T00:00:00.000Z',
764
- sessionId: 'session',
765
- sessionFilePath: '',
784
+ runtime: "tmux",
785
+ runtimeRef: null,
786
+ cwd: "/tmp",
787
+ startedAt: "2026-08-16T00:00:00.000Z",
788
+ sessionId: "session",
789
+ sessionFilePath: "",
766
790
  pinned: false
767
791
  });
768
- expect(()=>scopedManager.togglePin('dead')).toThrow(/no longer running/i);
769
- expect(registry.lookup('dead')).toBeNull();
792
+ expect(()=>scopedManager.togglePin("dead")).toThrow(/no longer running/i);
793
+ expect(registry.lookup("dead")).toBeNull();
770
794
  });
771
- it('surfaces a clear readonly mutation error', ()=>{
772
- const regPath = path.join(tmpDir, 'readonly-toggle.json');
795
+ it("surfaces a clear readonly mutation error", ()=>{
796
+ const regPath = path.join(tmpDir, "readonly-toggle.json");
773
797
  const writable = new AgentRegistry(regPath);
774
798
  writable.register({
775
- name: 'readonly-agent',
776
- type: 'claude',
799
+ name: "readonly-agent",
800
+ type: "claude",
777
801
  pid: process.pid,
778
- tmuxSession: '',
779
- cwd: '/tmp',
780
- startedAt: '2026-08-16T00:00:00.000Z',
781
- sessionId: 'session',
782
- sessionFilePath: '',
802
+ runtime: "tmux",
803
+ runtimeRef: null,
804
+ cwd: "/tmp",
805
+ startedAt: "2026-08-16T00:00:00.000Z",
806
+ sessionId: "session",
807
+ sessionFilePath: "",
783
808
  pinned: false
784
809
  });
785
810
  const readonlyManager = new AgentManager(new AgentRegistry(regPath, {
786
811
  readonly: true
787
812
  }));
788
- expect(()=>readonlyManager.togglePin('readonly-agent')).toThrow('Agent registry is readonly; cannot toggle pin.');
813
+ expect(()=>readonlyManager.togglePin("readonly-agent")).toThrow("Agent registry is readonly; cannot toggle pin.");
789
814
  });
790
815
  });
791
- describe('clear', ()=>{
792
- it('should remove all adapters', ()=>{
793
- manager.registerAdapter(new MockAdapter('claude'));
794
- manager.registerAdapter(new MockAdapter('gemini_cli'));
816
+ describe("clear", ()=>{
817
+ it("should remove all adapters", ()=>{
818
+ manager.registerAdapter(new MockAdapter("claude"));
819
+ manager.registerAdapter(new MockAdapter("gemini_cli"));
795
820
  manager.clear();
796
821
  expect(manager.getAdapterCount()).toBe(0);
797
822
  expect(manager.getAdapters()).toEqual([]);
798
823
  });
799
824
  });
800
- describe('listSessions', ()=>{
825
+ describe("listSessions", ()=>{
801
826
  function createMockSession(overrides = {}) {
802
827
  return {
803
- type: 'claude',
804
- sessionId: 'session-1',
805
- cwd: '/repo',
806
- firstUserMessage: 'hello',
807
- lastActive: new Date('2025-01-01T00:00:00Z'),
808
- startedAt: new Date('2025-01-01T00:00:00Z'),
809
- sessionFilePath: '/tmp/session-1.jsonl',
828
+ type: "claude",
829
+ sessionId: "session-1",
830
+ cwd: "/repo",
831
+ firstUserMessage: "hello",
832
+ lastActive: new Date("2025-01-01T00:00:00Z"),
833
+ startedAt: new Date("2025-01-01T00:00:00Z"),
834
+ sessionFilePath: "/tmp/session-1.jsonl",
810
835
  ...overrides
811
836
  };
812
837
  }
813
- it('returns empty array when no adapters are registered', async ()=>{
838
+ it("returns empty array when no adapters are registered", async ()=>{
814
839
  const result = await manager.listSessions();
815
840
  expect(result).toEqual([]);
816
841
  });
817
- it('merges sessions from every registered adapter', async ()=>{
842
+ it("merges sessions from every registered adapter", async ()=>{
818
843
  const claudeSession = createMockSession({
819
- type: 'claude',
820
- sessionId: 'c1'
844
+ type: "claude",
845
+ sessionId: "c1"
821
846
  });
822
847
  const codexSession = createMockSession({
823
- type: 'codex',
824
- sessionId: 'cx1'
848
+ type: "codex",
849
+ sessionId: "cx1"
825
850
  });
826
- manager.registerAdapter(new MockAdapter('claude', [], false, [
851
+ manager.registerAdapter(new MockAdapter("claude", [], false, [
827
852
  claudeSession
828
853
  ]));
829
- manager.registerAdapter(new MockAdapter('codex', [], false, [
854
+ manager.registerAdapter(new MockAdapter("codex", [], false, [
830
855
  codexSession
831
856
  ]));
832
857
  const result = await manager.listSessions();
833
858
  expect(result).toHaveLength(2);
834
859
  expect(result.map((s)=>s.sessionId).sort()).toEqual([
835
- 'c1',
836
- 'cx1'
860
+ "c1",
861
+ "cx1"
837
862
  ]);
838
863
  });
839
- it('sorts merged sessions by lastActive descending', async ()=>{
864
+ it("sorts merged sessions by lastActive descending", async ()=>{
840
865
  const older = createMockSession({
841
- sessionId: 'older',
842
- lastActive: new Date('2025-01-01T00:00:00Z')
866
+ sessionId: "older",
867
+ lastActive: new Date("2025-01-01T00:00:00Z")
843
868
  });
844
869
  const newer = createMockSession({
845
- type: 'codex',
846
- sessionId: 'newer',
847
- lastActive: new Date('2025-06-01T00:00:00Z')
870
+ type: "codex",
871
+ sessionId: "newer",
872
+ lastActive: new Date("2025-06-01T00:00:00Z")
848
873
  });
849
- manager.registerAdapter(new MockAdapter('claude', [], false, [
874
+ manager.registerAdapter(new MockAdapter("claude", [], false, [
850
875
  older
851
876
  ]));
852
- manager.registerAdapter(new MockAdapter('codex', [], false, [
877
+ manager.registerAdapter(new MockAdapter("codex", [], false, [
853
878
  newer
854
879
  ]));
855
880
  const result = await manager.listSessions();
856
881
  expect(result.map((s)=>s.sessionId)).toEqual([
857
- 'newer',
858
- 'older'
882
+ "newer",
883
+ "older"
859
884
  ]);
860
885
  });
861
- it('skips adapters whose type does not match opts.type', async ()=>{
862
- const claudeAdapter = new MockAdapter('claude', [], false, [
886
+ it("skips adapters whose type does not match opts.type", async ()=>{
887
+ const claudeAdapter = new MockAdapter("claude", [], false, [
863
888
  createMockSession({
864
- type: 'claude',
865
- sessionId: 'c1'
889
+ type: "claude",
890
+ sessionId: "c1"
866
891
  })
867
892
  ]);
868
- const codexAdapter = new MockAdapter('codex', [], false, [
893
+ const codexAdapter = new MockAdapter("codex", [], false, [
869
894
  createMockSession({
870
- type: 'codex',
871
- sessionId: 'cx1'
895
+ type: "codex",
896
+ sessionId: "cx1"
872
897
  })
873
898
  ]);
874
899
  manager.registerAdapter(claudeAdapter);
875
900
  manager.registerAdapter(codexAdapter);
876
901
  const result = await manager.listSessions({
877
- type: 'claude'
902
+ type: "claude"
878
903
  });
879
904
  expect(result).toHaveLength(1);
880
- expect(result[0].sessionId).toBe('c1');
905
+ expect(result[0].sessionId).toBe("c1");
881
906
  // Codex adapter must not have been called
882
907
  expect(codexAdapter.lastListSessionsOpts).toBeUndefined();
883
908
  expect(claudeAdapter.lastListSessionsOpts).toEqual({
884
- type: 'claude'
909
+ type: "claude"
885
910
  });
886
911
  });
887
- it('tolerates an adapter that throws and still returns the others', async ()=>{
912
+ it("tolerates an adapter that throws and still returns the others", async ()=>{
888
913
  const goodSession = createMockSession({
889
- sessionId: 'good'
914
+ sessionId: "good"
890
915
  });
891
- manager.registerAdapter(new MockAdapter('claude', [], false, [
916
+ manager.registerAdapter(new MockAdapter("claude", [], false, [
892
917
  goodSession
893
918
  ]));
894
- manager.registerAdapter(new MockAdapter('codex', [], false, [], true));
895
- const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(()=>undefined);
919
+ manager.registerAdapter(new MockAdapter("codex", [], false, [], true));
920
+ const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(()=>undefined);
896
921
  try {
897
922
  const result = await manager.listSessions();
898
923
  expect(result).toHaveLength(1);
899
- expect(result[0].sessionId).toBe('good');
924
+ expect(result[0].sessionId).toBe("good");
900
925
  expect(consoleErrorSpy).toHaveBeenCalled();
901
926
  } finally{
902
927
  consoleErrorSpy.mockRestore();
903
928
  }
904
929
  });
905
- it('passes the same opts to every called adapter', async ()=>{
906
- const a = new MockAdapter('claude', [], false, []);
907
- const b = new MockAdapter('codex', [], false, []);
930
+ it("passes the same opts to every called adapter", async ()=>{
931
+ const a = new MockAdapter("claude", [], false, []);
932
+ const b = new MockAdapter("codex", [], false, []);
908
933
  manager.registerAdapter(a);
909
934
  manager.registerAdapter(b);
910
935
  await manager.listSessions({
911
- cwd: '/Users/test/proj'
936
+ cwd: "/Users/test/proj"
912
937
  });
913
938
  expect(a.lastListSessionsOpts).toEqual({
914
- cwd: '/Users/test/proj'
939
+ cwd: "/Users/test/proj"
915
940
  });
916
941
  expect(b.lastListSessionsOpts).toEqual({
917
- cwd: '/Users/test/proj'
942
+ cwd: "/Users/test/proj"
918
943
  });
919
944
  });
920
945
  });
921
- describe('resolveAgent', ()=>{
922
- it('should return null for empty input or empty agents list', ()=>{
946
+ describe("resolveAgent", ()=>{
947
+ it("should return null for empty input or empty agents list", ()=>{
923
948
  const agent = createMockAgent({
924
- name: 'test-agent'
949
+ name: "test-agent"
925
950
  });
926
- expect(manager.resolveAgent('', [
951
+ expect(manager.resolveAgent("", [
927
952
  agent
928
953
  ])).toBeNull();
929
- expect(manager.resolveAgent('test', [])).toBeNull();
954
+ expect(manager.resolveAgent("test", [])).toBeNull();
930
955
  });
931
- it('should resolve exact match (case-insensitive)', ()=>{
956
+ it("should resolve exact match (case-insensitive)", ()=>{
932
957
  const agent = createMockAgent({
933
- name: 'My-Agent'
958
+ name: "My-Agent"
934
959
  });
935
960
  const agents = [
936
961
  agent,
937
962
  createMockAgent({
938
- name: 'Other'
963
+ name: "Other"
939
964
  })
940
965
  ];
941
966
  // Exact match
942
- expect(manager.resolveAgent('My-Agent', agents)).toBe(agent);
967
+ expect(manager.resolveAgent("My-Agent", agents)).toBe(agent);
943
968
  // Case-insensitive
944
- expect(manager.resolveAgent('my-agent', agents)).toBe(agent);
969
+ expect(manager.resolveAgent("my-agent", agents)).toBe(agent);
945
970
  });
946
- it('should resolve unique partial match', ()=>{
971
+ it("should resolve unique partial match", ()=>{
947
972
  const agent = createMockAgent({
948
- name: 'ai-devkit'
973
+ name: "ai-devkit"
949
974
  });
950
975
  const agents = [
951
976
  agent,
952
977
  createMockAgent({
953
- name: 'other-project'
978
+ name: "other-project"
954
979
  })
955
980
  ];
956
- const result = manager.resolveAgent('dev', agents);
981
+ const result = manager.resolveAgent("dev", agents);
957
982
  expect(result).toBe(agent);
958
983
  });
959
- it('should return array for ambiguous partial match', ()=>{
984
+ it("should return array for ambiguous partial match", ()=>{
960
985
  const agent1 = createMockAgent({
961
- name: 'my-website'
986
+ name: "my-website"
962
987
  });
963
988
  const agent2 = createMockAgent({
964
- name: 'my-app'
989
+ name: "my-app"
965
990
  });
966
991
  const agents = [
967
992
  agent1,
968
993
  agent2,
969
994
  createMockAgent({
970
- name: 'other'
995
+ name: "other"
971
996
  })
972
997
  ];
973
- const result = manager.resolveAgent('my', agents);
998
+ const result = manager.resolveAgent("my", agents);
974
999
  expect(Array.isArray(result)).toBe(true);
975
1000
  const matches = result;
976
1001
  expect(matches).toHaveLength(2);
977
1002
  expect(matches).toContain(agent1);
978
1003
  expect(matches).toContain(agent2);
979
1004
  });
980
- it('should return null for no match', ()=>{
1005
+ it("should return null for no match", ()=>{
981
1006
  const agents = [
982
1007
  createMockAgent({
983
- name: 'ai-devkit'
1008
+ name: "ai-devkit"
984
1009
  })
985
1010
  ];
986
- expect(manager.resolveAgent('xyz', agents)).toBeNull();
1011
+ expect(manager.resolveAgent("xyz", agents)).toBeNull();
987
1012
  });
988
- it('should prefer exact match over partial matches', ()=>{
1013
+ it("should prefer exact match over partial matches", ()=>{
989
1014
  // Edge case: "test" matches "test" (exact) and "testing" (partial)
990
1015
  // Should return exact "test"
991
1016
  const exact = createMockAgent({
992
- name: 'test'
1017
+ name: "test"
993
1018
  });
994
1019
  const partial = createMockAgent({
995
- name: 'testing'
1020
+ name: "testing"
996
1021
  });
997
1022
  const agents = [
998
1023
  exact,
999
1024
  partial
1000
1025
  ];
1001
- expect(manager.resolveAgent('test', agents)).toBe(exact);
1026
+ expect(manager.resolveAgent("test", agents)).toBe(exact);
1002
1027
  });
1003
1028
  });
1004
1029
  });