@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
@@ -1,29 +1,32 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import Database from 'better-sqlite3';
5
- import { AgentRegistry, RenameNotFoundError, RenameConflictError } from '../../utils/AgentRegistry.js';
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+ import Database from "better-sqlite3";
5
+ import { AgentRegistry, RenameNotFoundError, RenameConflictError } from "../../utils/AgentRegistry.js";
6
6
  function makeEntry(over = {}) {
7
7
  return {
8
- name: 'agent1',
9
- type: 'claude',
8
+ name: "agent1",
9
+ type: "claude",
10
10
  pid: process.pid,
11
- tmuxSession: 'agent1',
12
- cwd: '/tmp',
13
- startedAt: '2026-05-30T00:00:00.000Z',
14
- sessionId: 'sid-1',
15
- sessionFilePath: '/tmp/session.jsonl',
11
+ cwd: "/tmp",
12
+ startedAt: "2026-05-30T00:00:00.000Z",
13
+ sessionId: "sid-1",
14
+ sessionFilePath: "/tmp/session.jsonl",
16
15
  pinned: false,
16
+ runtime: "tmux",
17
+ runtimeRef: {
18
+ session: "agent1"
19
+ },
17
20
  ...over
18
21
  };
19
22
  }
20
- describe('AgentRegistry', ()=>{
23
+ describe("AgentRegistry", ()=>{
21
24
  let tmpDir;
22
25
  let regPath;
23
26
  let registry;
24
27
  beforeEach(()=>{
25
- tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-registry-'));
26
- regPath = path.join(tmpDir, 'nested', 'agents.json');
28
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "agent-registry-"));
29
+ regPath = path.join(tmpDir, "nested", "agents.json");
27
30
  registry = new AgentRegistry(regPath);
28
31
  });
29
32
  afterEach(()=>{
@@ -33,276 +36,345 @@ describe('AgentRegistry', ()=>{
33
36
  force: true
34
37
  });
35
38
  });
36
- describe('register', ()=>{
37
- it('creates the SQLite database and parent directory if missing', ()=>{
39
+ describe("register", ()=>{
40
+ it("creates the SQLite database and parent directory if missing", ()=>{
38
41
  registry.register(makeEntry());
39
- expect(fs.existsSync(regPath.replace(/\.json$/, '.db'))).toBe(true);
40
- expect(registry.list()[0].name).toBe('agent1');
42
+ expect(fs.existsSync(regPath.replace(/\.json$/, ".db"))).toBe(true);
43
+ expect(registry.list()[0].name).toBe("agent1");
41
44
  });
42
- it('appends a new entry when name is unique', ()=>{
45
+ it("appends a new entry when name is unique", ()=>{
43
46
  registry.register(makeEntry({
44
- name: 'a'
47
+ name: "a"
45
48
  }));
46
49
  registry.register(makeEntry({
47
- name: 'b',
50
+ name: "b",
48
51
  pid: process.ppid
49
52
  }));
50
53
  expect(registry.list()).toHaveLength(2);
51
54
  });
52
- it('upserts in place when type and pid already exist', ()=>{
55
+ it("upserts in place when type and pid already exist", ()=>{
53
56
  registry.register(makeEntry({
54
- name: 'a',
57
+ name: "a",
55
58
  pid: process.pid
56
59
  }));
57
60
  registry.register(makeEntry({
58
- name: 'fallback',
61
+ name: "fallback",
59
62
  pid: process.pid,
60
- tmuxSession: ''
63
+ runtimeRef: null
61
64
  }));
62
65
  const all = registry.list();
63
66
  expect(all).toHaveLength(1);
64
67
  expect(all[0].pid).toBe(process.pid);
65
- expect(all[0].name).toBe('a');
68
+ expect(all[0].name).toBe("a");
66
69
  });
67
- it('does not write through the legacy fixed .tmp path', ()=>{
70
+ it("does not write through the legacy fixed .tmp path", ()=>{
68
71
  registry.register(makeEntry());
69
72
  expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);
70
73
  });
71
- it('persists session fields', ()=>{
74
+ it("persists session fields", ()=>{
72
75
  registry.register(makeEntry({
73
- sessionId: 'sid-xyz',
74
- sessionFilePath: '/foo/bar.jsonl'
76
+ sessionId: "sid-xyz",
77
+ sessionFilePath: "/foo/bar.jsonl"
75
78
  }));
76
79
  const saved = registry.list()[0];
77
- expect(saved.sessionId).toBe('sid-xyz');
78
- expect(saved.sessionFilePath).toBe('/foo/bar.jsonl');
80
+ expect(saved.sessionId).toBe("sid-xyz");
81
+ expect(saved.sessionFilePath).toBe("/foo/bar.jsonl");
82
+ });
83
+ it("persists runtime metadata for Herdr-backed entries", ()=>{
84
+ const runtimeRef = {
85
+ session: "default",
86
+ paneId: "w1:p2",
87
+ agentName: "reviewer"
88
+ };
89
+ registry.register(makeEntry({
90
+ name: "reviewer",
91
+ runtime: "herdr",
92
+ runtimeRef
93
+ }));
94
+ expect(registry.lookup("reviewer")).toMatchObject({
95
+ runtime: "herdr",
96
+ runtimeRef
97
+ });
79
98
  });
80
- it('preserves existing tmuxSession when incoming is empty string', ()=>{
99
+ it("preserves existing identity and routing fields for same-pid refreshes", ()=>{
100
+ const runtimeRef = {
101
+ session: "default",
102
+ paneId: "w1:p2",
103
+ agentName: "requested-name"
104
+ };
81
105
  registry.register(makeEntry({
82
- name: 'a',
83
- tmuxSession: 'pinned'
106
+ name: "old-name",
107
+ pid: process.pid,
108
+ runtime: "tmux",
109
+ runtimeRef: {
110
+ session: "old-name"
111
+ },
112
+ cwd: "/original"
84
113
  }));
85
114
  registry.register(makeEntry({
86
- name: 'fallback',
87
- tmuxSession: '',
115
+ name: "requested-name",
116
+ pid: process.pid,
117
+ runtime: "herdr",
118
+ runtimeRef,
119
+ cwd: "/incoming"
120
+ }));
121
+ expect(registry.lookup("requested-name")).toBeNull();
122
+ expect(registry.lookup("old-name")).toMatchObject({
123
+ pid: process.pid,
124
+ runtime: "tmux",
125
+ runtimeRef: {
126
+ session: "old-name"
127
+ },
128
+ cwd: "/original"
129
+ });
130
+ });
131
+ it("preserves existing runtime ref when incoming runtime ref is empty", ()=>{
132
+ registry.register(makeEntry({
133
+ name: "a",
134
+ runtimeRef: {
135
+ session: "pinned"
136
+ }
137
+ }));
138
+ registry.register(makeEntry({
139
+ name: "fallback",
140
+ runtimeRef: null,
88
141
  pid: process.pid
89
142
  }));
90
- const saved = registry.lookup('a');
91
- expect(saved?.tmuxSession).toBe('pinned');
143
+ const saved = registry.lookup("a");
144
+ expect(saved?.runtimeRef).toEqual({
145
+ session: "pinned"
146
+ });
92
147
  expect(saved?.pid).toBe(process.pid);
93
148
  });
94
- it('lets a managed start entry replace a generated fallback for the same pid', ()=>{
149
+ it("defaults an empty tmux runtime ref from the tmux session", ()=>{
150
+ registry.register(makeEntry({
151
+ name: "a",
152
+ runtimeRef: null
153
+ }));
154
+ expect(registry.lookup("a")?.runtimeRef).toBeNull();
155
+ });
156
+ it("preserves an existing generated fallback for the same pid", ()=>{
95
157
  registry.register(makeEntry({
96
158
  name: `ai-devkit-${process.pid}`,
97
- tmuxSession: ''
159
+ runtimeRef: null
98
160
  }));
99
161
  registry.register(makeEntry({
100
- name: 'custom-name',
101
- tmuxSession: 'custom-name'
162
+ name: "custom-name",
163
+ runtimeRef: {
164
+ session: "custom-name"
165
+ }
102
166
  }));
103
- expect(registry.lookup('custom-name')?.tmuxSession).toBe('custom-name');
104
- expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();
167
+ expect(registry.lookup("custom-name")).toBeNull();
168
+ expect(registry.lookup(`ai-devkit-${process.pid}`)?.runtimeRef).toBeNull();
105
169
  expect(registry.list()).toHaveLength(1);
106
170
  });
107
- it('preserves an existing name conflict when its probe fails with EPERM', ()=>{
171
+ it("preserves an existing name conflict when its probe fails with EPERM", ()=>{
108
172
  registry.register(makeEntry({
109
- name: 'claimed-name',
173
+ name: "claimed-name",
110
174
  pid: process.pid
111
175
  }));
112
- vi.spyOn(process, 'kill').mockImplementation(()=>{
113
- throw Object.assign(new Error('operation not permitted'), {
114
- code: 'EPERM'
176
+ vi.spyOn(process, "kill").mockImplementation(()=>{
177
+ throw Object.assign(new Error("operation not permitted"), {
178
+ code: "EPERM"
115
179
  });
116
180
  });
117
181
  expect(()=>registry.register(makeEntry({
118
- name: 'claimed-name',
182
+ name: "claimed-name",
119
183
  pid: process.pid + 1
120
184
  }))).toThrow();
121
- expect(registry.lookup('claimed-name')?.pid).toBe(process.pid);
185
+ expect(registry.lookup("claimed-name")?.pid).toBe(process.pid);
122
186
  });
123
187
  });
124
- describe('registerBatch', ()=>{
125
- it('is a no-op on empty array', ()=>{
188
+ describe("registerBatch", ()=>{
189
+ it("is a no-op on empty array", ()=>{
126
190
  registry.registerBatch([]);
127
191
  expect(fs.existsSync(regPath)).toBe(false);
128
192
  });
129
- it('upserts multiple entries in a single batch', ()=>{
193
+ it("upserts multiple entries in a single batch", ()=>{
130
194
  registry.registerBatch([
131
195
  makeEntry({
132
- name: 'a'
196
+ name: "a"
133
197
  }),
134
198
  makeEntry({
135
- name: 'b',
199
+ name: "b",
136
200
  pid: process.pid + 1
137
201
  }),
138
202
  makeEntry({
139
- name: 'c',
203
+ name: "c",
140
204
  pid: process.pid + 2
141
205
  })
142
206
  ]);
143
207
  expect(registry.list()).toHaveLength(3);
144
208
  });
145
- it('applies the tmuxSession merge per entry', ()=>{
209
+ it("applies the tmux runtime ref merge per entry", ()=>{
146
210
  registry.register(makeEntry({
147
- name: 'a',
148
- tmuxSession: 'pinned'
211
+ name: "a",
212
+ runtimeRef: {
213
+ session: "pinned"
214
+ }
149
215
  }));
150
216
  registry.registerBatch([
151
217
  makeEntry({
152
- name: 'fallback',
153
- tmuxSession: '',
218
+ name: "fallback",
219
+ runtimeRef: null,
154
220
  pid: process.pid
155
221
  }),
156
222
  makeEntry({
157
- name: 'b',
158
- tmuxSession: '',
223
+ name: "b",
224
+ runtimeRef: null,
159
225
  pid: process.pid + 1
160
226
  })
161
227
  ]);
162
- expect(registry.lookup('a')?.tmuxSession).toBe('pinned');
163
- expect(registry.lookup('a')?.pid).toBe(process.pid);
164
- expect(registry.lookup('b')?.tmuxSession).toBe('');
228
+ expect(registry.lookup("a")?.runtimeRef).toEqual({
229
+ session: "pinned"
230
+ });
231
+ expect(registry.lookup("a")?.pid).toBe(process.pid);
232
+ expect(registry.lookup("b")?.runtimeRef).toBeNull();
165
233
  });
166
- it('handles concurrent registry instances without duplicate pid rows', ()=>{
234
+ it("handles concurrent registry instances without duplicate pid rows", ()=>{
167
235
  const other = new AgentRegistry(regPath);
168
236
  registry.register(makeEntry({
169
237
  name: `ai-devkit-${process.pid}`,
170
- tmuxSession: ''
238
+ runtimeRef: null
171
239
  }));
172
240
  other.register(makeEntry({
173
- name: 'custom-name',
174
- tmuxSession: 'custom-name'
241
+ name: "custom-name",
242
+ runtimeRef: {
243
+ session: "custom-name"
244
+ }
175
245
  }));
176
246
  registry.register(makeEntry({
177
247
  name: `ai-devkit-${process.pid}`,
178
- tmuxSession: ''
248
+ runtimeRef: null
179
249
  }));
180
250
  expect(registry.list()).toHaveLength(1);
181
- expect(registry.lookup('custom-name')?.pid).toBe(process.pid);
251
+ expect(registry.lookup(`ai-devkit-${process.pid}`)?.pid).toBe(process.pid);
182
252
  });
183
- it('cleans up a cross-type row when its pid has been reused', ()=>{
253
+ it("cleans up a cross-type row when its pid has been reused", ()=>{
184
254
  registry.register(makeEntry({
185
- name: 'old-claude',
186
- type: 'claude',
255
+ name: "old-claude",
256
+ type: "claude",
187
257
  pid: process.pid
188
258
  }));
189
259
  registry.register(makeEntry({
190
- name: 'new-codex',
191
- type: 'codex',
260
+ name: "new-codex",
261
+ type: "codex",
192
262
  pid: process.pid,
193
- tmuxSession: ''
263
+ runtimeRef: null
194
264
  }));
195
- expect(registry.lookup('old-claude')).toBeNull();
196
- expect(registry.lookup('new-codex')).toMatchObject({
197
- type: 'codex',
265
+ expect(registry.lookup("old-claude")).toBeNull();
266
+ expect(registry.lookup("new-codex")).toMatchObject({
267
+ type: "codex",
198
268
  pid: process.pid
199
269
  });
200
270
  expect(registry.list()).toHaveLength(1);
201
271
  });
202
- it('rolls back the whole batch when a live name conflict rejects one entry', ()=>{
272
+ it("rolls back the whole batch when a live name conflict rejects one entry", ()=>{
203
273
  registry.register(makeEntry({
204
- name: 'taken',
274
+ name: "taken",
205
275
  pid: process.pid
206
276
  }));
207
277
  expect(()=>registry.registerBatch([
208
278
  makeEntry({
209
- name: 'fresh',
279
+ name: "fresh",
210
280
  pid: 999998
211
281
  }),
212
282
  makeEntry({
213
- name: 'taken',
214
- type: 'codex',
283
+ name: "taken",
284
+ type: "codex",
215
285
  pid: 999997
216
286
  })
217
287
  ])).toThrow(/UNIQUE constraint failed/);
218
- expect(registry.lookup('fresh')).toBeNull();
219
- expect(registry.lookup('taken')?.pid).toBe(process.pid);
288
+ expect(registry.lookup("fresh")).toBeNull();
289
+ expect(registry.lookup("taken")?.pid).toBe(process.pid);
220
290
  });
221
291
  });
222
- describe('lookup', ()=>{
223
- it('returns null when name not found', ()=>{
224
- expect(registry.lookup('missing')).toBeNull();
292
+ describe("lookup", ()=>{
293
+ it("returns null when name not found", ()=>{
294
+ expect(registry.lookup("missing")).toBeNull();
225
295
  });
226
- it('returns the entry when name matches', ()=>{
296
+ it("returns the entry when name matches", ()=>{
227
297
  registry.register(makeEntry({
228
- name: 'a'
298
+ name: "a"
229
299
  }));
230
- expect(registry.lookup('a')?.name).toBe('a');
300
+ expect(registry.lookup("a")?.name).toBe("a");
231
301
  });
232
302
  });
233
- describe('pinning', ()=>{
234
- it('defaults new rows to unpinned and toggles the persisted state', ()=>{
303
+ describe("pinning", ()=>{
304
+ it("defaults new rows to unpinned and toggles the persisted state", ()=>{
235
305
  registry.register(makeEntry());
236
- expect(registry.lookup('agent1')?.pinned).toBe(false);
237
- expect(registry.togglePin('claude', process.pid)).toBe(true);
238
- expect(registry.lookup('agent1')?.pinned).toBe(true);
239
- expect(registry.togglePin('claude', process.pid)).toBe(false);
240
- expect(registry.lookup('agent1')?.pinned).toBe(false);
241
- });
242
- it('updates existing recency when toggled', ()=>{
243
- let now = new Date('2026-08-16T10:00:00.000Z');
306
+ expect(registry.lookup("agent1")?.pinned).toBe(false);
307
+ expect(registry.togglePin("claude", process.pid)).toBe(true);
308
+ expect(registry.lookup("agent1")?.pinned).toBe(true);
309
+ expect(registry.togglePin("claude", process.pid)).toBe(false);
310
+ expect(registry.lookup("agent1")?.pinned).toBe(false);
311
+ });
312
+ it("updates existing recency when toggled", ()=>{
313
+ let now = new Date("2026-08-16T10:00:00.000Z");
244
314
  const clocked = new AgentRegistry(regPath, {
245
315
  now: ()=>now
246
316
  });
247
317
  clocked.register(makeEntry());
248
- now = new Date('2026-08-16T10:01:00.000Z');
249
- clocked.togglePin('claude', process.pid);
250
- expect(clocked.lookup('agent1')?.updatedAt).toBe(now.toISOString());
251
- const db = new Database(regPath.replace(/\.json$/, '.db'), {
318
+ now = new Date("2026-08-16T10:01:00.000Z");
319
+ clocked.togglePin("claude", process.pid);
320
+ expect(clocked.lookup("agent1")?.updatedAt).toBe(now.toISOString());
321
+ const db = new Database(regPath.replace(/\.json$/, ".db"), {
252
322
  readonly: true
253
323
  });
254
- const row = db.prepare('SELECT updated_at FROM agents WHERE type = ? AND pid = ?').get('claude', process.pid);
324
+ const row = db.prepare("SELECT updated_at FROM agents WHERE type = ? AND pid = ?").get("claude", process.pid);
255
325
  db.close();
256
326
  expect(row.updated_at).toBe(now.toISOString());
257
327
  });
258
- it('returns null when the process row has disappeared', ()=>{
259
- expect(registry.togglePin('claude', 999999)).toBeNull();
328
+ it("returns null when the process row has disappeared", ()=>{
329
+ expect(registry.togglePin("claude", 999999)).toBeNull();
260
330
  });
261
- it('preserves a pin when poll registration updates the row', ()=>{
331
+ it("preserves a pin when poll registration updates the row", ()=>{
262
332
  registry.register(makeEntry({
263
- sessionId: 'before'
333
+ sessionId: "before"
264
334
  }));
265
- registry.togglePin('claude', process.pid);
335
+ registry.togglePin("claude", process.pid);
266
336
  registry.register(makeEntry({
267
- sessionId: 'after'
337
+ sessionId: "after"
268
338
  }));
269
- expect(registry.lookup('agent1')).toMatchObject({
270
- sessionId: 'after',
339
+ expect(registry.lookup("agent1")).toMatchObject({
340
+ sessionId: "after",
271
341
  pinned: true
272
342
  });
273
343
  });
274
- it('preserves a pin through rename', ()=>{
344
+ it("preserves a pin through rename", ()=>{
275
345
  registry.register(makeEntry({
276
- name: 'before'
346
+ name: "before"
277
347
  }));
278
- registry.togglePin('claude', process.pid);
279
- registry.rename('before', 'after');
280
- expect(registry.lookup('after')?.pinned).toBe(true);
348
+ registry.togglePin("claude", process.pid);
349
+ registry.rename("before", "after");
350
+ expect(registry.lookup("after")?.pinned).toBe(true);
281
351
  });
282
- it('removes the pin with a pruned process row', ()=>{
352
+ it("removes the pin with a pruned process row", ()=>{
283
353
  registry.register(makeEntry({
284
354
  pid: 999999
285
355
  }));
286
- registry.togglePin('claude', 999999);
356
+ registry.togglePin("claude", 999999);
287
357
  registry.prune();
288
- expect(registry.lookup('agent1')).toBeNull();
358
+ expect(registry.lookup("agent1")).toBeNull();
289
359
  });
290
- it('reports a clear error when a readonly registry toggles a pin', ()=>{
360
+ it("reports a clear error when a readonly registry toggles a pin", ()=>{
291
361
  registry.register(makeEntry());
292
362
  const readonlyRegistry = new AgentRegistry(regPath, {
293
363
  readonly: true
294
364
  });
295
- expect(()=>readonlyRegistry.togglePin('claude', process.pid)).toThrow(/readonly/i);
365
+ expect(()=>readonlyRegistry.togglePin("claude", process.pid)).toThrow(/readonly/i);
296
366
  });
297
367
  });
298
- describe('list', ()=>{
299
- it('returns empty array when database does not contain entries', ()=>{
368
+ describe("list", ()=>{
369
+ it("returns empty array when database does not contain entries", ()=>{
300
370
  expect(registry.list()).toEqual([]);
301
371
  });
302
- it('ignores existing legacy agents.json entries', ()=>{
372
+ it("ignores existing legacy agents.json entries", ()=>{
303
373
  const legacyEntry = makeEntry({
304
- name: 'legacy',
305
- tmuxSession: 'legacy'
374
+ name: "legacy",
375
+ runtimeRef: {
376
+ session: "legacy"
377
+ }
306
378
  });
307
379
  fs.mkdirSync(path.dirname(regPath), {
308
380
  recursive: true
@@ -311,63 +383,108 @@ describe('AgentRegistry', ()=>{
311
383
  entries: [
312
384
  legacyEntry
313
385
  ]
314
- }), 'utf8');
386
+ }), "utf8");
315
387
  const legacyRegistry = new AgentRegistry(regPath);
316
- expect(legacyRegistry.lookup('legacy')).toBeNull();
388
+ expect(legacyRegistry.lookup("legacy")).toBeNull();
317
389
  expect(legacyRegistry.list()).toEqual([]);
318
- expect(fs.existsSync(regPath.replace(/\.json$/, '.db'))).toBe(true);
390
+ expect(fs.existsSync(regPath.replace(/\.json$/, ".db"))).toBe(true);
391
+ });
392
+ it("reads pre-runtime SQLite rows as tmux-backed records", ()=>{
393
+ const dbPath = regPath.replace(/\.json$/, ".db");
394
+ fs.mkdirSync(path.dirname(dbPath), {
395
+ recursive: true
396
+ });
397
+ fs.rmSync(dbPath, {
398
+ force: true
399
+ });
400
+ fs.rmSync(`${dbPath}-wal`, {
401
+ force: true
402
+ });
403
+ fs.rmSync(`${dbPath}-shm`, {
404
+ force: true
405
+ });
406
+ const db = new Database(dbPath);
407
+ db.exec(`
408
+ CREATE TABLE agents (
409
+ type TEXT NOT NULL,
410
+ pid INTEGER NOT NULL,
411
+ name TEXT NOT NULL UNIQUE,
412
+ tmux_session TEXT NOT NULL DEFAULT '',
413
+ cwd TEXT NOT NULL DEFAULT '',
414
+ started_at TEXT NOT NULL,
415
+ session_id TEXT NOT NULL DEFAULT '',
416
+ session_file_path TEXT NOT NULL DEFAULT '',
417
+ updated_at TEXT NOT NULL,
418
+ PRIMARY KEY (type, pid)
419
+ );
420
+ INSERT INTO agents (
421
+ type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at
422
+ ) VALUES (
423
+ 'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',
424
+ '2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'
425
+ );
426
+ PRAGMA user_version = 1;
427
+ `);
428
+ db.close();
429
+ const migratedRegistry = new AgentRegistry(regPath);
430
+ expect(migratedRegistry.lookup("legacy-sqlite")).toMatchObject({
431
+ runtime: "tmux",
432
+ runtimeRef: {
433
+ session: "legacy-sqlite"
434
+ }
435
+ });
319
436
  });
320
437
  });
321
- describe('isAlive', ()=>{
322
- it('returns true for the current process', ()=>{
438
+ describe("isAlive", ()=>{
439
+ it("returns true for the current process", ()=>{
323
440
  expect(registry.isAlive(makeEntry({
324
441
  pid: process.pid
325
442
  }))).toBe(true);
326
443
  });
327
- it('returns false for a PID that does not exist', ()=>{
444
+ it("returns false for a PID that does not exist", ()=>{
328
445
  expect(registry.isAlive(makeEntry({
329
446
  pid: 999999
330
447
  }))).toBe(false);
331
448
  });
332
- it('returns true when the process probe is forbidden with EPERM', ()=>{
333
- vi.spyOn(process, 'kill').mockImplementation(()=>{
334
- throw Object.assign(new Error('operation not permitted'), {
335
- code: 'EPERM'
449
+ it("returns true when the process probe is forbidden with EPERM", ()=>{
450
+ vi.spyOn(process, "kill").mockImplementation(()=>{
451
+ throw Object.assign(new Error("operation not permitted"), {
452
+ code: "EPERM"
336
453
  });
337
454
  });
338
455
  expect(registry.isAlive(makeEntry())).toBe(true);
339
456
  });
340
- it('returns false when the process probe reports ESRCH', ()=>{
341
- vi.spyOn(process, 'kill').mockImplementation(()=>{
342
- throw Object.assign(new Error('no such process'), {
343
- code: 'ESRCH'
457
+ it("returns false when the process probe reports ESRCH", ()=>{
458
+ vi.spyOn(process, "kill").mockImplementation(()=>{
459
+ throw Object.assign(new Error("no such process"), {
460
+ code: "ESRCH"
344
461
  });
345
462
  });
346
463
  expect(registry.isAlive(makeEntry())).toBe(false);
347
464
  });
348
- it('returns true when the process probe fails without a definitive error code', ()=>{
349
- vi.spyOn(process, 'kill').mockImplementation(()=>{
350
- throw new Error('indeterminate probe failure');
465
+ it("returns true when the process probe fails without a definitive error code", ()=>{
466
+ vi.spyOn(process, "kill").mockImplementation(()=>{
467
+ throw new Error("indeterminate probe failure");
351
468
  });
352
469
  expect(registry.isAlive(makeEntry())).toBe(true);
353
470
  });
354
471
  });
355
- describe('prune', ()=>{
356
- it('removes entries whose PIDs are dead', ()=>{
472
+ describe("prune", ()=>{
473
+ it("removes entries whose PIDs are dead", ()=>{
357
474
  registry.register(makeEntry({
358
- name: 'alive',
475
+ name: "alive",
359
476
  pid: process.pid
360
477
  }));
361
478
  registry.register(makeEntry({
362
- name: 'dead',
479
+ name: "dead",
363
480
  pid: 999999
364
481
  }));
365
482
  registry.prune();
366
483
  const remaining = registry.list();
367
484
  expect(remaining).toHaveLength(1);
368
- expect(remaining[0].name).toBe('alive');
485
+ expect(remaining[0].name).toBe("alive");
369
486
  });
370
- it('is a no-op when all entries are alive', ()=>{
487
+ it("is a no-op when all entries are alive", ()=>{
371
488
  registry.register(makeEntry({
372
489
  pid: process.pid
373
490
  }));
@@ -376,133 +493,141 @@ describe('AgentRegistry', ()=>{
376
493
  const after = registry.list();
377
494
  expect(after).toEqual(before);
378
495
  });
379
- it('preserves entries when liveness probing fails with EPERM', ()=>{
496
+ it("preserves entries when liveness probing fails with EPERM", ()=>{
380
497
  registry.register(makeEntry({
381
- name: 'custom-name',
382
- tmuxSession: 'tmux-custom'
498
+ name: "custom-name",
499
+ runtimeRef: {
500
+ session: "tmux-custom"
501
+ }
383
502
  }));
384
- vi.spyOn(process, 'kill').mockImplementation(()=>{
385
- throw Object.assign(new Error('operation not permitted'), {
386
- code: 'EPERM'
503
+ vi.spyOn(process, "kill").mockImplementation(()=>{
504
+ throw Object.assign(new Error("operation not permitted"), {
505
+ code: "EPERM"
387
506
  });
388
507
  });
389
508
  registry.prune();
390
- expect(registry.lookup('custom-name')).toMatchObject({
391
- name: 'custom-name',
392
- tmuxSession: 'tmux-custom'
509
+ expect(registry.lookup("custom-name")).toMatchObject({
510
+ name: "custom-name",
511
+ runtimeRef: {
512
+ session: "tmux-custom"
513
+ }
393
514
  });
394
515
  });
395
- it('removes entries when liveness probing fails with ESRCH', ()=>{
516
+ it("removes entries when liveness probing fails with ESRCH", ()=>{
396
517
  registry.register(makeEntry({
397
- name: 'dead'
518
+ name: "dead"
398
519
  }));
399
- vi.spyOn(process, 'kill').mockImplementation(()=>{
400
- throw Object.assign(new Error('no such process'), {
401
- code: 'ESRCH'
520
+ vi.spyOn(process, "kill").mockImplementation(()=>{
521
+ throw Object.assign(new Error("no such process"), {
522
+ code: "ESRCH"
402
523
  });
403
524
  });
404
525
  registry.prune();
405
- expect(registry.lookup('dead')).toBeNull();
526
+ expect(registry.lookup("dead")).toBeNull();
406
527
  });
407
- it('does nothing when file is missing', ()=>{
528
+ it("does nothing when file is missing", ()=>{
408
529
  expect(()=>registry.prune()).not.toThrow();
409
530
  });
410
- it('keeps forced prune available before the passive cadence is due', ()=>{
411
- let nowMs = Date.parse('2026-08-14T10:00:00.000Z');
531
+ it("keeps forced prune available before the passive cadence is due", ()=>{
532
+ let nowMs = Date.parse("2026-08-14T10:00:00.000Z");
412
533
  const clocked = new AgentRegistry(regPath, {
413
534
  now: ()=>new Date(nowMs),
414
535
  pruneIntervalMs: 30_000
415
536
  });
416
537
  clocked.register(makeEntry({
417
- name: 'forced',
538
+ name: "forced",
418
539
  pid: process.pid
419
540
  }));
420
- const alive = vi.spyOn(clocked, 'isAlive').mockReturnValue(true);
541
+ const alive = vi.spyOn(clocked, "isAlive").mockReturnValue(true);
421
542
  clocked.pruneIfDue();
422
543
  alive.mockReturnValue(false);
423
544
  nowMs += 1;
424
545
  clocked.prune();
425
546
  expect(alive).toHaveBeenCalledTimes(2);
426
- expect(clocked.lookup('forced')).toBeNull();
547
+ expect(clocked.lookup("forced")).toBeNull();
427
548
  });
428
549
  });
429
- describe('default()', ()=>{
430
- it('returns a singleton instance', ()=>{
550
+ describe("default()", ()=>{
551
+ it("returns a singleton instance", ()=>{
431
552
  expect(AgentRegistry.default()).toBe(AgentRegistry.default());
432
553
  });
433
554
  });
434
- describe('rename', ()=>{
435
- it('updates the name of an existing entry', ()=>{
555
+ describe("rename", ()=>{
556
+ it("updates the name of an existing entry", ()=>{
436
557
  registry.register(makeEntry({
437
- name: 'old-name',
558
+ name: "old-name",
438
559
  pid: process.pid
439
560
  }));
440
- registry.rename('old-name', 'new-name');
441
- expect(registry.lookup('new-name')?.name).toBe('new-name');
442
- expect(registry.lookup('old-name')).toBeNull();
561
+ registry.rename("old-name", "new-name");
562
+ expect(registry.lookup("new-name")?.name).toBe("new-name");
563
+ expect(registry.lookup("old-name")).toBeNull();
443
564
  });
444
- it('preserves all other fields on the renamed entry', ()=>{
565
+ it("preserves all other fields on the renamed entry", ()=>{
445
566
  registry.register(makeEntry({
446
- name: 'old-name',
567
+ name: "old-name",
447
568
  pid: process.pid,
448
- tmuxSession: 'old-name',
449
- cwd: '/my/cwd'
450
- }));
451
- registry.rename('old-name', 'new-name');
452
- const entry = registry.lookup('new-name');
453
- expect(entry?.tmuxSession).toBe('old-name');
454
- expect(entry?.cwd).toBe('/my/cwd');
569
+ runtimeRef: {
570
+ session: "old-name"
571
+ },
572
+ cwd: "/my/cwd"
573
+ }));
574
+ registry.rename("old-name", "new-name");
575
+ const entry = registry.lookup("new-name");
576
+ expect(entry?.runtimeRef).toEqual({
577
+ session: "old-name"
578
+ });
579
+ expect(entry?.cwd).toBe("/my/cwd");
455
580
  expect(entry?.pid).toBe(process.pid);
456
581
  });
457
- it('throws RenameNotFoundError when current name does not exist', ()=>{
458
- expect(()=>registry.rename('ghost', 'new-name')).toThrow(RenameNotFoundError);
582
+ it("throws RenameNotFoundError when current name does not exist", ()=>{
583
+ expect(()=>registry.rename("ghost", "new-name")).toThrow(RenameNotFoundError);
459
584
  });
460
- it('throws RenameConflictError when new name is already in use by a live entry', ()=>{
585
+ it("throws RenameConflictError when new name is already in use by a live entry", ()=>{
461
586
  registry.register(makeEntry({
462
- name: 'agent-a',
587
+ name: "agent-a",
463
588
  pid: process.pid
464
589
  }));
465
590
  registry.register(makeEntry({
466
- name: 'agent-b',
591
+ name: "agent-b",
467
592
  pid: process.ppid
468
593
  }));
469
- expect(()=>registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);
594
+ expect(()=>registry.rename("agent-a", "agent-b")).toThrow(RenameConflictError);
470
595
  });
471
- it('throws RenameConflictError when the conflicting entry probe fails with EPERM', ()=>{
596
+ it("throws RenameConflictError when the conflicting entry probe fails with EPERM", ()=>{
472
597
  registry.register(makeEntry({
473
- name: 'agent-a',
598
+ name: "agent-a",
474
599
  pid: process.pid
475
600
  }));
476
601
  registry.register(makeEntry({
477
- name: 'agent-b',
602
+ name: "agent-b",
478
603
  pid: process.ppid
479
604
  }));
480
- vi.spyOn(process, 'kill').mockImplementation(()=>{
481
- throw Object.assign(new Error('operation not permitted'), {
482
- code: 'EPERM'
605
+ vi.spyOn(process, "kill").mockImplementation(()=>{
606
+ throw Object.assign(new Error("operation not permitted"), {
607
+ code: "EPERM"
483
608
  });
484
609
  });
485
- expect(()=>registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);
486
- expect(registry.lookup('agent-b')?.pid).toBe(process.ppid);
610
+ expect(()=>registry.rename("agent-a", "agent-b")).toThrow(RenameConflictError);
611
+ expect(registry.lookup("agent-b")?.pid).toBe(process.ppid);
487
612
  });
488
- it('succeeds when new name exists only as a stale (dead) entry', ()=>{
613
+ it("succeeds when new name exists only as a stale (dead) entry", ()=>{
489
614
  registry.register(makeEntry({
490
- name: 'agent-a',
615
+ name: "agent-a",
491
616
  pid: process.pid
492
617
  }));
493
618
  registry.register(makeEntry({
494
- name: 'agent-b',
619
+ name: "agent-b",
495
620
  pid: 999999
496
621
  }));
497
- expect(()=>registry.rename('agent-a', 'agent-b')).not.toThrow();
498
- expect(registry.lookup('agent-b')?.pid).toBe(process.pid);
622
+ expect(()=>registry.rename("agent-a", "agent-b")).not.toThrow();
623
+ expect(registry.lookup("agent-b")?.pid).toBe(process.pid);
499
624
  });
500
- it('does not create the legacy fixed .tmp path on rename', ()=>{
625
+ it("does not create the legacy fixed .tmp path on rename", ()=>{
501
626
  registry.register(makeEntry({
502
- name: 'old-name',
627
+ name: "old-name",
503
628
  pid: process.pid
504
629
  }));
505
- registry.rename('old-name', 'new-name');
630
+ registry.rename("old-name", "new-name");
506
631
  expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);
507
632
  });
508
633
  });