@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 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport path from 'path';\nimport Database from 'better-sqlite3';\nimport { AgentRegistry, RenameNotFoundError, RenameConflictError, type RegistryEntry } from '../../utils/AgentRegistry.js';\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: 'agent1',\n type: 'claude',\n pid: process.pid,\n tmuxSession: 'agent1',\n cwd: '/tmp',\n startedAt: '2026-05-30T00:00:00.000Z',\n sessionId: 'sid-1',\n sessionFilePath: '/tmp/session.jsonl',\n pinned: false,\n ...over,\n };\n}\n\ndescribe('AgentRegistry', () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-registry-'));\n regPath = path.join(tmpDir, 'nested', 'agents.json');\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe('register', () => {\n it('creates the SQLite database and parent directory if missing', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n expect(registry.list()[0].name).toBe('agent1');\n });\n\n it('appends a new entry when name is unique', () => {\n registry.register(makeEntry({ name: 'a' }));\n registry.register(makeEntry({ name: 'b', pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it('upserts in place when type and pid already exist', () => {\n registry.register(makeEntry({ name: 'a', pid: process.pid }));\n registry.register(makeEntry({ name: 'fallback', pid: process.pid, tmuxSession: '' }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe('a');\n });\n\n it('does not write through the legacy fixed .tmp path', () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it('persists session fields', () => {\n registry.register(makeEntry({ sessionId: 'sid-xyz', sessionFilePath: '/foo/bar.jsonl' }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe('sid-xyz');\n expect(saved.sessionFilePath).toBe('/foo/bar.jsonl');\n });\n\n it('preserves existing tmuxSession when incoming is empty string', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.register(makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }));\n const saved = registry.lookup('a');\n expect(saved?.tmuxSession).toBe('pinned');\n expect(saved?.pid).toBe(process.pid);\n });\n\n it('lets a managed start entry replace a generated fallback for the same pid', () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n expect(registry.lookup('custom-name')?.tmuxSession).toBe('custom-name');\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it('preserves an existing name conflict when its probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'claimed-name', pid: process.pid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.register(makeEntry({\n name: 'claimed-name',\n pid: process.pid + 1,\n }))).toThrow();\n expect(registry.lookup('claimed-name')?.pid).toBe(process.pid);\n });\n });\n\n describe('registerBatch', () => {\n it('is a no-op on empty array', () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it('upserts multiple entries in a single batch', () => {\n registry.registerBatch([\n makeEntry({ name: 'a' }),\n makeEntry({ name: 'b', pid: process.pid + 1 }),\n makeEntry({ name: 'c', pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it('applies the tmuxSession merge per entry', () => {\n registry.register(makeEntry({ name: 'a', tmuxSession: 'pinned' }));\n registry.registerBatch([\n makeEntry({ name: 'fallback', tmuxSession: '', pid: process.pid }),\n makeEntry({ name: 'b', tmuxSession: '', pid: process.pid + 1 }),\n ]);\n expect(registry.lookup('a')?.tmuxSession).toBe('pinned');\n expect(registry.lookup('a')?.pid).toBe(process.pid);\n expect(registry.lookup('b')?.tmuxSession).toBe('');\n });\n\n it('handles concurrent registry instances without duplicate pid rows', () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n other.register(makeEntry({ name: 'custom-name', tmuxSession: 'custom-name' }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, tmuxSession: '' }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup('custom-name')?.pid).toBe(process.pid);\n });\n\n it('cleans up a cross-type row when its pid has been reused', () => {\n registry.register(makeEntry({ name: 'old-claude', type: 'claude', pid: process.pid }));\n\n registry.register(makeEntry({\n name: 'new-codex',\n type: 'codex',\n pid: process.pid,\n tmuxSession: '',\n }));\n\n expect(registry.lookup('old-claude')).toBeNull();\n expect(registry.lookup('new-codex')).toMatchObject({ type: 'codex', pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it('rolls back the whole batch when a live name conflict rejects one entry', () => {\n registry.register(makeEntry({ name: 'taken', pid: process.pid }));\n\n expect(() => registry.registerBatch([\n makeEntry({ name: 'fresh', pid: 999998 }),\n makeEntry({ name: 'taken', type: 'codex', pid: 999997 }),\n ])).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup('fresh')).toBeNull();\n expect(registry.lookup('taken')?.pid).toBe(process.pid);\n });\n });\n\n describe('lookup', () => {\n it('returns null when name not found', () => {\n expect(registry.lookup('missing')).toBeNull();\n });\n\n it('returns the entry when name matches', () => {\n registry.register(makeEntry({ name: 'a' }));\n expect(registry.lookup('a')?.name).toBe('a');\n });\n });\n\n describe('pinning', () => {\n it('defaults new rows to unpinned and toggles the persisted state', () => {\n registry.register(makeEntry());\n\n expect(registry.lookup('agent1')?.pinned).toBe(false);\n expect(registry.togglePin('claude', process.pid)).toBe(true);\n expect(registry.lookup('agent1')?.pinned).toBe(true);\n expect(registry.togglePin('claude', process.pid)).toBe(false);\n expect(registry.lookup('agent1')?.pinned).toBe(false);\n });\n\n it('updates existing recency when toggled', () => {\n let now = new Date('2026-08-16T10:00:00.000Z');\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date('2026-08-16T10:01:00.000Z');\n\n clocked.togglePin('claude', process.pid);\n\n expect(clocked.lookup('agent1')?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, '.db'), { readonly: true });\n const row = db.prepare('SELECT updated_at FROM agents WHERE type = ? AND pid = ?')\n .get('claude', process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it('returns null when the process row has disappeared', () => {\n expect(registry.togglePin('claude', 999999)).toBeNull();\n });\n\n it('preserves a pin when poll registration updates the row', () => {\n registry.register(makeEntry({ sessionId: 'before' }));\n registry.togglePin('claude', process.pid);\n\n registry.register(makeEntry({ sessionId: 'after' }));\n\n expect(registry.lookup('agent1')).toMatchObject({ sessionId: 'after', pinned: true });\n });\n\n it('preserves a pin through rename', () => {\n registry.register(makeEntry({ name: 'before' }));\n registry.togglePin('claude', process.pid);\n\n registry.rename('before', 'after');\n\n expect(registry.lookup('after')?.pinned).toBe(true);\n });\n\n it('removes the pin with a pruned process row', () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin('claude', 999999);\n\n registry.prune();\n\n expect(registry.lookup('agent1')).toBeNull();\n });\n\n it('reports a clear error when a readonly registry toggles a pin', () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin('claude', process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe('list', () => {\n it('returns empty array when database does not contain entries', () => {\n expect(registry.list()).toEqual([]);\n });\n\n it('ignores existing legacy agents.json entries', () => {\n const legacyEntry = makeEntry({ name: 'legacy', tmuxSession: 'legacy' });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), 'utf8');\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup('legacy')).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, '.db'))).toBe(true);\n });\n });\n\n describe('isAlive', () => {\n it('returns true for the current process', () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it('returns false for a PID that does not exist', () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it('returns true when the process probe is forbidden with EPERM', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it('returns false when the process probe reports ESRCH', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it('returns true when the process probe fails without a definitive error code', () => {\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw new Error('indeterminate probe failure');\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe('prune', () => {\n it('removes entries whose PIDs are dead', () => {\n registry.register(makeEntry({ name: 'alive', pid: process.pid }));\n registry.register(makeEntry({ name: 'dead', pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe('alive');\n });\n\n it('is a no-op when all entries are alive', () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it('preserves entries when liveness probing fails with EPERM', () => {\n registry.register(makeEntry({ name: 'custom-name', tmuxSession: 'tmux-custom' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n registry.prune();\n\n expect(registry.lookup('custom-name')).toMatchObject({\n name: 'custom-name',\n tmuxSession: 'tmux-custom',\n });\n });\n\n it('removes entries when liveness probing fails with ESRCH', () => {\n registry.register(makeEntry({ name: 'dead' }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('no such process'), { code: 'ESRCH' });\n });\n\n registry.prune();\n\n expect(registry.lookup('dead')).toBeNull();\n });\n\n it('does nothing when file is missing', () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it('keeps forced prune available before the passive cadence is due', () => {\n let nowMs = Date.parse('2026-08-14T10:00:00.000Z');\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: 'forced', pid: process.pid }));\n const alive = vi.spyOn(clocked, 'isAlive').mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup('forced')).toBeNull();\n });\n });\n\n describe('default()', () => {\n it('returns a singleton instance', () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe('rename', () => {\n it('updates the name of an existing entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(registry.lookup('new-name')?.name).toBe('new-name');\n expect(registry.lookup('old-name')).toBeNull();\n });\n\n it('preserves all other fields on the renamed entry', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid, tmuxSession: 'old-name', cwd: '/my/cwd' }));\n registry.rename('old-name', 'new-name');\n const entry = registry.lookup('new-name');\n expect(entry?.tmuxSession).toBe('old-name');\n expect(entry?.cwd).toBe('/my/cwd');\n expect(entry?.pid).toBe(process.pid);\n });\n\n it('throws RenameNotFoundError when current name does not exist', () => {\n expect(() => registry.rename('ghost', 'new-name')).toThrow(RenameNotFoundError);\n });\n\n it('throws RenameConflictError when new name is already in use by a live entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n });\n\n it('throws RenameConflictError when the conflicting entry probe fails with EPERM', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: process.ppid }));\n vi.spyOn(process, 'kill').mockImplementation(() => {\n throw Object.assign(new Error('operation not permitted'), { code: 'EPERM' });\n });\n\n expect(() => registry.rename('agent-a', 'agent-b')).toThrow(RenameConflictError);\n expect(registry.lookup('agent-b')?.pid).toBe(process.ppid);\n });\n\n it('succeeds when new name exists only as a stale (dead) entry', () => {\n registry.register(makeEntry({ name: 'agent-a', pid: process.pid }));\n registry.register(makeEntry({ name: 'agent-b', pid: 999999 }));\n expect(() => registry.rename('agent-a', 'agent-b')).not.toThrow();\n expect(registry.lookup('agent-b')?.pid).toBe(process.pid);\n });\n\n it('does not create the legacy fixed .tmp path on rename', () => {\n registry.register(makeEntry({ name: 'old-name', pid: process.pid }));\n registry.rename('old-name', 'new-name');\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","tmuxSession","cwd","startedAt","sessionId","sessionFilePath","pinned","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","lookup","toBeNull","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","toMatchObject","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","toEqual","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/utils/AgentRegistry.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport Database from \"better-sqlite3\";\nimport {\n AgentRegistry,\n RenameNotFoundError,\n RenameConflictError,\n type RegistryEntry,\n} from \"../../utils/AgentRegistry.js\";\n\nfunction makeEntry(over: Partial<RegistryEntry> = {}): RegistryEntry {\n return {\n name: \"agent1\",\n type: \"claude\",\n pid: process.pid,\n cwd: \"/tmp\",\n startedAt: \"2026-05-30T00:00:00.000Z\",\n sessionId: \"sid-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n pinned: false,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n ...over,\n };\n}\n\ndescribe(\"AgentRegistry\", () => {\n let tmpDir: string;\n let regPath: string;\n let registry: AgentRegistry;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"agent-registry-\"));\n regPath = path.join(tmpDir, \"nested\", \"agents.json\");\n registry = new AgentRegistry(regPath);\n });\n\n afterEach(() => {\n vi.restoreAllMocks();\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"register\", () => {\n it(\"creates the SQLite database and parent directory if missing\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n expect(registry.list()[0].name).toBe(\"agent1\");\n });\n\n it(\"appends a new entry when name is unique\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n registry.register(makeEntry({ name: \"b\", pid: process.ppid }));\n expect(registry.list()).toHaveLength(2);\n });\n\n it(\"upserts in place when type and pid already exist\", () => {\n registry.register(makeEntry({ name: \"a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"fallback\", pid: process.pid, runtimeRef: null }));\n const all = registry.list();\n expect(all).toHaveLength(1);\n expect(all[0].pid).toBe(process.pid);\n expect(all[0].name).toBe(\"a\");\n });\n\n it(\"does not write through the legacy fixed .tmp path\", () => {\n registry.register(makeEntry());\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n\n it(\"persists session fields\", () => {\n registry.register(makeEntry({ sessionId: \"sid-xyz\", sessionFilePath: \"/foo/bar.jsonl\" }));\n const saved = registry.list()[0];\n expect(saved.sessionId).toBe(\"sid-xyz\");\n expect(saved.sessionFilePath).toBe(\"/foo/bar.jsonl\");\n });\n\n it(\"persists runtime metadata for Herdr-backed entries\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"reviewer\" };\n\n registry.register(\n makeEntry({\n name: \"reviewer\",\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"reviewer\")).toMatchObject({\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"lets a Herdr managed start replace an existing same-pid name\", () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"requested-name\" };\n\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.register(\n makeEntry({\n name: \"requested-name\",\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n }),\n );\n\n expect(registry.lookup(\"old-name\")).toBeNull();\n expect(registry.lookup(\"requested-name\")).toMatchObject({\n pid: process.pid,\n runtime: \"herdr\",\n runtimeRef,\n });\n });\n\n it(\"preserves existing runtime ref when incoming runtime ref is empty\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.register(makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }));\n const saved = registry.lookup(\"a\");\n expect(saved?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(saved?.pid).toBe(process.pid);\n });\n\n it(\"defaults an empty tmux runtime ref from the tmux session\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: null }));\n\n expect(registry.lookup(\"a\")?.runtimeRef).toBeNull();\n });\n\n it(\"lets a managed start entry replace a generated fallback for the same pid\", () => {\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n expect(registry.lookup(\"custom-name\")?.runtimeRef).toEqual({ session: \"custom-name\" });\n expect(registry.lookup(`ai-devkit-${process.pid}`)).toBeNull();\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"preserves an existing name conflict when its probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"claimed-name\", pid: process.pid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() =>\n registry.register(\n makeEntry({\n name: \"claimed-name\",\n pid: process.pid + 1,\n }),\n ),\n ).toThrow();\n expect(registry.lookup(\"claimed-name\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"registerBatch\", () => {\n it(\"is a no-op on empty array\", () => {\n registry.registerBatch([]);\n expect(fs.existsSync(regPath)).toBe(false);\n });\n\n it(\"upserts multiple entries in a single batch\", () => {\n registry.registerBatch([\n makeEntry({ name: \"a\" }),\n makeEntry({ name: \"b\", pid: process.pid + 1 }),\n makeEntry({ name: \"c\", pid: process.pid + 2 }),\n ]);\n expect(registry.list()).toHaveLength(3);\n });\n\n it(\"applies the tmux runtime ref merge per entry\", () => {\n registry.register(makeEntry({ name: \"a\", runtimeRef: { session: \"pinned\" } }));\n registry.registerBatch([\n makeEntry({ name: \"fallback\", runtimeRef: null, pid: process.pid }),\n makeEntry({ name: \"b\", runtimeRef: null, pid: process.pid + 1 }),\n ]);\n expect(registry.lookup(\"a\")?.runtimeRef).toEqual({ session: \"pinned\" });\n expect(registry.lookup(\"a\")?.pid).toBe(process.pid);\n expect(registry.lookup(\"b\")?.runtimeRef).toBeNull();\n });\n\n it(\"handles concurrent registry instances without duplicate pid rows\", () => {\n const other = new AgentRegistry(regPath);\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n other.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"custom-name\" } }));\n registry.register(makeEntry({ name: `ai-devkit-${process.pid}`, runtimeRef: null }));\n\n expect(registry.list()).toHaveLength(1);\n expect(registry.lookup(\"custom-name\")?.pid).toBe(process.pid);\n });\n\n it(\"cleans up a cross-type row when its pid has been reused\", () => {\n registry.register(makeEntry({ name: \"old-claude\", type: \"claude\", pid: process.pid }));\n\n registry.register(\n makeEntry({\n name: \"new-codex\",\n type: \"codex\",\n pid: process.pid,\n runtimeRef: null,\n }),\n );\n\n expect(registry.lookup(\"old-claude\")).toBeNull();\n expect(registry.lookup(\"new-codex\")).toMatchObject({ type: \"codex\", pid: process.pid });\n expect(registry.list()).toHaveLength(1);\n });\n\n it(\"rolls back the whole batch when a live name conflict rejects one entry\", () => {\n registry.register(makeEntry({ name: \"taken\", pid: process.pid }));\n\n expect(() =>\n registry.registerBatch([\n makeEntry({ name: \"fresh\", pid: 999998 }),\n makeEntry({ name: \"taken\", type: \"codex\", pid: 999997 }),\n ]),\n ).toThrow(/UNIQUE constraint failed/);\n\n expect(registry.lookup(\"fresh\")).toBeNull();\n expect(registry.lookup(\"taken\")?.pid).toBe(process.pid);\n });\n });\n\n describe(\"lookup\", () => {\n it(\"returns null when name not found\", () => {\n expect(registry.lookup(\"missing\")).toBeNull();\n });\n\n it(\"returns the entry when name matches\", () => {\n registry.register(makeEntry({ name: \"a\" }));\n expect(registry.lookup(\"a\")?.name).toBe(\"a\");\n });\n });\n\n describe(\"pinning\", () => {\n it(\"defaults new rows to unpinned and toggles the persisted state\", () => {\n registry.register(makeEntry());\n\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(true);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(true);\n expect(registry.togglePin(\"claude\", process.pid)).toBe(false);\n expect(registry.lookup(\"agent1\")?.pinned).toBe(false);\n });\n\n it(\"updates existing recency when toggled\", () => {\n let now = new Date(\"2026-08-16T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, { now: () => now });\n clocked.register(makeEntry());\n now = new Date(\"2026-08-16T10:01:00.000Z\");\n\n clocked.togglePin(\"claude\", process.pid);\n\n expect(clocked.lookup(\"agent1\")?.updatedAt).toBe(now.toISOString());\n const db = new Database(regPath.replace(/\\.json$/, \".db\"), { readonly: true });\n const row = db\n .prepare(\"SELECT updated_at FROM agents WHERE type = ? AND pid = ?\")\n .get(\"claude\", process.pid) as { updated_at: string };\n db.close();\n expect(row.updated_at).toBe(now.toISOString());\n });\n\n it(\"returns null when the process row has disappeared\", () => {\n expect(registry.togglePin(\"claude\", 999999)).toBeNull();\n });\n\n it(\"preserves a pin when poll registration updates the row\", () => {\n registry.register(makeEntry({ sessionId: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.register(makeEntry({ sessionId: \"after\" }));\n\n expect(registry.lookup(\"agent1\")).toMatchObject({ sessionId: \"after\", pinned: true });\n });\n\n it(\"preserves a pin through rename\", () => {\n registry.register(makeEntry({ name: \"before\" }));\n registry.togglePin(\"claude\", process.pid);\n\n registry.rename(\"before\", \"after\");\n\n expect(registry.lookup(\"after\")?.pinned).toBe(true);\n });\n\n it(\"removes the pin with a pruned process row\", () => {\n registry.register(makeEntry({ pid: 999999 }));\n registry.togglePin(\"claude\", 999999);\n\n registry.prune();\n\n expect(registry.lookup(\"agent1\")).toBeNull();\n });\n\n it(\"reports a clear error when a readonly registry toggles a pin\", () => {\n registry.register(makeEntry());\n const readonlyRegistry = new AgentRegistry(regPath, { readonly: true });\n\n expect(() => readonlyRegistry.togglePin(\"claude\", process.pid)).toThrow(/readonly/i);\n });\n });\n\n describe(\"list\", () => {\n it(\"returns empty array when database does not contain entries\", () => {\n expect(registry.list()).toEqual([]);\n });\n\n it(\"ignores existing legacy agents.json entries\", () => {\n const legacyEntry = makeEntry({ name: \"legacy\", runtimeRef: { session: \"legacy\" } });\n fs.mkdirSync(path.dirname(regPath), { recursive: true });\n fs.writeFileSync(regPath, JSON.stringify({ entries: [legacyEntry] }), \"utf8\");\n\n const legacyRegistry = new AgentRegistry(regPath);\n\n expect(legacyRegistry.lookup(\"legacy\")).toBeNull();\n expect(legacyRegistry.list()).toEqual([]);\n expect(fs.existsSync(regPath.replace(/\\.json$/, \".db\"))).toBe(true);\n });\n\n it(\"reads pre-runtime SQLite rows as tmux-backed records\", () => {\n const dbPath = regPath.replace(/\\.json$/, \".db\");\n fs.mkdirSync(path.dirname(dbPath), { recursive: true });\n fs.rmSync(dbPath, { force: true });\n fs.rmSync(`${dbPath}-wal`, { force: true });\n fs.rmSync(`${dbPath}-shm`, { force: true });\n const db = new Database(dbPath);\n db.exec(`\n CREATE TABLE agents (\n type TEXT NOT NULL,\n pid INTEGER NOT NULL,\n name TEXT NOT NULL UNIQUE,\n tmux_session TEXT NOT NULL DEFAULT '',\n cwd TEXT NOT NULL DEFAULT '',\n started_at TEXT NOT NULL,\n session_id TEXT NOT NULL DEFAULT '',\n session_file_path TEXT NOT NULL DEFAULT '',\n updated_at TEXT NOT NULL,\n PRIMARY KEY (type, pid)\n );\n INSERT INTO agents (\n type, pid, name, tmux_session, cwd, started_at, session_id, session_file_path, updated_at\n ) VALUES (\n 'claude', ${process.pid}, 'legacy-sqlite', 'legacy-sqlite', '/tmp',\n '2026-05-30T00:00:00.000Z', 'sid-1', '/tmp/session.jsonl', '2026-05-30T00:00:00.000Z'\n );\n PRAGMA user_version = 1;\n `);\n db.close();\n\n const migratedRegistry = new AgentRegistry(regPath);\n\n expect(migratedRegistry.lookup(\"legacy-sqlite\")).toMatchObject({\n runtime: \"tmux\",\n runtimeRef: { session: \"legacy-sqlite\" },\n });\n });\n });\n\n describe(\"isAlive\", () => {\n it(\"returns true for the current process\", () => {\n expect(registry.isAlive(makeEntry({ pid: process.pid }))).toBe(true);\n });\n\n it(\"returns false for a PID that does not exist\", () => {\n expect(registry.isAlive(makeEntry({ pid: 999999 }))).toBe(false);\n });\n\n it(\"returns true when the process probe is forbidden with EPERM\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n\n it(\"returns false when the process probe reports ESRCH\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n expect(registry.isAlive(makeEntry())).toBe(false);\n });\n\n it(\"returns true when the process probe fails without a definitive error code\", () => {\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw new Error(\"indeterminate probe failure\");\n });\n\n expect(registry.isAlive(makeEntry())).toBe(true);\n });\n });\n\n describe(\"prune\", () => {\n it(\"removes entries whose PIDs are dead\", () => {\n registry.register(makeEntry({ name: \"alive\", pid: process.pid }));\n registry.register(makeEntry({ name: \"dead\", pid: 999999 }));\n registry.prune();\n const remaining = registry.list();\n expect(remaining).toHaveLength(1);\n expect(remaining[0].name).toBe(\"alive\");\n });\n\n it(\"is a no-op when all entries are alive\", () => {\n registry.register(makeEntry({ pid: process.pid }));\n const before = registry.list();\n registry.prune();\n const after = registry.list();\n expect(after).toEqual(before);\n });\n\n it(\"preserves entries when liveness probing fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"custom-name\", runtimeRef: { session: \"tmux-custom\" } }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"custom-name\")).toMatchObject({\n name: \"custom-name\",\n runtimeRef: { session: \"tmux-custom\" },\n });\n });\n\n it(\"removes entries when liveness probing fails with ESRCH\", () => {\n registry.register(makeEntry({ name: \"dead\" }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"no such process\"), { code: \"ESRCH\" });\n });\n\n registry.prune();\n\n expect(registry.lookup(\"dead\")).toBeNull();\n });\n\n it(\"does nothing when file is missing\", () => {\n expect(() => registry.prune()).not.toThrow();\n });\n\n it(\"keeps forced prune available before the passive cadence is due\", () => {\n let nowMs = Date.parse(\"2026-08-14T10:00:00.000Z\");\n const clocked = new AgentRegistry(regPath, {\n now: () => new Date(nowMs),\n pruneIntervalMs: 30_000,\n });\n clocked.register(makeEntry({ name: \"forced\", pid: process.pid }));\n const alive = vi.spyOn(clocked, \"isAlive\").mockReturnValue(true);\n clocked.pruneIfDue();\n alive.mockReturnValue(false);\n nowMs += 1;\n\n clocked.prune();\n\n expect(alive).toHaveBeenCalledTimes(2);\n expect(clocked.lookup(\"forced\")).toBeNull();\n });\n });\n\n describe(\"default()\", () => {\n it(\"returns a singleton instance\", () => {\n expect(AgentRegistry.default()).toBe(AgentRegistry.default());\n });\n });\n\n describe(\"rename\", () => {\n it(\"updates the name of an existing entry\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(registry.lookup(\"new-name\")?.name).toBe(\"new-name\");\n expect(registry.lookup(\"old-name\")).toBeNull();\n });\n\n it(\"preserves all other fields on the renamed entry\", () => {\n registry.register(\n makeEntry({\n name: \"old-name\",\n pid: process.pid,\n runtimeRef: { session: \"old-name\" },\n cwd: \"/my/cwd\",\n }),\n );\n registry.rename(\"old-name\", \"new-name\");\n const entry = registry.lookup(\"new-name\");\n expect(entry?.runtimeRef).toEqual({ session: \"old-name\" });\n expect(entry?.cwd).toBe(\"/my/cwd\");\n expect(entry?.pid).toBe(process.pid);\n });\n\n it(\"throws RenameNotFoundError when current name does not exist\", () => {\n expect(() => registry.rename(\"ghost\", \"new-name\")).toThrow(RenameNotFoundError);\n });\n\n it(\"throws RenameConflictError when new name is already in use by a live entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n });\n\n it(\"throws RenameConflictError when the conflicting entry probe fails with EPERM\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: process.ppid }));\n vi.spyOn(process, \"kill\").mockImplementation(() => {\n throw Object.assign(new Error(\"operation not permitted\"), { code: \"EPERM\" });\n });\n\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).toThrow(RenameConflictError);\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.ppid);\n });\n\n it(\"succeeds when new name exists only as a stale (dead) entry\", () => {\n registry.register(makeEntry({ name: \"agent-a\", pid: process.pid }));\n registry.register(makeEntry({ name: \"agent-b\", pid: 999999 }));\n expect(() => registry.rename(\"agent-a\", \"agent-b\")).not.toThrow();\n expect(registry.lookup(\"agent-b\")?.pid).toBe(process.pid);\n });\n\n it(\"does not create the legacy fixed .tmp path on rename\", () => {\n registry.register(makeEntry({ name: \"old-name\", pid: process.pid }));\n registry.rename(\"old-name\", \"new-name\");\n expect(fs.existsSync(`${regPath}.tmp`)).toBe(false);\n });\n });\n});\n"],"names":["fs","os","path","Database","AgentRegistry","RenameNotFoundError","RenameConflictError","makeEntry","over","name","type","pid","process","cwd","startedAt","sessionId","sessionFilePath","pinned","runtime","runtimeRef","session","describe","tmpDir","regPath","registry","beforeEach","mkdtempSync","join","tmpdir","afterEach","vi","restoreAllMocks","rmSync","recursive","force","it","register","expect","existsSync","replace","toBe","list","ppid","toHaveLength","all","saved","paneId","agentName","lookup","toMatchObject","toBeNull","toEqual","spyOn","mockImplementation","Object","assign","Error","code","toThrow","registerBatch","other","togglePin","now","Date","clocked","updatedAt","toISOString","db","readonly","row","prepare","get","close","updated_at","rename","prune","readonlyRegistry","legacyEntry","mkdirSync","dirname","writeFileSync","JSON","stringify","entries","legacyRegistry","dbPath","exec","migratedRegistry","isAlive","remaining","before","after","not","nowMs","parse","pruneIntervalMs","alive","mockReturnValue","pruneIfDue","toHaveBeenCalledTimes","default","entry"],"mappings":"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"}
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Tests for providers/claude/ClaudeSessionParser.ts — focused on stripping
3
3
  * harness-injected XML tags from conversation content.
4
- */ import * as fs from 'fs';
5
- import * as os from 'os';
6
- import * as path from 'path';
7
- import { ClaudeSessionParser } from '../../providers/claude/ClaudeSessionParser.js';
4
+ */ import * as fs from "fs";
5
+ import * as os from "os";
6
+ import * as path from "path";
7
+ import { ClaudeSessionParser } from "../../providers/claude/ClaudeSessionParser.js";
8
8
  function writeSession(entries) {
9
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'parser-test-'));
10
- const filePath = path.join(dir, 'session.jsonl');
11
- fs.writeFileSync(filePath, entries.map((e)=>JSON.stringify(e)).join('\n'));
9
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "parser-test-"));
10
+ const filePath = path.join(dir, "session.jsonl");
11
+ fs.writeFileSync(filePath, entries.map((e)=>JSON.stringify(e)).join("\n"));
12
12
  return filePath;
13
13
  }
14
- describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
14
+ describe("ClaudeSessionParser.getConversation — harness tag stripping", ()=>{
15
15
  let parser;
16
16
  const tempFiles = [];
17
17
  beforeEach(()=>{
@@ -24,7 +24,8 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
24
24
  recursive: true,
25
25
  force: true
26
26
  });
27
- } catch {}
27
+ } catch {
28
+ /* best effort */ }
28
29
  }
29
30
  tempFiles.length = 0;
30
31
  });
@@ -33,15 +34,15 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
33
34
  tempFiles.push(f);
34
35
  return f;
35
36
  }
36
- it('strips <system-reminder> blocks from text content', ()=>{
37
+ it("strips <system-reminder> blocks from text content", ()=>{
37
38
  const file = makeSession([
38
39
  {
39
- type: 'assistant',
40
+ type: "assistant",
40
41
  message: {
41
42
  content: [
42
43
  {
43
- type: 'text',
44
- text: 'Real response here.\n<system-reminder>\nDo not mention this reminder.\n</system-reminder>\nMore response.'
44
+ type: "text",
45
+ text: "Real response here.\n<system-reminder>\nDo not mention this reminder.\n</system-reminder>\nMore response."
45
46
  }
46
47
  ]
47
48
  }
@@ -49,124 +50,124 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
49
50
  ]);
50
51
  const conv = parser.getConversation(file);
51
52
  expect(conv).toHaveLength(1);
52
- expect(conv[0].content).toBe('Real response here.\n\nMore response.');
53
+ expect(conv[0].content).toBe("Real response here.\n\nMore response.");
53
54
  });
54
- it('strips <local-command-stdout> blocks', ()=>{
55
+ it("strips <local-command-stdout> blocks", ()=>{
55
56
  const file = makeSession([
56
57
  {
57
- type: 'system',
58
+ type: "system",
58
59
  message: {
59
- content: 'before <local-command-stdout>\nRunning...\nDone\n</local-command-stdout> after'
60
+ content: "before <local-command-stdout>\nRunning...\nDone\n</local-command-stdout> after"
60
61
  }
61
62
  }
62
63
  ]);
63
64
  const conv = parser.getConversation(file);
64
- expect(conv[0].content).toBe('before after');
65
+ expect(conv[0].content).toBe("before after");
65
66
  });
66
- it('strips <user-prompt-submit-hook> blocks', ()=>{
67
+ it("strips <user-prompt-submit-hook> blocks", ()=>{
67
68
  const file = makeSession([
68
69
  {
69
- type: 'user',
70
+ type: "user",
70
71
  message: {
71
- content: '<user-prompt-submit-hook>hook output</user-prompt-submit-hook>\nactual question'
72
+ content: "<user-prompt-submit-hook>hook output</user-prompt-submit-hook>\nactual question"
72
73
  }
73
74
  }
74
75
  ]);
75
76
  const conv = parser.getConversation(file);
76
- expect(conv[0].content).toBe('actual question');
77
+ expect(conv[0].content).toBe("actual question");
77
78
  });
78
- it('strips bash and command stdout/stderr blocks', ()=>{
79
+ it("strips bash and command stdout/stderr blocks", ()=>{
79
80
  const file = makeSession([
80
81
  {
81
- type: 'assistant',
82
+ type: "assistant",
82
83
  message: {
83
84
  content: [
84
85
  {
85
- type: 'text',
86
- text: 'Output:\n<bash-input>ls</bash-input>\n<bash-stdout>file.txt</bash-stdout>\n<bash-stderr></bash-stderr>\n<command-stdout>x</command-stdout>\n<command-stderr>y</command-stderr>\nEnd.'
86
+ type: "text",
87
+ text: "Output:\n<bash-input>ls</bash-input>\n<bash-stdout>file.txt</bash-stdout>\n<bash-stderr></bash-stderr>\n<command-stdout>x</command-stdout>\n<command-stderr>y</command-stderr>\nEnd."
87
88
  }
88
89
  ]
89
90
  }
90
91
  }
91
92
  ]);
92
93
  const conv = parser.getConversation(file);
93
- expect(conv[0].content).toBe('Output:\n\n\n\n\n\nEnd.'.replace(/\n{3,}/g, '\n\n'));
94
+ expect(conv[0].content).toBe("Output:\n\n\n\n\n\nEnd.".replace(/\n{3,}/g, "\n\n"));
94
95
  expect(conv[0].content).not.toMatch(/<bash-/);
95
96
  expect(conv[0].content).not.toMatch(/<command-stdout>|<command-stderr>/);
96
97
  });
97
98
  it('collapses <command-name>/<command-args> into "/name args" shorthand', ()=>{
98
99
  const file = makeSession([
99
100
  {
100
- type: 'user',
101
+ type: "user",
101
102
  message: {
102
- content: '<command-message>debug</command-message>\n<command-name>/debug</command-name>\n<command-args>fix the bug</command-args>'
103
+ content: "<command-message>debug</command-message>\n<command-name>/debug</command-name>\n<command-args>fix the bug</command-args>"
103
104
  }
104
105
  }
105
106
  ]);
106
107
  const conv = parser.getConversation(file);
107
- expect(conv[0].content).toBe('/debug fix the bug');
108
+ expect(conv[0].content).toBe("/debug fix the bug");
108
109
  });
109
- it('handles <command-name> without <command-args>', ()=>{
110
+ it("handles <command-name> without <command-args>", ()=>{
110
111
  const file = makeSession([
111
112
  {
112
- type: 'user',
113
+ type: "user",
113
114
  message: {
114
- content: '<command-message>clear</command-message>\n<command-name>/clear</command-name>'
115
+ content: "<command-message>clear</command-message>\n<command-name>/clear</command-name>"
115
116
  }
116
117
  }
117
118
  ]);
118
119
  const conv = parser.getConversation(file);
119
- expect(conv[0].content).toBe('/clear');
120
+ expect(conv[0].content).toBe("/clear");
120
121
  });
121
- it('handles multiple harness tags mixed together', ()=>{
122
+ it("handles multiple harness tags mixed together", ()=>{
122
123
  const file = makeSession([
123
124
  {
124
- type: 'user',
125
+ type: "user",
125
126
  message: {
126
127
  content: [
127
128
  {
128
- type: 'text',
129
- text: '<system-reminder>ignore me</system-reminder>\n<command-message>build</command-message>\n<command-name>/build</command-name>\n<command-args>--watch</command-args>\n<local-command-stdout>build output here</local-command-stdout>'
129
+ type: "text",
130
+ text: "<system-reminder>ignore me</system-reminder>\n<command-message>build</command-message>\n<command-name>/build</command-name>\n<command-args>--watch</command-args>\n<local-command-stdout>build output here</local-command-stdout>"
130
131
  }
131
132
  ]
132
133
  }
133
134
  }
134
135
  ]);
135
136
  const conv = parser.getConversation(file);
136
- expect(conv[0].content).toBe('/build --watch');
137
+ expect(conv[0].content).toBe("/build --watch");
137
138
  });
138
- it('leaves text without harness tags unchanged', ()=>{
139
+ it("leaves text without harness tags unchanged", ()=>{
139
140
  const file = makeSession([
140
141
  {
141
- type: 'assistant',
142
+ type: "assistant",
142
143
  message: {
143
144
  content: [
144
145
  {
145
- type: 'text',
146
- text: 'Hello, world!'
146
+ type: "text",
147
+ text: "Hello, world!"
147
148
  }
148
149
  ]
149
150
  }
150
151
  }
151
152
  ]);
152
153
  const conv = parser.getConversation(file);
153
- expect(conv[0].content).toBe('Hello, world!');
154
+ expect(conv[0].content).toBe("Hello, world!");
154
155
  });
155
- it('drops a message that becomes empty after stripping', ()=>{
156
+ it("drops a message that becomes empty after stripping", ()=>{
156
157
  const file = makeSession([
157
158
  {
158
- type: 'system',
159
+ type: "system",
159
160
  message: {
160
- content: '<system-reminder>only this</system-reminder>'
161
+ content: "<system-reminder>only this</system-reminder>"
161
162
  }
162
163
  },
163
164
  {
164
- type: 'assistant',
165
+ type: "assistant",
165
166
  message: {
166
167
  content: [
167
168
  {
168
- type: 'text',
169
- text: 'kept'
169
+ type: "text",
170
+ text: "kept"
170
171
  }
171
172
  ]
172
173
  }
@@ -174,17 +175,17 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
174
175
  ]);
175
176
  const conv = parser.getConversation(file);
176
177
  expect(conv).toHaveLength(1);
177
- expect(conv[0].content).toBe('kept');
178
+ expect(conv[0].content).toBe("kept");
178
179
  });
179
- it('strips tags spanning multiple lines', ()=>{
180
- const multilineReminder = '<system-reminder>\nLine 1\nLine 2\nLine 3\n</system-reminder>';
180
+ it("strips tags spanning multiple lines", ()=>{
181
+ const multilineReminder = "<system-reminder>\nLine 1\nLine 2\nLine 3\n</system-reminder>";
181
182
  const file = makeSession([
182
183
  {
183
- type: 'assistant',
184
+ type: "assistant",
184
185
  message: {
185
186
  content: [
186
187
  {
187
- type: 'text',
188
+ type: "text",
188
189
  text: `before\n${multilineReminder}\nafter`
189
190
  }
190
191
  ]
@@ -192,10 +193,10 @@ describe('ClaudeSessionParser.getConversation — harness tag stripping', ()=>{
192
193
  }
193
194
  ]);
194
195
  const conv = parser.getConversation(file);
195
- expect(conv[0].content).toBe('before\n\nafter');
196
+ expect(conv[0].content).toBe("before\n\nafter");
196
197
  });
197
198
  });
198
- describe('ClaudeSessionParser.readSession — UI-state entries ignored for status', ()=>{
199
+ describe("ClaudeSessionParser.readSession — UI-state entries ignored for status", ()=>{
199
200
  let parser;
200
201
  const tempFiles = [];
201
202
  beforeEach(()=>{
@@ -208,104 +209,105 @@ describe('ClaudeSessionParser.readSession — UI-state entries ignored for statu
208
209
  recursive: true,
209
210
  force: true
210
211
  });
211
- } catch {}
212
+ } catch {
213
+ /* best effort */ }
212
214
  }
213
215
  tempFiles.length = 0;
214
216
  });
215
217
  function writeRawSession(lines) {
216
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'parser-status-'));
217
- const filePath = path.join(dir, 'session.jsonl');
218
- fs.writeFileSync(filePath, lines.map((l)=>JSON.stringify(l)).join('\n'));
218
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "parser-status-"));
219
+ const filePath = path.join(dir, "session.jsonl");
220
+ fs.writeFileSync(filePath, lines.map((l)=>JSON.stringify(l)).join("\n"));
219
221
  tempFiles.push(filePath);
220
222
  return filePath;
221
223
  }
222
224
  const uiStateTypes = [
223
- 'attachment',
224
- 'permission-mode',
225
- 'ai-title',
226
- 'queued_command',
227
- 'tools_changed',
228
- 'model_changed',
229
- 'hook_progress'
225
+ "attachment",
226
+ "permission-mode",
227
+ "ai-title",
228
+ "queued_command",
229
+ "tools_changed",
230
+ "model_changed",
231
+ "hook_progress"
230
232
  ];
231
233
  for (const uiType of uiStateTypes){
232
234
  it(`keeps lastEntryType from previous conversation turn when trailing entry is ${uiType}`, ()=>{
233
235
  const file = writeRawSession([
234
236
  {
235
- type: 'user',
236
- timestamp: '2026-05-30T06:17:57.189Z',
237
+ type: "user",
238
+ timestamp: "2026-05-30T06:17:57.189Z",
237
239
  message: {
238
- content: 'hello'
240
+ content: "hello"
239
241
  }
240
242
  },
241
243
  {
242
244
  type: uiType,
243
- timestamp: '2026-05-30T06:17:57.201Z'
245
+ timestamp: "2026-05-30T06:17:57.201Z"
244
246
  }
245
247
  ]);
246
- const session = parser.readSession(file, '/test');
247
- expect(session?.lastEntryType).toBe('user');
248
+ const session = parser.readSession(file, "/test");
249
+ expect(session?.lastEntryType).toBe("user");
248
250
  });
249
251
  }
250
- it('keeps lastEntryType from a user turn even with multiple trailing UI-state entries', ()=>{
252
+ it("keeps lastEntryType from a user turn even with multiple trailing UI-state entries", ()=>{
251
253
  const file = writeRawSession([
252
254
  {
253
- type: 'user',
254
- timestamp: '2026-05-30T06:17:57.189Z',
255
+ type: "user",
256
+ timestamp: "2026-05-30T06:17:57.189Z",
255
257
  message: {
256
- content: 'hello'
258
+ content: "hello"
257
259
  }
258
260
  },
259
261
  {
260
- type: 'attachment',
261
- timestamp: '2026-05-30T06:17:57.200Z',
262
+ type: "attachment",
263
+ timestamp: "2026-05-30T06:17:57.200Z",
262
264
  attachment: {
263
- type: 'task_reminder',
265
+ type: "task_reminder",
264
266
  content: []
265
267
  }
266
268
  },
267
269
  {
268
- type: 'permission-mode',
269
- timestamp: '2026-05-30T06:17:57.210Z',
270
- permissionMode: 'default'
270
+ type: "permission-mode",
271
+ timestamp: "2026-05-30T06:17:57.210Z",
272
+ permissionMode: "default"
271
273
  },
272
274
  {
273
- type: 'ai-title',
274
- timestamp: '2026-05-30T06:17:57.220Z'
275
+ type: "ai-title",
276
+ timestamp: "2026-05-30T06:17:57.220Z"
275
277
  }
276
278
  ]);
277
- const session = parser.readSession(file, '/test');
278
- expect(session?.lastEntryType).toBe('user');
279
+ const session = parser.readSession(file, "/test");
280
+ expect(session?.lastEntryType).toBe("user");
279
281
  });
280
- it('keeps lastEntryType from assistant turn when followed by UI-state events', ()=>{
282
+ it("keeps lastEntryType from assistant turn when followed by UI-state events", ()=>{
281
283
  const file = writeRawSession([
282
284
  {
283
- type: 'user',
284
- timestamp: '2026-05-30T06:17:00.000Z',
285
+ type: "user",
286
+ timestamp: "2026-05-30T06:17:00.000Z",
285
287
  message: {
286
- content: 'go'
288
+ content: "go"
287
289
  }
288
290
  },
289
291
  {
290
- type: 'assistant',
291
- timestamp: '2026-05-30T06:17:01.000Z',
292
+ type: "assistant",
293
+ timestamp: "2026-05-30T06:17:01.000Z",
292
294
  message: {
293
295
  content: [
294
296
  {
295
- type: 'text',
296
- text: 'done'
297
+ type: "text",
298
+ text: "done"
297
299
  }
298
300
  ]
299
301
  }
300
302
  },
301
303
  {
302
- type: 'permission-mode',
303
- timestamp: '2026-05-30T06:17:02.000Z',
304
- permissionMode: 'default'
304
+ type: "permission-mode",
305
+ timestamp: "2026-05-30T06:17:02.000Z",
306
+ permissionMode: "default"
305
307
  }
306
308
  ]);
307
- const session = parser.readSession(file, '/test');
308
- expect(session?.lastEntryType).toBe('assistant');
309
+ const session = parser.readSession(file, "/test");
310
+ expect(session?.lastEntryType).toBe("assistant");
309
311
  });
310
312
  });
311
313