@ai-devkit/agent-manager 0.32.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 +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/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 -43
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +27 -26
  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 +6 -6
  279. package/dist/readiness/AgentReadiness.d.ts.map +1 -1
  280. package/dist/readiness/AgentReadiness.js +130 -130
  281. package/dist/readiness/AgentReadiness.js.map +1 -1
  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 +217 -169
  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 +144 -103
  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 +585 -513
  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,188 +1,188 @@
1
1
  /**
2
2
  * Tests for new functions in utils/process.ts
3
- */ import { execFile, execFileSync } from 'child_process';
4
- import { listAgentProcesses, batchGetProcessCwds, batchGetProcessStartTimes, enrichProcesses, findWrapperProcess, findWrapperProcessPids, captureProcessSnapshot, filterByProcessNames } from '../../utils/process.js';
5
- vi.mock('child_process', ()=>({
3
+ */ import { execFile, execFileSync } from "child_process";
4
+ import { listAgentProcesses, batchGetProcessCwds, batchGetProcessStartTimes, enrichProcesses, findWrapperProcess, findWrapperProcessPids, captureProcessSnapshot, filterByProcessNames } from "../../utils/process.js";
5
+ vi.mock("child_process", ()=>({
6
6
  execFile: vi.fn(),
7
7
  execFileSync: vi.fn()
8
8
  }));
9
9
  const mockedExecFileSync = execFileSync;
10
10
  const mockedExecFile = execFile;
11
- describe('captureProcessSnapshot', ()=>{
11
+ describe("captureProcessSnapshot", ()=>{
12
12
  beforeEach(()=>{
13
13
  mockedExecFile.mockReset();
14
14
  mockedExecFileSync.mockReset();
15
15
  });
16
- it('captures and enriches relevant processes without synchronous scans', async ()=>{
16
+ it("captures and enriches relevant processes without synchronous scans", async ()=>{
17
17
  mockedExecFile.mockImplementation((file, args, _options, callback)=>{
18
18
  queueMicrotask(()=>{
19
- if (file === 'ps' && args.includes('-axo')) {
20
- callback(null, '100 1 s001 /usr/bin/claude --resume abc\n' + '200 1 s002 C:\\\\tools\\\\node.exe C:\\\\bin\\\\pi.js\n' + '300 1 s003 /usr/bin/unrelated\n', '');
19
+ if (file === "ps" && args.includes("-axo")) {
20
+ callback(null, "100 1 s001 /usr/bin/claude --resume abc\n" + "200 1 s002 C:\\\\tools\\\\node.exe C:\\\\bin\\\\pi.js\n" + "300 1 s003 /usr/bin/unrelated\n", "");
21
21
  return;
22
22
  }
23
- if (file === 'lsof') {
24
- callback(null, 'p100\nn/projects/claude\np200\nn/projects/pi\n', '');
23
+ if (file === "lsof") {
24
+ callback(null, "p100\nn/projects/claude\np200\nn/projects/pi\n", "");
25
25
  return;
26
26
  }
27
- if (file === 'ps' && args.some((arg)=>arg.includes('lstart='))) {
28
- callback(null, '100 Wed Mar 18 23:18:01 2026\n' + '200 Thu Mar 19 10:00:00 2026\n', '');
27
+ if (file === "ps" && args.some((arg)=>arg.includes("lstart="))) {
28
+ callback(null, "100 Wed Mar 18 23:18:01 2026\n" + "200 Thu Mar 19 10:00:00 2026\n", "");
29
29
  return;
30
30
  }
31
- callback(new Error(`unexpected command: ${file} ${args.join(' ')}`), '', '');
31
+ callback(new Error(`unexpected command: ${file} ${args.join(" ")}`), "", "");
32
32
  });
33
33
  });
34
34
  const snapshot = await captureProcessSnapshot([
35
- 'claude',
36
- 'node'
35
+ "claude",
36
+ "node"
37
37
  ]);
38
38
  expect(snapshot.map((process)=>process.pid)).toEqual([
39
39
  100,
40
40
  200
41
41
  ]);
42
42
  expect(snapshot.map((process)=>process.cwd)).toEqual([
43
- '/projects/claude',
44
- '/projects/pi'
43
+ "/projects/claude",
44
+ "/projects/pi"
45
45
  ]);
46
46
  expect(snapshot.map((process)=>process.startTime)).toEqual([
47
47
  expect.any(Date),
48
48
  expect.any(Date)
49
49
  ]);
50
50
  expect(mockedExecFileSync).not.toHaveBeenCalled();
51
- expect(mockedExecFile.mock.calls.filter(([, args])=>args.includes('-axo'))).toHaveLength(1);
51
+ expect(mockedExecFile.mock.calls.filter(([, args])=>args.includes("-axo"))).toHaveLength(1);
52
52
  for (const [, , options] of mockedExecFile.mock.calls){
53
53
  expect(options).toMatchObject({
54
- encoding: 'utf-8',
54
+ encoding: "utf-8",
55
55
  maxBuffer: 10 * 1024 * 1024
56
56
  });
57
- expect(options).not.toHaveProperty('stdio');
57
+ expect(options).not.toHaveProperty("stdio");
58
58
  }
59
59
  });
60
60
  });
61
- describe('filterByProcessNames', ()=>{
62
- it('matches only argv[0] and normalizes Windows paths and executable suffixes', ()=>{
61
+ describe("filterByProcessNames", ()=>{
62
+ it("matches only argv[0] and normalizes Windows paths and executable suffixes", ()=>{
63
63
  const processes = [
64
64
  {
65
65
  pid: 1,
66
- command: 'C:\\tools\\node.exe C:\\bin\\pi.js',
67
- cwd: '',
68
- tty: ''
66
+ command: "C:\\tools\\node.exe C:\\bin\\pi.js",
67
+ cwd: "",
68
+ tty: ""
69
69
  },
70
70
  {
71
71
  pid: 2,
72
- command: '/usr/local/bin/node /opt/gemini.js',
73
- cwd: '',
74
- tty: ''
72
+ command: "/usr/local/bin/node /opt/gemini.js",
73
+ cwd: "",
74
+ tty: ""
75
75
  },
76
76
  {
77
77
  pid: 3,
78
- command: 'codex exec --cd C:\\repos\\node',
79
- cwd: '',
80
- tty: ''
78
+ command: "codex exec --cd C:\\repos\\node",
79
+ cwd: "",
80
+ tty: ""
81
81
  }
82
82
  ];
83
83
  expect(filterByProcessNames(processes, [
84
- 'node'
84
+ "node"
85
85
  ])).toEqual([
86
86
  processes[0],
87
87
  processes[1]
88
88
  ]);
89
89
  expect(filterByProcessNames(processes, [
90
- 'node.exe'
90
+ "node.exe"
91
91
  ])).toEqual([
92
92
  processes[0],
93
93
  processes[1]
94
94
  ]);
95
95
  });
96
96
  });
97
- describe('listAgentProcesses', ()=>{
97
+ describe("listAgentProcesses", ()=>{
98
98
  beforeEach(()=>{
99
99
  mockedExecFileSync.mockReset();
100
100
  });
101
- it('should parse ps output and post-filter by executable name', ()=>{
102
- mockedExecFileSync.mockReturnValue('78070 1 s018 claude\n' + '55106 55100 s015 claude\n');
103
- const processes = listAgentProcesses('claude');
101
+ it("should parse ps output and post-filter by executable name", ()=>{
102
+ mockedExecFileSync.mockReturnValue("78070 1 s018 claude\n" + "55106 55100 s015 claude\n");
103
+ const processes = listAgentProcesses("claude");
104
104
  expect(processes).toHaveLength(2);
105
105
  expect(processes[0].pid).toBe(78070);
106
106
  expect(processes[0].ppid).toBe(1);
107
- expect(processes[0].command).toBe('claude');
108
- expect(processes[0].tty).toBe('s018');
109
- expect(processes[0].cwd).toBe(''); // not populated yet
107
+ expect(processes[0].command).toBe("claude");
108
+ expect(processes[0].tty).toBe("s018");
109
+ expect(processes[0].cwd).toBe(""); // not populated yet
110
110
  expect(processes[1].pid).toBe(55106);
111
111
  expect(processes[1].ppid).toBe(55100);
112
112
  });
113
- it('should filter out non-matching executables', ()=>{
114
- mockedExecFileSync.mockReturnValue('100 1 s001 claude\n' + '200 1 s002 claude-helper --pid 100\n' + '300 1 s003 /usr/bin/claude\n');
115
- const processes = listAgentProcesses('claude');
113
+ it("should filter out non-matching executables", ()=>{
114
+ mockedExecFileSync.mockReturnValue("100 1 s001 claude\n" + "200 1 s002 claude-helper --pid 100\n" + "300 1 s003 /usr/bin/claude\n");
115
+ const processes = listAgentProcesses("claude");
116
116
  expect(processes).toHaveLength(2);
117
117
  expect(processes.map((p)=>p.pid)).toEqual([
118
118
  100,
119
119
  300
120
120
  ]);
121
121
  });
122
- it('should return empty array on command failure', ()=>{
122
+ it("should return empty array on command failure", ()=>{
123
123
  mockedExecFileSync.mockImplementation(()=>{
124
- throw new Error('fail');
124
+ throw new Error("fail");
125
125
  });
126
- expect(listAgentProcesses('claude')).toEqual([]);
126
+ expect(listAgentProcesses("claude")).toEqual([]);
127
127
  });
128
- it('should handle empty output', ()=>{
129
- mockedExecFileSync.mockReturnValue('');
130
- expect(listAgentProcesses('claude')).toEqual([]);
128
+ it("should handle empty output", ()=>{
129
+ mockedExecFileSync.mockReturnValue("");
130
+ expect(listAgentProcesses("claude")).toEqual([]);
131
131
  });
132
- it('should reject empty pattern', ()=>{
133
- expect(listAgentProcesses('')).toEqual([]);
132
+ it("should reject empty pattern", ()=>{
133
+ expect(listAgentProcesses("")).toEqual([]);
134
134
  expect(mockedExecFileSync).not.toHaveBeenCalled();
135
135
  });
136
- it('should reject patterns with shell injection characters', ()=>{
137
- expect(listAgentProcesses('claude; rm -rf /')).toEqual([]);
136
+ it("should reject patterns with shell injection characters", ()=>{
137
+ expect(listAgentProcesses("claude; rm -rf /")).toEqual([]);
138
138
  expect(listAgentProcesses("claude' || true")).toEqual([]);
139
- expect(listAgentProcesses('$(whoami)')).toEqual([]);
139
+ expect(listAgentProcesses("$(whoami)")).toEqual([]);
140
140
  expect(mockedExecFileSync).not.toHaveBeenCalled();
141
141
  });
142
- it('should accept valid patterns with dashes and underscores', ()=>{
143
- mockedExecFileSync.mockReturnValue('');
144
- listAgentProcesses('claude-code');
145
- expect(mockedExecFileSync).toHaveBeenCalledWith('ps', [
146
- '-axo',
147
- 'pid=,ppid=,tty=,command='
142
+ it("should accept valid patterns with dashes and underscores", ()=>{
143
+ mockedExecFileSync.mockReturnValue("");
144
+ listAgentProcesses("claude-code");
145
+ expect(mockedExecFileSync).toHaveBeenCalledWith("ps", [
146
+ "-axo",
147
+ "pid=,ppid=,tty=,command="
148
148
  ], {
149
- encoding: 'utf-8'
149
+ encoding: "utf-8"
150
150
  });
151
151
  mockedExecFileSync.mockReset();
152
- mockedExecFileSync.mockReturnValue('');
153
- listAgentProcesses('my_agent');
152
+ mockedExecFileSync.mockReturnValue("");
153
+ listAgentProcesses("my_agent");
154
154
  expect(mockedExecFileSync).toHaveBeenCalled();
155
155
  });
156
156
  });
157
- describe('batchGetProcessCwds', ()=>{
157
+ describe("batchGetProcessCwds", ()=>{
158
158
  beforeEach(()=>{
159
159
  mockedExecFileSync.mockReset();
160
160
  });
161
- it('should parse batched lsof output', ()=>{
162
- mockedExecFileSync.mockReturnValue('p78070\nn/Users/user/ai-devkit\np55106\nn/Users/user/other-project\n');
161
+ it("should parse batched lsof output", ()=>{
162
+ mockedExecFileSync.mockReturnValue("p78070\nn/Users/user/ai-devkit\np55106\nn/Users/user/other-project\n");
163
163
  const cwds = batchGetProcessCwds([
164
164
  78070,
165
165
  55106
166
166
  ]);
167
- expect(cwds.get(78070)).toBe('/Users/user/ai-devkit');
168
- expect(cwds.get(55106)).toBe('/Users/user/other-project');
167
+ expect(cwds.get(78070)).toBe("/Users/user/ai-devkit");
168
+ expect(cwds.get(55106)).toBe("/Users/user/other-project");
169
169
  });
170
- it('should return empty map for empty pids', ()=>{
170
+ it("should return empty map for empty pids", ()=>{
171
171
  expect(batchGetProcessCwds([])).toEqual(new Map());
172
172
  });
173
- it('should return partial results when lsof succeeds for some PIDs', ()=>{
173
+ it("should return partial results when lsof succeeds for some PIDs", ()=>{
174
174
  // lsof might not return entries for dead processes
175
- mockedExecFileSync.mockReturnValue('p78070\nn/Users/user/ai-devkit\n');
175
+ mockedExecFileSync.mockReturnValue("p78070\nn/Users/user/ai-devkit\n");
176
176
  const cwds = batchGetProcessCwds([
177
177
  78070,
178
178
  99999
179
179
  ]);
180
180
  expect(cwds.size).toBe(1);
181
- expect(cwds.get(78070)).toBe('/Users/user/ai-devkit');
181
+ expect(cwds.get(78070)).toBe("/Users/user/ai-devkit");
182
182
  });
183
- it('should return empty map on total failure', ()=>{
183
+ it("should return empty map on total failure", ()=>{
184
184
  mockedExecFileSync.mockImplementation(()=>{
185
- throw new Error('fail');
185
+ throw new Error("fail");
186
186
  });
187
187
  const cwds = batchGetProcessCwds([
188
188
  78070
@@ -191,12 +191,12 @@ describe('batchGetProcessCwds', ()=>{
191
191
  expect(cwds.size).toBe(0);
192
192
  });
193
193
  });
194
- describe('batchGetProcessStartTimes', ()=>{
194
+ describe("batchGetProcessStartTimes", ()=>{
195
195
  beforeEach(()=>{
196
196
  mockedExecFileSync.mockReset();
197
197
  });
198
- it('should parse ps lstart output', ()=>{
199
- mockedExecFileSync.mockReturnValue(' 78070 Wed Mar 18 23:18:01 2026\n' + ' 55106 Mon Mar 9 21:41:42 2026\n');
198
+ it("should parse ps lstart output", ()=>{
199
+ mockedExecFileSync.mockReturnValue(" 78070 Wed Mar 18 23:18:01 2026\n" + " 55106 Mon Mar 9 21:41:42 2026\n");
200
200
  const times = batchGetProcessStartTimes([
201
201
  78070,
202
202
  55106
@@ -205,11 +205,11 @@ describe('batchGetProcessStartTimes', ()=>{
205
205
  expect(times.get(78070)?.getFullYear()).toBe(2026);
206
206
  expect(times.get(55106)?.getMonth()).toBe(2); // March = 2
207
207
  });
208
- it('should return empty map for empty pids', ()=>{
208
+ it("should return empty map for empty pids", ()=>{
209
209
  expect(batchGetProcessStartTimes([])).toEqual(new Map());
210
210
  });
211
- it('should skip lines with unparseable dates', ()=>{
212
- mockedExecFileSync.mockReturnValue(' 78070 Wed Mar 18 23:18:01 2026\n' + ' 99999 INVALID_DATE\n');
211
+ it("should skip lines with unparseable dates", ()=>{
212
+ mockedExecFileSync.mockReturnValue(" 78070 Wed Mar 18 23:18:01 2026\n" + " 99999 INVALID_DATE\n");
213
213
  const times = batchGetProcessStartTimes([
214
214
  78070,
215
215
  99999
@@ -217,72 +217,72 @@ describe('batchGetProcessStartTimes', ()=>{
217
217
  expect(times.size).toBe(1);
218
218
  expect(times.has(78070)).toBe(true);
219
219
  });
220
- it('should return empty map on failure', ()=>{
220
+ it("should return empty map on failure", ()=>{
221
221
  mockedExecFileSync.mockImplementation(()=>{
222
- throw new Error('fail');
222
+ throw new Error("fail");
223
223
  });
224
224
  expect(batchGetProcessStartTimes([
225
225
  78070
226
226
  ])).toEqual(new Map());
227
227
  });
228
228
  });
229
- describe('enrichProcesses', ()=>{
229
+ describe("enrichProcesses", ()=>{
230
230
  beforeEach(()=>{
231
231
  mockedExecFileSync.mockReset();
232
232
  });
233
- it('should populate cwd and startTime on processes', ()=>{
233
+ it("should populate cwd and startTime on processes", ()=>{
234
234
  // First call: batchGetProcessCwds (lsof)
235
235
  // Second call: batchGetProcessStartTimes (ps lstart)
236
- mockedExecFileSync.mockReturnValueOnce('p100\nn/projects/app\n').mockReturnValueOnce(' 100 Wed Mar 18 23:18:01 2026\n');
236
+ mockedExecFileSync.mockReturnValueOnce("p100\nn/projects/app\n").mockReturnValueOnce(" 100 Wed Mar 18 23:18:01 2026\n");
237
237
  const processes = [
238
238
  {
239
239
  pid: 100,
240
- command: 'claude',
241
- cwd: '',
242
- tty: 's001'
240
+ command: "claude",
241
+ cwd: "",
242
+ tty: "s001"
243
243
  }
244
244
  ];
245
245
  const enriched = enrichProcesses(processes);
246
- expect(enriched[0].cwd).toBe('/projects/app');
246
+ expect(enriched[0].cwd).toBe("/projects/app");
247
247
  expect(enriched[0].startTime).toBeDefined();
248
248
  });
249
- it('should return empty array for empty input', ()=>{
249
+ it("should return empty array for empty input", ()=>{
250
250
  expect(enrichProcesses([])).toEqual([]);
251
251
  expect(mockedExecFileSync).not.toHaveBeenCalled();
252
252
  });
253
- it('should handle partial failures', ()=>{
253
+ it("should handle partial failures", ()=>{
254
254
  // lsof succeeds, ps lstart fails
255
- mockedExecFileSync.mockReturnValueOnce('p100\nn/projects/app\n').mockImplementationOnce(()=>{
256
- throw new Error('fail');
255
+ mockedExecFileSync.mockReturnValueOnce("p100\nn/projects/app\n").mockImplementationOnce(()=>{
256
+ throw new Error("fail");
257
257
  });
258
258
  const processes = [
259
259
  {
260
260
  pid: 100,
261
- command: 'claude',
262
- cwd: '',
263
- tty: 's001'
261
+ command: "claude",
262
+ cwd: "",
263
+ tty: "s001"
264
264
  }
265
265
  ];
266
266
  const enriched = enrichProcesses(processes);
267
- expect(enriched[0].cwd).toBe('/projects/app');
267
+ expect(enriched[0].cwd).toBe("/projects/app");
268
268
  expect(enriched[0].startTime).toBeUndefined();
269
269
  });
270
270
  });
271
- describe('wrapper process detection', ()=>{
272
- it('finds the parent wrapper process for a child in the same terminal and cwd', ()=>{
271
+ describe("wrapper process detection", ()=>{
272
+ it("finds the parent wrapper process for a child in the same terminal and cwd", ()=>{
273
273
  const wrapper = {
274
274
  pid: 100,
275
275
  ppid: 1,
276
- command: 'node /bin/gemini',
277
- cwd: '/repo',
278
- tty: 'ttys001'
276
+ command: "node /bin/gemini",
277
+ cwd: "/repo",
278
+ tty: "ttys001"
279
279
  };
280
280
  const child = {
281
281
  pid: 200,
282
282
  ppid: 100,
283
- command: 'node --max-old-space-size=8192 /bin/gemini',
284
- cwd: '/repo',
285
- tty: 'ttys001'
283
+ command: "node --max-old-space-size=8192 /bin/gemini",
284
+ cwd: "/repo",
285
+ tty: "ttys001"
286
286
  };
287
287
  expect(findWrapperProcess([
288
288
  wrapper,
@@ -295,13 +295,13 @@ describe('wrapper process detection', ()=>{
295
295
  100
296
296
  ]));
297
297
  });
298
- it('does not mark a matched child process as its own wrapper', ()=>{
298
+ it("does not mark a matched child process as its own wrapper", ()=>{
299
299
  const child = {
300
300
  pid: 200,
301
301
  ppid: 100,
302
- command: 'node --max-old-space-size=8192 /bin/gemini',
303
- cwd: '/repo',
304
- tty: 'ttys001'
302
+ command: "node --max-old-space-size=8192 /bin/gemini",
303
+ cwd: "/repo",
304
+ tty: "ttys001"
305
305
  };
306
306
  expect(findWrapperProcessPids([
307
307
  child
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/utils/process.test.ts"],"sourcesContent":["/**\n * Tests for new functions in utils/process.ts\n */\n\nimport type { MockedFunction } from 'vitest';\n\nimport { execFile, execFileSync } from 'child_process';\nimport {\n listAgentProcesses,\n batchGetProcessCwds,\n batchGetProcessStartTimes,\n enrichProcesses,\n findWrapperProcess,\n findWrapperProcessPids,\n captureProcessSnapshot,\n filterByProcessNames,\n} from '../../utils/process.js';\n\nvi.mock('child_process', () => ({\n execFile: vi.fn(),\n execFileSync: vi.fn(),\n}));\n\nconst mockedExecFileSync = execFileSync as MockedFunction<typeof execFileSync>;\nconst mockedExecFile = execFile as unknown as MockedFunction<(\n file: string,\n args: readonly string[],\n options: object,\n callback: (error: Error | null, stdout: string, stderr: string) => void,\n) => void>;\n\ndescribe('captureProcessSnapshot', () => {\n beforeEach(() => {\n mockedExecFile.mockReset();\n mockedExecFileSync.mockReset();\n });\n\n it('captures and enriches relevant processes without synchronous scans', async () => {\n mockedExecFile.mockImplementation((file, args, _options, callback) => {\n queueMicrotask(() => {\n if (file === 'ps' && args.includes('-axo')) {\n callback(null,\n '100 1 s001 /usr/bin/claude --resume abc\\n' +\n '200 1 s002 C:\\\\\\\\tools\\\\\\\\node.exe C:\\\\\\\\bin\\\\\\\\pi.js\\n' +\n '300 1 s003 /usr/bin/unrelated\\n',\n '');\n return;\n }\n if (file === 'lsof') {\n callback(null, 'p100\\nn/projects/claude\\np200\\nn/projects/pi\\n', '');\n return;\n }\n if (file === 'ps' && args.some((arg) => arg.includes('lstart='))) {\n callback(null,\n '100 Wed Mar 18 23:18:01 2026\\n' +\n '200 Thu Mar 19 10:00:00 2026\\n',\n '');\n return;\n }\n callback(new Error(`unexpected command: ${file} ${args.join(' ')}`), '', '');\n });\n });\n\n const snapshot = await captureProcessSnapshot(['claude', 'node']);\n\n expect(snapshot.map((process) => process.pid)).toEqual([100, 200]);\n expect(snapshot.map((process) => process.cwd)).toEqual(['/projects/claude', '/projects/pi']);\n expect(snapshot.map((process) => process.startTime)).toEqual([\n expect.any(Date),\n expect.any(Date),\n ]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n expect(mockedExecFile.mock.calls.filter(([, args]) => args.includes('-axo'))).toHaveLength(1);\n for (const [, , options] of mockedExecFile.mock.calls) {\n expect(options).toMatchObject({ encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });\n expect(options).not.toHaveProperty('stdio');\n }\n });\n});\n\ndescribe('filterByProcessNames', () => {\n it('matches only argv[0] and normalizes Windows paths and executable suffixes', () => {\n const processes: ProcessInfo[] = [\n { pid: 1, command: 'C:\\\\tools\\\\node.exe C:\\\\bin\\\\pi.js', cwd: '', tty: '' },\n { pid: 2, command: '/usr/local/bin/node /opt/gemini.js', cwd: '', tty: '' },\n { pid: 3, command: 'codex exec --cd C:\\\\repos\\\\node', cwd: '', tty: '' },\n ];\n\n expect(filterByProcessNames(processes, ['node'])).toEqual([processes[0], processes[1]]);\n expect(filterByProcessNames(processes, ['node.exe'])).toEqual([processes[0], processes[1]]);\n });\n});\n\ndescribe('listAgentProcesses', () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it('should parse ps output and post-filter by executable name', () => {\n mockedExecFileSync.mockReturnValue(\n '78070 1 s018 claude\\n' +\n '55106 55100 s015 claude\\n',\n );\n\n const processes = listAgentProcesses('claude');\n expect(processes).toHaveLength(2);\n expect(processes[0].pid).toBe(78070);\n expect(processes[0].ppid).toBe(1);\n expect(processes[0].command).toBe('claude');\n expect(processes[0].tty).toBe('s018');\n expect(processes[0].cwd).toBe(''); // not populated yet\n expect(processes[1].pid).toBe(55106);\n expect(processes[1].ppid).toBe(55100);\n });\n\n it('should filter out non-matching executables', () => {\n mockedExecFileSync.mockReturnValue(\n '100 1 s001 claude\\n' +\n '200 1 s002 claude-helper --pid 100\\n' +\n '300 1 s003 /usr/bin/claude\\n',\n );\n\n const processes = listAgentProcesses('claude');\n expect(processes).toHaveLength(2);\n expect(processes.map(p => p.pid)).toEqual([100, 300]);\n });\n\n it('should return empty array on command failure', () => {\n mockedExecFileSync.mockImplementation(() => { throw new Error('fail'); });\n expect(listAgentProcesses('claude')).toEqual([]);\n });\n\n it('should handle empty output', () => {\n mockedExecFileSync.mockReturnValue('');\n expect(listAgentProcesses('claude')).toEqual([]);\n });\n\n it('should reject empty pattern', () => {\n expect(listAgentProcesses('')).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it('should reject patterns with shell injection characters', () => {\n expect(listAgentProcesses('claude; rm -rf /')).toEqual([]);\n expect(listAgentProcesses(\"claude' || true\")).toEqual([]);\n expect(listAgentProcesses('$(whoami)')).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it('should accept valid patterns with dashes and underscores', () => {\n mockedExecFileSync.mockReturnValue('');\n listAgentProcesses('claude-code');\n expect(mockedExecFileSync).toHaveBeenCalledWith(\n 'ps',\n ['-axo', 'pid=,ppid=,tty=,command='],\n { encoding: 'utf-8' },\n );\n\n mockedExecFileSync.mockReset();\n mockedExecFileSync.mockReturnValue('');\n listAgentProcesses('my_agent');\n expect(mockedExecFileSync).toHaveBeenCalled();\n });\n});\n\ndescribe('batchGetProcessCwds', () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it('should parse batched lsof output', () => {\n mockedExecFileSync.mockReturnValue(\n 'p78070\\nn/Users/user/ai-devkit\\np55106\\nn/Users/user/other-project\\n',\n );\n\n const cwds = batchGetProcessCwds([78070, 55106]);\n expect(cwds.get(78070)).toBe('/Users/user/ai-devkit');\n expect(cwds.get(55106)).toBe('/Users/user/other-project');\n });\n\n it('should return empty map for empty pids', () => {\n expect(batchGetProcessCwds([])).toEqual(new Map());\n });\n\n it('should return partial results when lsof succeeds for some PIDs', () => {\n // lsof might not return entries for dead processes\n mockedExecFileSync.mockReturnValue(\n 'p78070\\nn/Users/user/ai-devkit\\n',\n );\n\n const cwds = batchGetProcessCwds([78070, 99999]);\n expect(cwds.size).toBe(1);\n expect(cwds.get(78070)).toBe('/Users/user/ai-devkit');\n });\n\n it('should return empty map on total failure', () => {\n mockedExecFileSync.mockImplementation(() => { throw new Error('fail'); });\n const cwds = batchGetProcessCwds([78070]);\n // Falls through to pwdx fallback which also fails\n expect(cwds.size).toBe(0);\n });\n});\n\ndescribe('batchGetProcessStartTimes', () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it('should parse ps lstart output', () => {\n mockedExecFileSync.mockReturnValue(\n ' 78070 Wed Mar 18 23:18:01 2026\\n' +\n ' 55106 Mon Mar 9 21:41:42 2026\\n',\n );\n\n const times = batchGetProcessStartTimes([78070, 55106]);\n expect(times.size).toBe(2);\n expect(times.get(78070)?.getFullYear()).toBe(2026);\n expect(times.get(55106)?.getMonth()).toBe(2); // March = 2\n });\n\n it('should return empty map for empty pids', () => {\n expect(batchGetProcessStartTimes([])).toEqual(new Map());\n });\n\n it('should skip lines with unparseable dates', () => {\n mockedExecFileSync.mockReturnValue(\n ' 78070 Wed Mar 18 23:18:01 2026\\n' +\n ' 99999 INVALID_DATE\\n',\n );\n\n const times = batchGetProcessStartTimes([78070, 99999]);\n expect(times.size).toBe(1);\n expect(times.has(78070)).toBe(true);\n });\n\n it('should return empty map on failure', () => {\n mockedExecFileSync.mockImplementation(() => { throw new Error('fail'); });\n expect(batchGetProcessStartTimes([78070])).toEqual(new Map());\n });\n});\n\ndescribe('enrichProcesses', () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it('should populate cwd and startTime on processes', () => {\n // First call: batchGetProcessCwds (lsof)\n // Second call: batchGetProcessStartTimes (ps lstart)\n mockedExecFileSync\n .mockReturnValueOnce('p100\\nn/projects/app\\n')\n .mockReturnValueOnce(' 100 Wed Mar 18 23:18:01 2026\\n');\n\n const processes = [\n { pid: 100, command: 'claude', cwd: '', tty: 's001' },\n ];\n\n const enriched = enrichProcesses(processes);\n expect(enriched[0].cwd).toBe('/projects/app');\n expect(enriched[0].startTime).toBeDefined();\n });\n\n it('should return empty array for empty input', () => {\n expect(enrichProcesses([])).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it('should handle partial failures', () => {\n // lsof succeeds, ps lstart fails\n mockedExecFileSync\n .mockReturnValueOnce('p100\\nn/projects/app\\n')\n .mockImplementationOnce(() => { throw new Error('fail'); });\n\n const processes = [\n { pid: 100, command: 'claude', cwd: '', tty: 's001' },\n ];\n\n const enriched = enrichProcesses(processes);\n expect(enriched[0].cwd).toBe('/projects/app');\n expect(enriched[0].startTime).toBeUndefined();\n });\n});\n\ndescribe('wrapper process detection', () => {\n it('finds the parent wrapper process for a child in the same terminal and cwd', () => {\n const wrapper = { pid: 100, ppid: 1, command: 'node /bin/gemini', cwd: '/repo', tty: 'ttys001' };\n const child = { pid: 200, ppid: 100, command: 'node --max-old-space-size=8192 /bin/gemini', cwd: '/repo', tty: 'ttys001' };\n\n expect(findWrapperProcess([wrapper, child], child)).toBe(wrapper);\n expect(findWrapperProcessPids([wrapper, child])).toEqual(new Set([100]));\n });\n\n it('does not mark a matched child process as its own wrapper', () => {\n const child = { pid: 200, ppid: 100, command: 'node --max-old-space-size=8192 /bin/gemini', cwd: '/repo', tty: 'ttys001' };\n\n expect(findWrapperProcessPids([child], [child])).toEqual(new Set());\n });\n});\n"],"names":["execFile","execFileSync","listAgentProcesses","batchGetProcessCwds","batchGetProcessStartTimes","enrichProcesses","findWrapperProcess","findWrapperProcessPids","captureProcessSnapshot","filterByProcessNames","vi","mock","fn","mockedExecFileSync","mockedExecFile","describe","beforeEach","mockReset","it","mockImplementation","file","args","_options","callback","queueMicrotask","includes","some","arg","Error","join","snapshot","expect","map","process","pid","toEqual","cwd","startTime","any","Date","not","toHaveBeenCalled","calls","filter","toHaveLength","options","toMatchObject","encoding","maxBuffer","toHaveProperty","processes","command","tty","mockReturnValue","toBe","ppid","p","toHaveBeenCalledWith","cwds","get","Map","size","times","getFullYear","getMonth","has","mockReturnValueOnce","enriched","toBeDefined","mockImplementationOnce","toBeUndefined","wrapper","child","Set"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/utils/process.test.ts"],"sourcesContent":["/**\n * Tests for new functions in utils/process.ts\n */\n\nimport type { MockedFunction } from \"vitest\";\n\nimport { execFile, execFileSync } from \"child_process\";\nimport {\n listAgentProcesses,\n batchGetProcessCwds,\n batchGetProcessStartTimes,\n enrichProcesses,\n findWrapperProcess,\n findWrapperProcessPids,\n captureProcessSnapshot,\n filterByProcessNames,\n} from \"../../utils/process.js\";\n\nvi.mock(\"child_process\", () => ({\n execFile: vi.fn(),\n execFileSync: vi.fn(),\n}));\n\nconst mockedExecFileSync = execFileSync as MockedFunction<typeof execFileSync>;\nconst mockedExecFile = execFile as unknown as MockedFunction<\n (\n file: string,\n args: readonly string[],\n options: object,\n callback: (error: Error | null, stdout: string, stderr: string) => void,\n ) => void\n>;\n\ndescribe(\"captureProcessSnapshot\", () => {\n beforeEach(() => {\n mockedExecFile.mockReset();\n mockedExecFileSync.mockReset();\n });\n\n it(\"captures and enriches relevant processes without synchronous scans\", async () => {\n mockedExecFile.mockImplementation((file, args, _options, callback) => {\n queueMicrotask(() => {\n if (file === \"ps\" && args.includes(\"-axo\")) {\n callback(\n null,\n \"100 1 s001 /usr/bin/claude --resume abc\\n\" +\n \"200 1 s002 C:\\\\\\\\tools\\\\\\\\node.exe C:\\\\\\\\bin\\\\\\\\pi.js\\n\" +\n \"300 1 s003 /usr/bin/unrelated\\n\",\n \"\",\n );\n return;\n }\n if (file === \"lsof\") {\n callback(null, \"p100\\nn/projects/claude\\np200\\nn/projects/pi\\n\", \"\");\n return;\n }\n if (file === \"ps\" && args.some((arg) => arg.includes(\"lstart=\"))) {\n callback(null, \"100 Wed Mar 18 23:18:01 2026\\n\" + \"200 Thu Mar 19 10:00:00 2026\\n\", \"\");\n return;\n }\n callback(new Error(`unexpected command: ${file} ${args.join(\" \")}`), \"\", \"\");\n });\n });\n\n const snapshot = await captureProcessSnapshot([\"claude\", \"node\"]);\n\n expect(snapshot.map((process) => process.pid)).toEqual([100, 200]);\n expect(snapshot.map((process) => process.cwd)).toEqual([\"/projects/claude\", \"/projects/pi\"]);\n expect(snapshot.map((process) => process.startTime)).toEqual([\n expect.any(Date),\n expect.any(Date),\n ]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n expect(mockedExecFile.mock.calls.filter(([, args]) => args.includes(\"-axo\"))).toHaveLength(1);\n for (const [, , options] of mockedExecFile.mock.calls) {\n expect(options).toMatchObject({ encoding: \"utf-8\", maxBuffer: 10 * 1024 * 1024 });\n expect(options).not.toHaveProperty(\"stdio\");\n }\n });\n});\n\ndescribe(\"filterByProcessNames\", () => {\n it(\"matches only argv[0] and normalizes Windows paths and executable suffixes\", () => {\n const processes: ProcessInfo[] = [\n { pid: 1, command: \"C:\\\\tools\\\\node.exe C:\\\\bin\\\\pi.js\", cwd: \"\", tty: \"\" },\n { pid: 2, command: \"/usr/local/bin/node /opt/gemini.js\", cwd: \"\", tty: \"\" },\n { pid: 3, command: \"codex exec --cd C:\\\\repos\\\\node\", cwd: \"\", tty: \"\" },\n ];\n\n expect(filterByProcessNames(processes, [\"node\"])).toEqual([processes[0], processes[1]]);\n expect(filterByProcessNames(processes, [\"node.exe\"])).toEqual([processes[0], processes[1]]);\n });\n});\n\ndescribe(\"listAgentProcesses\", () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it(\"should parse ps output and post-filter by executable name\", () => {\n mockedExecFileSync.mockReturnValue(\n \"78070 1 s018 claude\\n\" + \"55106 55100 s015 claude\\n\",\n );\n\n const processes = listAgentProcesses(\"claude\");\n expect(processes).toHaveLength(2);\n expect(processes[0].pid).toBe(78070);\n expect(processes[0].ppid).toBe(1);\n expect(processes[0].command).toBe(\"claude\");\n expect(processes[0].tty).toBe(\"s018\");\n expect(processes[0].cwd).toBe(\"\"); // not populated yet\n expect(processes[1].pid).toBe(55106);\n expect(processes[1].ppid).toBe(55100);\n });\n\n it(\"should filter out non-matching executables\", () => {\n mockedExecFileSync.mockReturnValue(\n \"100 1 s001 claude\\n\" +\n \"200 1 s002 claude-helper --pid 100\\n\" +\n \"300 1 s003 /usr/bin/claude\\n\",\n );\n\n const processes = listAgentProcesses(\"claude\");\n expect(processes).toHaveLength(2);\n expect(processes.map((p) => p.pid)).toEqual([100, 300]);\n });\n\n it(\"should return empty array on command failure\", () => {\n mockedExecFileSync.mockImplementation(() => {\n throw new Error(\"fail\");\n });\n expect(listAgentProcesses(\"claude\")).toEqual([]);\n });\n\n it(\"should handle empty output\", () => {\n mockedExecFileSync.mockReturnValue(\"\");\n expect(listAgentProcesses(\"claude\")).toEqual([]);\n });\n\n it(\"should reject empty pattern\", () => {\n expect(listAgentProcesses(\"\")).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it(\"should reject patterns with shell injection characters\", () => {\n expect(listAgentProcesses(\"claude; rm -rf /\")).toEqual([]);\n expect(listAgentProcesses(\"claude' || true\")).toEqual([]);\n expect(listAgentProcesses(\"$(whoami)\")).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it(\"should accept valid patterns with dashes and underscores\", () => {\n mockedExecFileSync.mockReturnValue(\"\");\n listAgentProcesses(\"claude-code\");\n expect(mockedExecFileSync).toHaveBeenCalledWith(\"ps\", [\"-axo\", \"pid=,ppid=,tty=,command=\"], {\n encoding: \"utf-8\",\n });\n\n mockedExecFileSync.mockReset();\n mockedExecFileSync.mockReturnValue(\"\");\n listAgentProcesses(\"my_agent\");\n expect(mockedExecFileSync).toHaveBeenCalled();\n });\n});\n\ndescribe(\"batchGetProcessCwds\", () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it(\"should parse batched lsof output\", () => {\n mockedExecFileSync.mockReturnValue(\n \"p78070\\nn/Users/user/ai-devkit\\np55106\\nn/Users/user/other-project\\n\",\n );\n\n const cwds = batchGetProcessCwds([78070, 55106]);\n expect(cwds.get(78070)).toBe(\"/Users/user/ai-devkit\");\n expect(cwds.get(55106)).toBe(\"/Users/user/other-project\");\n });\n\n it(\"should return empty map for empty pids\", () => {\n expect(batchGetProcessCwds([])).toEqual(new Map());\n });\n\n it(\"should return partial results when lsof succeeds for some PIDs\", () => {\n // lsof might not return entries for dead processes\n mockedExecFileSync.mockReturnValue(\"p78070\\nn/Users/user/ai-devkit\\n\");\n\n const cwds = batchGetProcessCwds([78070, 99999]);\n expect(cwds.size).toBe(1);\n expect(cwds.get(78070)).toBe(\"/Users/user/ai-devkit\");\n });\n\n it(\"should return empty map on total failure\", () => {\n mockedExecFileSync.mockImplementation(() => {\n throw new Error(\"fail\");\n });\n const cwds = batchGetProcessCwds([78070]);\n // Falls through to pwdx fallback which also fails\n expect(cwds.size).toBe(0);\n });\n});\n\ndescribe(\"batchGetProcessStartTimes\", () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it(\"should parse ps lstart output\", () => {\n mockedExecFileSync.mockReturnValue(\n \" 78070 Wed Mar 18 23:18:01 2026\\n\" + \" 55106 Mon Mar 9 21:41:42 2026\\n\",\n );\n\n const times = batchGetProcessStartTimes([78070, 55106]);\n expect(times.size).toBe(2);\n expect(times.get(78070)?.getFullYear()).toBe(2026);\n expect(times.get(55106)?.getMonth()).toBe(2); // March = 2\n });\n\n it(\"should return empty map for empty pids\", () => {\n expect(batchGetProcessStartTimes([])).toEqual(new Map());\n });\n\n it(\"should skip lines with unparseable dates\", () => {\n mockedExecFileSync.mockReturnValue(\n \" 78070 Wed Mar 18 23:18:01 2026\\n\" + \" 99999 INVALID_DATE\\n\",\n );\n\n const times = batchGetProcessStartTimes([78070, 99999]);\n expect(times.size).toBe(1);\n expect(times.has(78070)).toBe(true);\n });\n\n it(\"should return empty map on failure\", () => {\n mockedExecFileSync.mockImplementation(() => {\n throw new Error(\"fail\");\n });\n expect(batchGetProcessStartTimes([78070])).toEqual(new Map());\n });\n});\n\ndescribe(\"enrichProcesses\", () => {\n beforeEach(() => {\n mockedExecFileSync.mockReset();\n });\n\n it(\"should populate cwd and startTime on processes\", () => {\n // First call: batchGetProcessCwds (lsof)\n // Second call: batchGetProcessStartTimes (ps lstart)\n mockedExecFileSync\n .mockReturnValueOnce(\"p100\\nn/projects/app\\n\")\n .mockReturnValueOnce(\" 100 Wed Mar 18 23:18:01 2026\\n\");\n\n const processes = [{ pid: 100, command: \"claude\", cwd: \"\", tty: \"s001\" }];\n\n const enriched = enrichProcesses(processes);\n expect(enriched[0].cwd).toBe(\"/projects/app\");\n expect(enriched[0].startTime).toBeDefined();\n });\n\n it(\"should return empty array for empty input\", () => {\n expect(enrichProcesses([])).toEqual([]);\n expect(mockedExecFileSync).not.toHaveBeenCalled();\n });\n\n it(\"should handle partial failures\", () => {\n // lsof succeeds, ps lstart fails\n mockedExecFileSync.mockReturnValueOnce(\"p100\\nn/projects/app\\n\").mockImplementationOnce(() => {\n throw new Error(\"fail\");\n });\n\n const processes = [{ pid: 100, command: \"claude\", cwd: \"\", tty: \"s001\" }];\n\n const enriched = enrichProcesses(processes);\n expect(enriched[0].cwd).toBe(\"/projects/app\");\n expect(enriched[0].startTime).toBeUndefined();\n });\n});\n\ndescribe(\"wrapper process detection\", () => {\n it(\"finds the parent wrapper process for a child in the same terminal and cwd\", () => {\n const wrapper = {\n pid: 100,\n ppid: 1,\n command: \"node /bin/gemini\",\n cwd: \"/repo\",\n tty: \"ttys001\",\n };\n const child = {\n pid: 200,\n ppid: 100,\n command: \"node --max-old-space-size=8192 /bin/gemini\",\n cwd: \"/repo\",\n tty: \"ttys001\",\n };\n\n expect(findWrapperProcess([wrapper, child], child)).toBe(wrapper);\n expect(findWrapperProcessPids([wrapper, child])).toEqual(new Set([100]));\n });\n\n it(\"does not mark a matched child process as its own wrapper\", () => {\n const child = {\n pid: 200,\n ppid: 100,\n command: \"node --max-old-space-size=8192 /bin/gemini\",\n cwd: \"/repo\",\n tty: \"ttys001\",\n };\n\n expect(findWrapperProcessPids([child], [child])).toEqual(new Set());\n });\n});\n"],"names":["execFile","execFileSync","listAgentProcesses","batchGetProcessCwds","batchGetProcessStartTimes","enrichProcesses","findWrapperProcess","findWrapperProcessPids","captureProcessSnapshot","filterByProcessNames","vi","mock","fn","mockedExecFileSync","mockedExecFile","describe","beforeEach","mockReset","it","mockImplementation","file","args","_options","callback","queueMicrotask","includes","some","arg","Error","join","snapshot","expect","map","process","pid","toEqual","cwd","startTime","any","Date","not","toHaveBeenCalled","calls","filter","toHaveLength","options","toMatchObject","encoding","maxBuffer","toHaveProperty","processes","command","tty","mockReturnValue","toBe","ppid","p","toHaveBeenCalledWith","cwds","get","Map","size","times","getFullYear","getMonth","has","mockReturnValueOnce","enriched","toBeDefined","mockImplementationOnce","toBeUndefined","wrapper","child","Set"],"mappings":"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"}