@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__/providers/claude/ClaudeSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from 'vitest';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';\n\nimport { AgentStatus, type ProcessInfo } from '../../../adapters/AgentAdapter.js';\nimport { ClaudeSessionLocator } from '../../../providers/claude/ClaudeSessionLocator.js';\nimport { batchGetSessionFileBirthtimes } from '../../../utils/session.js';\nimport type { SessionFile } from '../../../utils/session.js';\n\nvi.mock('../../../utils/session.js', async (importOriginal) => {\n const actual = await importOriginal() as typeof import('../../../utils/session.js');\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes =\n batchGetSessionFileBirthtimes as MockedFunction<typeof batchGetSessionFileBirthtimes>;\n\nconst tmpDirs: string[] = [];\n\nfunction makeTmpDir(): string {\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'claude-locator-test-'));\n tmpDirs.push(dir);\n return dir;\n}\n\nfunction makeProcess(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 123,\n command: 'claude',\n cwd: '/repo/my-app',\n tty: 'ttys001',\n startTime: new Date('2026-08-23T10:00:00.000Z'),\n ...overrides,\n };\n}\n\ntype PidFileMatching = (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n};\n\n/** `tryPidFileMatching` is private; tests drive it directly like the sibling adapter suites do. */\nfunction bindPidFileMatching(locator: ClaudeSessionLocator): PidFileMatching {\n return (locator as unknown as { tryPidFileMatching: PidFileMatching })\n .tryPidFileMatching.bind(locator) as PidFileMatching;\n}\n\n/** `getProjectDir` is private; bound here so the encoding tests read cleanly. */\nfunction bindProjectDir(locator: ClaudeSessionLocator): (cwd: string) => string {\n return (locator as unknown as { getProjectDir: (cwd: string) => string })\n .getProjectDir.bind(locator);\n}\n\ndescribe('ClaudeSessionLocator', () => {\n beforeEach(() => {\n mockedBatchGetSessionFileBirthtimes.mockReset();\n });\n\n afterEach(() => {\n for (const dir of tmpDirs.splice(0)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n });\n\n it('matches resumed sessions directly and carries live PID status metadata', () => {\n const root = makeTmpDir();\n const projectsDir = path.join(root, 'projects');\n const sessionsDir = path.join(root, 'sessions');\n const cwd = '/repo/my-app';\n const sessionId = '12345678-1234-1234-1234-123456789abc';\n const projectDir = path.join(projectsDir, '-repo-my-app');\n const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);\n fs.mkdirSync(projectDir, { recursive: true });\n fs.mkdirSync(sessionsDir, { recursive: true });\n fs.writeFileSync(sessionFile, '{}\\n');\n fs.writeFileSync(path.join(sessionsDir, '123.json'), JSON.stringify({\n pid: 123,\n sessionId,\n cwd,\n startedAt: new Date('2026-08-23T10:00:00.000Z').getTime(),\n kind: 'interactive',\n entrypoint: 'cli',\n status: 'waiting',\n waitingFor: 'approve Read',\n }));\n\n const locator = new ClaudeSessionLocator({ projectsDir, sessionsDir });\n const matches = locator.matchRunningProcesses([\n makeProcess({ command: `claude --resume ${sessionId}`, cwd }),\n ]);\n\n expect(matches.direct).toHaveLength(1);\n expect(matches.legacyMatches).toEqual([]);\n expect(matches.direct[0]).toMatchObject({\n pidStatus: AgentStatus.WAITING,\n waitingFor: 'approve Read',\n sessionFile: {\n sessionId,\n filePath: sessionFile,\n projectDir,\n resolvedCwd: cwd,\n },\n });\n });\n describe('discoverLiveSessions', () => {\n let tmpDir: string;\n let projectsDir: string;\n let locator: ClaudeSessionLocator;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, 'projects');\n locator = new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'sessions'),\n });\n });\n\n it('should return empty when projects dir does not exist', () => {\n const missing = new ClaudeSessionLocator({\n projectsDir: path.join(tmpDir, 'nonexistent'),\n sessionsDir: path.join(tmpDir, 'sessions'),\n });\n\n const result = missing.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '/test', tty: '' },\n ]);\n expect(result).toEqual([]);\n });\n\n it('should scan only directories matching process CWDs', () => {\n // /my/project → -my-project (encoded dir)\n const encodedDir = path.join(projectsDir, '-my-project');\n fs.mkdirSync(encodedDir, { recursive: true });\n\n // Also create another dir that should NOT be scanned\n const otherDir = path.join(projectsDir, '-other-project');\n fs.mkdirSync(otherDir, { recursive: true });\n\n const mockFiles: SessionFile[] = [\n {\n sessionId: 's1',\n filePath: path.join(encodedDir, 's1.jsonl'),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: '',\n },\n ];\n mockedBatchGetSessionFileBirthtimes.mockReturnValue(mockFiles);\n\n const processes = [\n { pid: 1, command: 'claude', cwd: '/my/project', tty: '' },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n expect(result).toHaveLength(1);\n expect(result[0].resolvedCwd).toBe('/my/project');\n // batchGetSessionFileBirthtimes called once with all dirs\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n });\n\n it('should return empty when encoded dir does not exist', () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // Process CWD /test encodes to -test, but that dir doesn't exist\n const result = locator.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '/test', tty: '' },\n ]);\n expect(result).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n });\n\n it('should deduplicate when multiple processes share same CWD', () => {\n const encodedDir = path.join(projectsDir, '-my-project');\n fs.mkdirSync(encodedDir, { recursive: true });\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n { sessionId: 's1', filePath: path.join(encodedDir, 's1.jsonl'), projectDir: encodedDir, birthtimeMs: 1710800324000, resolvedCwd: '' },\n ]);\n\n const processes = [\n { pid: 1, command: 'claude', cwd: '/my/project', tty: '' },\n { pid: 2, command: 'claude', cwd: '/my/project', tty: '' },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n // Should only call batch once with deduplicated dir\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n expect(result).toHaveLength(1);\n });\n\n it('should skip processes with empty cwd', () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n const result = locator.discoverLiveSessions([\n { pid: 1, command: 'claude', cwd: '', tty: '' },\n ]);\n expect(result).toEqual([]);\n });\n });\n\n describe('tryPidFileMatching', () => {\n let tmpDir: string;\n let sessionsDir: string;\n let projectsDir: string;\n let tryMatch: (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n };\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n sessionsDir = path.join(tmpDir, 'sessions');\n projectsDir = path.join(tmpDir, 'projects');\n fs.mkdirSync(sessionsDir, { recursive: true });\n tryMatch = bindPidFileMatching(new ClaudeSessionLocator({ projectsDir, sessionsDir }));\n });\n\n const makeProc = (pid: number, cwd = '/project/test', startTime?: Date): ProcessInfo => ({\n pid, command: 'claude', cwd, tty: 'ttys001', startTime,\n });\n\n const writePidFile = (pid: number, sessionId: string, cwd: string, startedAt: number) => {\n fs.writeFileSync(\n path.join(sessionsDir, `${pid}.json`),\n JSON.stringify({ pid, sessionId, cwd, startedAt, kind: 'interactive', entrypoint: 'cli' }),\n );\n };\n\n const writeJsonl = (cwd: string, sessionId: string) => {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, '-');\n const projDir = path.join(projectsDir, encoded);\n fs.mkdirSync(projDir, { recursive: true });\n const filePath = path.join(projDir, `${sessionId}.jsonl`);\n fs.writeFileSync(filePath, JSON.stringify({ type: 'assistant', timestamp: new Date().toISOString() }));\n return filePath;\n };\n\n it('should return direct match when PID file and JSONL both exist within time tolerance', () => {\n const startTime = new Date();\n const proc = makeProc(1001, '/project/test', startTime);\n writePidFile(1001, 'session-abc', '/project/test', startTime.getTime());\n writeJsonl('/project/test', 'session-abc');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n expect(direct[0].sessionFile.sessionId).toBe('session-abc');\n expect(direct[0].sessionFile.resolvedCwd).toBe('/project/test');\n expect(direct[0].process.pid).toBe(1001);\n });\n\n it('should fall back when PID file exists but JSONL is missing', () => {\n const startTime = new Date();\n const proc = makeProc(1002, '/project/test', startTime);\n writePidFile(1002, 'nonexistent-session', '/project/test', startTime.getTime());\n // No JSONL file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n expect(fallback[0].pid).toBe(1002);\n });\n\n it('should fall back when startedAt is stale (>60s from proc.startTime)', () => {\n const startTime = new Date();\n const staleTime = startTime.getTime() - 90_000; // 90 seconds earlier\n const proc = makeProc(1003, '/project/test', startTime);\n writePidFile(1003, 'stale-session', '/project/test', staleTime);\n writeJsonl('/project/test', 'stale-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it('should accept PID file when startedAt is within 60s tolerance', () => {\n const startTime = new Date();\n const closeTime = startTime.getTime() - 30_000; // 30 seconds earlier — within tolerance\n const proc = makeProc(1004, '/project/test', startTime);\n writePidFile(1004, 'close-session', '/project/test', closeTime);\n writeJsonl('/project/test', 'close-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n\n it('should fall back when PID file is absent', () => {\n const proc = makeProc(1005, '/project/test', new Date());\n // No PID file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it('should fall back when PID file contains malformed JSON', () => {\n const proc = makeProc(1006, '/project/test', new Date());\n fs.writeFileSync(path.join(sessionsDir, '1006.json'), 'not valid json {{{');\n\n expect(() => {\n const { direct, fallback } = tryMatch([proc]);\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n }).not.toThrow();\n });\n\n it('should fall back for all processes when sessions dir does not exist', () => {\n const missingSessions = bindPidFileMatching(new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'nonexistent-sessions'),\n }));\n const processes = [makeProc(2001, '/a', new Date()), makeProc(2002, '/b', new Date())];\n\n const { direct, fallback } = missingSessions(processes);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(2);\n });\n\n it('should correctly split mixed processes (some with PID files, some without)', () => {\n const startTime = new Date();\n const proc1 = makeProc(3001, '/project/one', startTime);\n const proc2 = makeProc(3002, '/project/two', startTime);\n const proc3 = makeProc(3003, '/project/three', startTime);\n\n writePidFile(3001, 'session-one', '/project/one', startTime.getTime());\n writeJsonl('/project/one', 'session-one');\n writePidFile(3003, 'session-three', '/project/three', startTime.getTime());\n writeJsonl('/project/three', 'session-three');\n // proc2 has no PID file\n\n const { direct, fallback } = tryMatch([proc1, proc2, proc3]);\n\n expect(direct).toHaveLength(2);\n expect(fallback).toHaveLength(1);\n expect(direct.map((d) => d.process.pid).sort()).toEqual([3001, 3003]);\n expect(fallback[0].pid).toBe(3002);\n });\n\n it('should skip stale-file check when proc.startTime is undefined', () => {\n const proc = makeProc(4001, '/project/test', undefined); // no startTime\n writePidFile(4001, 'no-time-session', '/project/test', Date.now() - 999_999);\n writeJsonl('/project/test', 'no-time-session');\n\n const { direct, fallback } = tryMatch([proc]);\n\n // startTime undefined → stale check skipped → direct match\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n });\n\n describe('getProjectDir', () => {\n let tmpDir: string;\n let projectsDir: string;\n let encode: (cwd: string) => string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, 'projects');\n encode = bindProjectDir(new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, 'sessions'),\n }));\n });\n\n it('should replace path separators with hyphens', () => {\n expect(encode('/Users/foo/bar')).toBe(path.join(projectsDir, '-Users-foo-bar'));\n });\n\n it('should encode underscores as hyphens (matches Claude Code CLI)', () => {\n expect(encode('/Users/foo/my_project')).toBe(path.join(projectsDir, '-Users-foo-my-project'));\n });\n\n it('should encode dots as hyphens', () => {\n expect(encode('/Users/foo/.worktrees/x')).toBe(path.join(projectsDir, '-Users-foo--worktrees-x'));\n });\n\n it('should collide paths that differ only in non-alphanumeric chars', () => {\n // The encoding is intentionally lossy — callers must\n // disambiguate via session JSONL contents, not dir name.\n expect(encode('/a/b_c')).toBe(encode('/a/b-c'));\n expect(encode('/a/b_c')).toBe(encode('/a/b.c'));\n });\n\n it('should resolve to a real session dir when cwd contains underscores', () => {\n const cwd = '/Users/foo/my_project';\n const expectedDir = path.join(projectsDir, '-Users-foo-my-project');\n fs.mkdirSync(expectedDir, { recursive: true });\n const sessionFile = path.join(expectedDir, 'session-underscore.jsonl');\n fs.writeFileSync(sessionFile, '');\n\n expect(encode(cwd)).toBe(expectedDir);\n expect(fs.existsSync(path.join(encode(cwd), 'session-underscore.jsonl'))).toBe(true);\n });\n });\n});\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","vi","AgentStatus","ClaudeSessionLocator","batchGetSessionFileBirthtimes","mock","importOriginal","actual","fn","mockedBatchGetSessionFileBirthtimes","tmpDirs","makeTmpDir","dir","mkdtempSync","join","tmpdir","push","makeProcess","overrides","pid","command","cwd","tty","startTime","Date","bindPidFileMatching","locator","tryPidFileMatching","bind","bindProjectDir","getProjectDir","mockReset","splice","rmSync","recursive","force","root","projectsDir","sessionsDir","sessionId","projectDir","sessionFile","mkdirSync","writeFileSync","JSON","stringify","startedAt","getTime","kind","entrypoint","status","waitingFor","matches","matchRunningProcesses","direct","toHaveLength","legacyMatches","toEqual","toMatchObject","pidStatus","WAITING","filePath","resolvedCwd","tmpDir","missing","result","discoverLiveSessions","encodedDir","otherDir","mockFiles","birthtimeMs","mockReturnValue","processes","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","not","toHaveBeenCalled","tryMatch","makeProc","writePidFile","writeJsonl","encoded","replace","projDir","type","timestamp","toISOString","proc","fallback","process","staleTime","closeTime","toThrow","missingSessions","proc1","proc2","proc3","map","d","sort","undefined","now","encode","expectedDir","existsSync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/__tests__/providers/claude/ClaudeSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { AgentStatus, type ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { ClaudeSessionLocator } from \"../../../providers/claude/ClaudeSessionLocator.js\";\nimport { batchGetSessionFileBirthtimes } from \"../../../utils/session.js\";\nimport type { SessionFile } from \"../../../utils/session.js\";\n\nvi.mock(\"../../../utils/session.js\", async (importOriginal) => {\n const actual = (await importOriginal()) as typeof import(\"../../../utils/session.js\");\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes as MockedFunction<\n typeof batchGetSessionFileBirthtimes\n>;\n\nconst tmpDirs: string[] = [];\n\nfunction makeTmpDir(): string {\n const dir = fs.mkdtempSync(path.join(os.tmpdir(), \"claude-locator-test-\"));\n tmpDirs.push(dir);\n return dir;\n}\n\nfunction makeProcess(overrides: Partial<ProcessInfo> = {}): ProcessInfo {\n return {\n pid: 123,\n command: \"claude\",\n cwd: \"/repo/my-app\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-08-23T10:00:00.000Z\"),\n ...overrides,\n };\n}\n\ntype PidFileMatching = (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n};\n\n/** `tryPidFileMatching` is private; tests drive it directly like the sibling adapter suites do. */\nfunction bindPidFileMatching(locator: ClaudeSessionLocator): PidFileMatching {\n return (locator as unknown as { tryPidFileMatching: PidFileMatching }).tryPidFileMatching.bind(\n locator,\n ) as PidFileMatching;\n}\n\n/** `getProjectDir` is private; bound here so the encoding tests read cleanly. */\nfunction bindProjectDir(locator: ClaudeSessionLocator): (cwd: string) => string {\n return (locator as unknown as { getProjectDir: (cwd: string) => string }).getProjectDir.bind(\n locator,\n );\n}\n\ndescribe(\"ClaudeSessionLocator\", () => {\n beforeEach(() => {\n mockedBatchGetSessionFileBirthtimes.mockReset();\n });\n\n afterEach(() => {\n for (const dir of tmpDirs.splice(0)) {\n fs.rmSync(dir, { recursive: true, force: true });\n }\n });\n\n it(\"matches resumed sessions directly and carries live PID status metadata\", () => {\n const root = makeTmpDir();\n const projectsDir = path.join(root, \"projects\");\n const sessionsDir = path.join(root, \"sessions\");\n const cwd = \"/repo/my-app\";\n const sessionId = \"12345678-1234-1234-1234-123456789abc\";\n const projectDir = path.join(projectsDir, \"-repo-my-app\");\n const sessionFile = path.join(projectDir, `${sessionId}.jsonl`);\n fs.mkdirSync(projectDir, { recursive: true });\n fs.mkdirSync(sessionsDir, { recursive: true });\n fs.writeFileSync(sessionFile, \"{}\\n\");\n fs.writeFileSync(\n path.join(sessionsDir, \"123.json\"),\n JSON.stringify({\n pid: 123,\n sessionId,\n cwd,\n startedAt: new Date(\"2026-08-23T10:00:00.000Z\").getTime(),\n kind: \"interactive\",\n entrypoint: \"cli\",\n status: \"waiting\",\n waitingFor: \"approve Read\",\n }),\n );\n\n const locator = new ClaudeSessionLocator({ projectsDir, sessionsDir });\n const matches = locator.matchRunningProcesses([\n makeProcess({ command: `claude --resume ${sessionId}`, cwd }),\n ]);\n\n expect(matches.direct).toHaveLength(1);\n expect(matches.legacyMatches).toEqual([]);\n expect(matches.direct[0]).toMatchObject({\n pidStatus: AgentStatus.WAITING,\n waitingFor: \"approve Read\",\n sessionFile: {\n sessionId,\n filePath: sessionFile,\n projectDir,\n resolvedCwd: cwd,\n },\n });\n });\n describe(\"discoverLiveSessions\", () => {\n let tmpDir: string;\n let projectsDir: string;\n let locator: ClaudeSessionLocator;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, \"projects\");\n locator = new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"sessions\"),\n });\n });\n\n it(\"should return empty when projects dir does not exist\", () => {\n const missing = new ClaudeSessionLocator({\n projectsDir: path.join(tmpDir, \"nonexistent\"),\n sessionsDir: path.join(tmpDir, \"sessions\"),\n });\n\n const result = missing.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"/test\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n });\n\n it(\"should scan only directories matching process CWDs\", () => {\n // /my/project → -my-project (encoded dir)\n const encodedDir = path.join(projectsDir, \"-my-project\");\n fs.mkdirSync(encodedDir, { recursive: true });\n\n // Also create another dir that should NOT be scanned\n const otherDir = path.join(projectsDir, \"-other-project\");\n fs.mkdirSync(otherDir, { recursive: true });\n\n const mockFiles: SessionFile[] = [\n {\n sessionId: \"s1\",\n filePath: path.join(encodedDir, \"s1.jsonl\"),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: \"\",\n },\n ];\n mockedBatchGetSessionFileBirthtimes.mockReturnValue(mockFiles);\n\n const processes = [{ pid: 1, command: \"claude\", cwd: \"/my/project\", tty: \"\" }];\n\n const result = locator.discoverLiveSessions(processes);\n expect(result).toHaveLength(1);\n expect(result[0].resolvedCwd).toBe(\"/my/project\");\n // batchGetSessionFileBirthtimes called once with all dirs\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n });\n\n it(\"should return empty when encoded dir does not exist\", () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n // Process CWD /test encodes to -test, but that dir doesn't exist\n const result = locator.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"/test\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n });\n\n it(\"should deduplicate when multiple processes share same CWD\", () => {\n const encodedDir = path.join(projectsDir, \"-my-project\");\n fs.mkdirSync(encodedDir, { recursive: true });\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n {\n sessionId: \"s1\",\n filePath: path.join(encodedDir, \"s1.jsonl\"),\n projectDir: encodedDir,\n birthtimeMs: 1710800324000,\n resolvedCwd: \"\",\n },\n ]);\n\n const processes = [\n { pid: 1, command: \"claude\", cwd: \"/my/project\", tty: \"\" },\n { pid: 2, command: \"claude\", cwd: \"/my/project\", tty: \"\" },\n ];\n\n const result = locator.discoverLiveSessions(processes);\n // Should only call batch once with deduplicated dir\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledTimes(1);\n expect(mockedBatchGetSessionFileBirthtimes).toHaveBeenCalledWith([encodedDir]);\n expect(result).toHaveLength(1);\n });\n\n it(\"should skip processes with empty cwd\", () => {\n fs.mkdirSync(projectsDir, { recursive: true });\n\n const result = locator.discoverLiveSessions([\n { pid: 1, command: \"claude\", cwd: \"\", tty: \"\" },\n ]);\n expect(result).toEqual([]);\n });\n });\n\n describe(\"tryPidFileMatching\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let projectsDir: string;\n let tryMatch: (processes: ProcessInfo[]) => {\n direct: Array<{ process: ProcessInfo; sessionFile: SessionFile }>;\n fallback: ProcessInfo[];\n };\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n sessionsDir = path.join(tmpDir, \"sessions\");\n projectsDir = path.join(tmpDir, \"projects\");\n fs.mkdirSync(sessionsDir, { recursive: true });\n tryMatch = bindPidFileMatching(new ClaudeSessionLocator({ projectsDir, sessionsDir }));\n });\n\n const makeProc = (pid: number, cwd = \"/project/test\", startTime?: Date): ProcessInfo => ({\n pid,\n command: \"claude\",\n cwd,\n tty: \"ttys001\",\n startTime,\n });\n\n const writePidFile = (pid: number, sessionId: string, cwd: string, startedAt: number) => {\n fs.writeFileSync(\n path.join(sessionsDir, `${pid}.json`),\n JSON.stringify({ pid, sessionId, cwd, startedAt, kind: \"interactive\", entrypoint: \"cli\" }),\n );\n };\n\n const writeJsonl = (cwd: string, sessionId: string) => {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n const projDir = path.join(projectsDir, encoded);\n fs.mkdirSync(projDir, { recursive: true });\n const filePath = path.join(projDir, `${sessionId}.jsonl`);\n fs.writeFileSync(\n filePath,\n JSON.stringify({ type: \"assistant\", timestamp: new Date().toISOString() }),\n );\n return filePath;\n };\n\n it(\"should return direct match when PID file and JSONL both exist within time tolerance\", () => {\n const startTime = new Date();\n const proc = makeProc(1001, \"/project/test\", startTime);\n writePidFile(1001, \"session-abc\", \"/project/test\", startTime.getTime());\n writeJsonl(\"/project/test\", \"session-abc\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n expect(direct[0].sessionFile.sessionId).toBe(\"session-abc\");\n expect(direct[0].sessionFile.resolvedCwd).toBe(\"/project/test\");\n expect(direct[0].process.pid).toBe(1001);\n });\n\n it(\"should fall back when PID file exists but JSONL is missing\", () => {\n const startTime = new Date();\n const proc = makeProc(1002, \"/project/test\", startTime);\n writePidFile(1002, \"nonexistent-session\", \"/project/test\", startTime.getTime());\n // No JSONL file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n expect(fallback[0].pid).toBe(1002);\n });\n\n it(\"should fall back when startedAt is stale (>60s from proc.startTime)\", () => {\n const startTime = new Date();\n const staleTime = startTime.getTime() - 90_000; // 90 seconds earlier\n const proc = makeProc(1003, \"/project/test\", startTime);\n writePidFile(1003, \"stale-session\", \"/project/test\", staleTime);\n writeJsonl(\"/project/test\", \"stale-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it(\"should accept PID file when startedAt is within 60s tolerance\", () => {\n const startTime = new Date();\n const closeTime = startTime.getTime() - 30_000; // 30 seconds earlier — within tolerance\n const proc = makeProc(1004, \"/project/test\", startTime);\n writePidFile(1004, \"close-session\", \"/project/test\", closeTime);\n writeJsonl(\"/project/test\", \"close-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n\n it(\"should fall back when PID file is absent\", () => {\n const proc = makeProc(1005, \"/project/test\", new Date());\n // No PID file written\n\n const { direct, fallback } = tryMatch([proc]);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n });\n\n it(\"should fall back when PID file contains malformed JSON\", () => {\n const proc = makeProc(1006, \"/project/test\", new Date());\n fs.writeFileSync(path.join(sessionsDir, \"1006.json\"), \"not valid json {{{\");\n\n expect(() => {\n const { direct, fallback } = tryMatch([proc]);\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(1);\n }).not.toThrow();\n });\n\n it(\"should fall back for all processes when sessions dir does not exist\", () => {\n const missingSessions = bindPidFileMatching(\n new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"nonexistent-sessions\"),\n }),\n );\n const processes = [makeProc(2001, \"/a\", new Date()), makeProc(2002, \"/b\", new Date())];\n\n const { direct, fallback } = missingSessions(processes);\n\n expect(direct).toHaveLength(0);\n expect(fallback).toHaveLength(2);\n });\n\n it(\"should correctly split mixed processes (some with PID files, some without)\", () => {\n const startTime = new Date();\n const proc1 = makeProc(3001, \"/project/one\", startTime);\n const proc2 = makeProc(3002, \"/project/two\", startTime);\n const proc3 = makeProc(3003, \"/project/three\", startTime);\n\n writePidFile(3001, \"session-one\", \"/project/one\", startTime.getTime());\n writeJsonl(\"/project/one\", \"session-one\");\n writePidFile(3003, \"session-three\", \"/project/three\", startTime.getTime());\n writeJsonl(\"/project/three\", \"session-three\");\n // proc2 has no PID file\n\n const { direct, fallback } = tryMatch([proc1, proc2, proc3]);\n\n expect(direct).toHaveLength(2);\n expect(fallback).toHaveLength(1);\n expect(direct.map((d) => d.process.pid).sort()).toEqual([3001, 3003]);\n expect(fallback[0].pid).toBe(3002);\n });\n\n it(\"should skip stale-file check when proc.startTime is undefined\", () => {\n const proc = makeProc(4001, \"/project/test\", undefined); // no startTime\n writePidFile(4001, \"no-time-session\", \"/project/test\", Date.now() - 999_999);\n writeJsonl(\"/project/test\", \"no-time-session\");\n\n const { direct, fallback } = tryMatch([proc]);\n\n // startTime undefined → stale check skipped → direct match\n expect(direct).toHaveLength(1);\n expect(fallback).toHaveLength(0);\n });\n });\n\n describe(\"getProjectDir\", () => {\n let tmpDir: string;\n let projectsDir: string;\n let encode: (cwd: string) => string;\n\n beforeEach(() => {\n tmpDir = makeTmpDir();\n projectsDir = path.join(tmpDir, \"projects\");\n encode = bindProjectDir(\n new ClaudeSessionLocator({\n projectsDir,\n sessionsDir: path.join(tmpDir, \"sessions\"),\n }),\n );\n });\n\n it(\"should replace path separators with hyphens\", () => {\n expect(encode(\"/Users/foo/bar\")).toBe(path.join(projectsDir, \"-Users-foo-bar\"));\n });\n\n it(\"should encode underscores as hyphens (matches Claude Code CLI)\", () => {\n expect(encode(\"/Users/foo/my_project\")).toBe(path.join(projectsDir, \"-Users-foo-my-project\"));\n });\n\n it(\"should encode dots as hyphens\", () => {\n expect(encode(\"/Users/foo/.worktrees/x\")).toBe(\n path.join(projectsDir, \"-Users-foo--worktrees-x\"),\n );\n });\n\n it(\"should collide paths that differ only in non-alphanumeric chars\", () => {\n // The encoding is intentionally lossy — callers must\n // disambiguate via session JSONL contents, not dir name.\n expect(encode(\"/a/b_c\")).toBe(encode(\"/a/b-c\"));\n expect(encode(\"/a/b_c\")).toBe(encode(\"/a/b.c\"));\n });\n\n it(\"should resolve to a real session dir when cwd contains underscores\", () => {\n const cwd = \"/Users/foo/my_project\";\n const expectedDir = path.join(projectsDir, \"-Users-foo-my-project\");\n fs.mkdirSync(expectedDir, { recursive: true });\n const sessionFile = path.join(expectedDir, \"session-underscore.jsonl\");\n fs.writeFileSync(sessionFile, \"\");\n\n expect(encode(cwd)).toBe(expectedDir);\n expect(fs.existsSync(path.join(encode(cwd), \"session-underscore.jsonl\"))).toBe(true);\n });\n });\n});\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","vi","AgentStatus","ClaudeSessionLocator","batchGetSessionFileBirthtimes","mock","importOriginal","actual","fn","mockedBatchGetSessionFileBirthtimes","tmpDirs","makeTmpDir","dir","mkdtempSync","join","tmpdir","push","makeProcess","overrides","pid","command","cwd","tty","startTime","Date","bindPidFileMatching","locator","tryPidFileMatching","bind","bindProjectDir","getProjectDir","mockReset","splice","rmSync","recursive","force","root","projectsDir","sessionsDir","sessionId","projectDir","sessionFile","mkdirSync","writeFileSync","JSON","stringify","startedAt","getTime","kind","entrypoint","status","waitingFor","matches","matchRunningProcesses","direct","toHaveLength","legacyMatches","toEqual","toMatchObject","pidStatus","WAITING","filePath","resolvedCwd","tmpDir","missing","result","discoverLiveSessions","encodedDir","otherDir","mockFiles","birthtimeMs","mockReturnValue","processes","toBe","toHaveBeenCalledTimes","toHaveBeenCalledWith","not","toHaveBeenCalled","tryMatch","makeProc","writePidFile","writeJsonl","encoded","replace","projDir","type","timestamp","toISOString","proc","fallback","process","staleTime","closeTime","toThrow","missingSessions","proc1","proc2","proc3","map","d","sort","undefined","now","encode","expectedDir","existsSync"],"mappings":"AACA,YAAYA,QAAQ,KAAK;AACzB,YAAYC,QAAQ,KAAK;AACzB,YAAYC,UAAU,OAAO;AAC7B,SAASC,SAAS,EAAEC,UAAU,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAS;AAEzE,SAASC,WAAW,QAA0B,oCAAoC;AAClF,SAASC,oBAAoB,QAAQ,oDAAoD;AACzF,SAASC,6BAA6B,QAAQ,4BAA4B;AAG1EH,GAAGI,IAAI,CAAC,6BAA6B,OAAOC;IAC1C,MAAMC,SAAU,MAAMD;IACtB,OAAO;QACL,GAAGC,MAAM;QACTH,+BAA+BH,GAAGO,EAAE;IACtC;AACF;AAEA,MAAMC,sCAAsCL;AAI5C,MAAMM,UAAoB,EAAE;AAE5B,SAASC;IACP,MAAMC,MAAMnB,GAAGoB,WAAW,CAAClB,KAAKmB,IAAI,CAACpB,GAAGqB,MAAM,IAAI;IAClDL,QAAQM,IAAI,CAACJ;IACb,OAAOA;AACT;AAEA,SAASK,YAAYC,YAAkC,CAAC,CAAC;IACvD,OAAO;QACLC,KAAK;QACLC,SAAS;QACTC,KAAK;QACLC,KAAK;QACLC,WAAW,IAAIC,KAAK;QACpB,GAAGN,SAAS;IACd;AACF;AAOA,iGAAiG,GACjG,SAASO,oBAAoBC,OAA6B;IACxD,OAAO,AAACA,QAA+DC,kBAAkB,CAACC,IAAI,CAC5FF;AAEJ;AAEA,+EAA+E,GAC/E,SAASG,eAAeH,OAA6B;IACnD,OAAO,AAACA,QAAkEI,aAAa,CAACF,IAAI,CAC1FF;AAEJ;AAEA5B,SAAS,wBAAwB;IAC/BD,WAAW;QACTY,oCAAoCsB,SAAS;IAC/C;IAEAnC,UAAU;QACR,KAAK,MAAMgB,OAAOF,QAAQsB,MAAM,CAAC,GAAI;YACnCvC,GAAGwC,MAAM,CAACrB,KAAK;gBAAEsB,WAAW;gBAAMC,OAAO;YAAK;QAChD;IACF;IAEAnC,GAAG,0EAA0E;QAC3E,MAAMoC,OAAOzB;QACb,MAAM0B,cAAc1C,KAAKmB,IAAI,CAACsB,MAAM;QACpC,MAAME,cAAc3C,KAAKmB,IAAI,CAACsB,MAAM;QACpC,MAAMf,MAAM;QACZ,MAAMkB,YAAY;QAClB,MAAMC,aAAa7C,KAAKmB,IAAI,CAACuB,aAAa;QAC1C,MAAMI,cAAc9C,KAAKmB,IAAI,CAAC0B,YAAY,GAAGD,UAAU,MAAM,CAAC;QAC9D9C,GAAGiD,SAAS,CAACF,YAAY;YAAEN,WAAW;QAAK;QAC3CzC,GAAGiD,SAAS,CAACJ,aAAa;YAAEJ,WAAW;QAAK;QAC5CzC,GAAGkD,aAAa,CAACF,aAAa;QAC9BhD,GAAGkD,aAAa,CACdhD,KAAKmB,IAAI,CAACwB,aAAa,aACvBM,KAAKC,SAAS,CAAC;YACb1B,KAAK;YACLoB;YACAlB;YACAyB,WAAW,IAAItB,KAAK,4BAA4BuB,OAAO;YACvDC,MAAM;YACNC,YAAY;YACZC,QAAQ;YACRC,YAAY;QACd;QAGF,MAAMzB,UAAU,IAAIvB,qBAAqB;YAAEkC;YAAaC;QAAY;QACpE,MAAMc,UAAU1B,QAAQ2B,qBAAqB,CAAC;YAC5CpC,YAAY;gBAAEG,SAAS,CAAC,gBAAgB,EAAEmB,WAAW;gBAAElB;YAAI;SAC5D;QAEDtB,OAAOqD,QAAQE,MAAM,EAAEC,YAAY,CAAC;QACpCxD,OAAOqD,QAAQI,aAAa,EAAEC,OAAO,CAAC,EAAE;QACxC1D,OAAOqD,QAAQE,MAAM,CAAC,EAAE,EAAEI,aAAa,CAAC;YACtCC,WAAWzD,YAAY0D,OAAO;YAC9BT,YAAY;YACZV,aAAa;gBACXF;gBACAsB,UAAUpB;gBACVD;gBACAsB,aAAazC;YACf;QACF;IACF;IACAvB,SAAS,wBAAwB;QAC/B,IAAIiE;QACJ,IAAI1B;QACJ,IAAIX;QAEJ7B,WAAW;YACTkE,SAASpD;YACT0B,cAAc1C,KAAKmB,IAAI,CAACiD,QAAQ;YAChCrC,UAAU,IAAIvB,qBAAqB;gBACjCkC;gBACAC,aAAa3C,KAAKmB,IAAI,CAACiD,QAAQ;YACjC;QACF;QAEA/D,GAAG,wDAAwD;YACzD,MAAMgE,UAAU,IAAI7D,qBAAqB;gBACvCkC,aAAa1C,KAAKmB,IAAI,CAACiD,QAAQ;gBAC/BzB,aAAa3C,KAAKmB,IAAI,CAACiD,QAAQ;YACjC;YAEA,MAAME,SAASD,QAAQE,oBAAoB,CAAC;gBAC1C;oBAAE/C,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAASC,KAAK;gBAAG;aACpD;YACDvB,OAAOkE,QAAQR,OAAO,CAAC,EAAE;QAC3B;QAEAzD,GAAG,sDAAsD;YACvD,0CAA0C;YAC1C,MAAMmE,aAAaxE,KAAKmB,IAAI,CAACuB,aAAa;YAC1C5C,GAAGiD,SAAS,CAACyB,YAAY;gBAAEjC,WAAW;YAAK;YAE3C,qDAAqD;YACrD,MAAMkC,WAAWzE,KAAKmB,IAAI,CAACuB,aAAa;YACxC5C,GAAGiD,SAAS,CAAC0B,UAAU;gBAAElC,WAAW;YAAK;YAEzC,MAAMmC,YAA2B;gBAC/B;oBACE9B,WAAW;oBACXsB,UAAUlE,KAAKmB,IAAI,CAACqD,YAAY;oBAChC3B,YAAY2B;oBACZG,aAAa;oBACbR,aAAa;gBACf;aACD;YACDrD,oCAAoC8D,eAAe,CAACF;YAEpD,MAAMG,YAAY;gBAAC;oBAAErD,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAAeC,KAAK;gBAAG;aAAE;YAE9E,MAAM2C,SAASvC,QAAQwC,oBAAoB,CAACM;YAC5CzE,OAAOkE,QAAQV,YAAY,CAAC;YAC5BxD,OAAOkE,MAAM,CAAC,EAAE,CAACH,WAAW,EAAEW,IAAI,CAAC;YACnC,0DAA0D;YAC1D1E,OAAOU,qCAAqCiE,qBAAqB,CAAC;YAClE3E,OAAOU,qCAAqCkE,oBAAoB,CAAC;gBAACR;aAAW;QAC/E;QAEAnE,GAAG,uDAAuD;YACxDP,GAAGiD,SAAS,CAACL,aAAa;gBAAEH,WAAW;YAAK;YAE5C,iEAAiE;YACjE,MAAM+B,SAASvC,QAAQwC,oBAAoB,CAAC;gBAC1C;oBAAE/C,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAASC,KAAK;gBAAG;aACpD;YACDvB,OAAOkE,QAAQR,OAAO,CAAC,EAAE;YACzB1D,OAAOU,qCAAqCmE,GAAG,CAACC,gBAAgB;QAClE;QAEA7E,GAAG,6DAA6D;YAC9D,MAAMmE,aAAaxE,KAAKmB,IAAI,CAACuB,aAAa;YAC1C5C,GAAGiD,SAAS,CAACyB,YAAY;gBAAEjC,WAAW;YAAK;YAE3CzB,oCAAoC8D,eAAe,CAAC;gBAClD;oBACEhC,WAAW;oBACXsB,UAAUlE,KAAKmB,IAAI,CAACqD,YAAY;oBAChC3B,YAAY2B;oBACZG,aAAa;oBACbR,aAAa;gBACf;aACD;YAED,MAAMU,YAAY;gBAChB;oBAAErD,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAAeC,KAAK;gBAAG;gBACzD;oBAAEH,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAAeC,KAAK;gBAAG;aAC1D;YAED,MAAM2C,SAASvC,QAAQwC,oBAAoB,CAACM;YAC5C,oDAAoD;YACpDzE,OAAOU,qCAAqCiE,qBAAqB,CAAC;YAClE3E,OAAOU,qCAAqCkE,oBAAoB,CAAC;gBAACR;aAAW;YAC7EpE,OAAOkE,QAAQV,YAAY,CAAC;QAC9B;QAEAvD,GAAG,wCAAwC;YACzCP,GAAGiD,SAAS,CAACL,aAAa;gBAAEH,WAAW;YAAK;YAE5C,MAAM+B,SAASvC,QAAQwC,oBAAoB,CAAC;gBAC1C;oBAAE/C,KAAK;oBAAGC,SAAS;oBAAUC,KAAK;oBAAIC,KAAK;gBAAG;aAC/C;YACDvB,OAAOkE,QAAQR,OAAO,CAAC,EAAE;QAC3B;IACF;IAEA3D,SAAS,sBAAsB;QAC7B,IAAIiE;QACJ,IAAIzB;QACJ,IAAID;QACJ,IAAIyC;QAKJjF,WAAW;YACTkE,SAASpD;YACT2B,cAAc3C,KAAKmB,IAAI,CAACiD,QAAQ;YAChC1B,cAAc1C,KAAKmB,IAAI,CAACiD,QAAQ;YAChCtE,GAAGiD,SAAS,CAACJ,aAAa;gBAAEJ,WAAW;YAAK;YAC5C4C,WAAWrD,oBAAoB,IAAItB,qBAAqB;gBAAEkC;gBAAaC;YAAY;QACrF;QAEA,MAAMyC,WAAW,CAAC5D,KAAaE,MAAM,eAAe,EAAEE,YAAmC,CAAA;gBACvFJ;gBACAC,SAAS;gBACTC;gBACAC,KAAK;gBACLC;YACF,CAAA;QAEA,MAAMyD,eAAe,CAAC7D,KAAaoB,WAAmBlB,KAAayB;YACjErD,GAAGkD,aAAa,CACdhD,KAAKmB,IAAI,CAACwB,aAAa,GAAGnB,IAAI,KAAK,CAAC,GACpCyB,KAAKC,SAAS,CAAC;gBAAE1B;gBAAKoB;gBAAWlB;gBAAKyB;gBAAWE,MAAM;gBAAeC,YAAY;YAAM;QAE5F;QAEA,MAAMgC,aAAa,CAAC5D,KAAakB;YAC/B,MAAM2C,UAAU7D,IAAI8D,OAAO,CAAC,iBAAiB;YAC7C,MAAMC,UAAUzF,KAAKmB,IAAI,CAACuB,aAAa6C;YACvCzF,GAAGiD,SAAS,CAAC0C,SAAS;gBAAElD,WAAW;YAAK;YACxC,MAAM2B,WAAWlE,KAAKmB,IAAI,CAACsE,SAAS,GAAG7C,UAAU,MAAM,CAAC;YACxD9C,GAAGkD,aAAa,CACdkB,UACAjB,KAAKC,SAAS,CAAC;gBAAEwC,MAAM;gBAAaC,WAAW,IAAI9D,OAAO+D,WAAW;YAAG;YAE1E,OAAO1B;QACT;QAEA7D,GAAG,uFAAuF;YACxF,MAAMuB,YAAY,IAAIC;YACtB,MAAMgE,OAAOT,SAAS,MAAM,iBAAiBxD;YAC7CyD,aAAa,MAAM,eAAe,iBAAiBzD,UAAUwB,OAAO;YACpEkC,WAAW,iBAAiB;YAE5B,MAAM,EAAE3B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5CzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;YAC9BxD,OAAOuD,MAAM,CAAC,EAAE,CAACb,WAAW,CAACF,SAAS,EAAEkC,IAAI,CAAC;YAC7C1E,OAAOuD,MAAM,CAAC,EAAE,CAACb,WAAW,CAACqB,WAAW,EAAEW,IAAI,CAAC;YAC/C1E,OAAOuD,MAAM,CAAC,EAAE,CAACoC,OAAO,CAACvE,GAAG,EAAEsD,IAAI,CAAC;QACrC;QAEAzE,GAAG,8DAA8D;YAC/D,MAAMuB,YAAY,IAAIC;YACtB,MAAMgE,OAAOT,SAAS,MAAM,iBAAiBxD;YAC7CyD,aAAa,MAAM,uBAAuB,iBAAiBzD,UAAUwB,OAAO;YAC5E,wBAAwB;YAExB,MAAM,EAAEO,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5CzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;YAC9BxD,OAAO0F,QAAQ,CAAC,EAAE,CAACtE,GAAG,EAAEsD,IAAI,CAAC;QAC/B;QAEAzE,GAAG,uEAAuE;YACxE,MAAMuB,YAAY,IAAIC;YACtB,MAAMmE,YAAYpE,UAAUwB,OAAO,KAAK,QAAQ,qBAAqB;YACrE,MAAMyC,OAAOT,SAAS,MAAM,iBAAiBxD;YAC7CyD,aAAa,MAAM,iBAAiB,iBAAiBW;YACrDV,WAAW,iBAAiB;YAE5B,MAAM,EAAE3B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5CzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;QAChC;QAEAvD,GAAG,iEAAiE;YAClE,MAAMuB,YAAY,IAAIC;YACtB,MAAMoE,YAAYrE,UAAUwB,OAAO,KAAK,QAAQ,wCAAwC;YACxF,MAAMyC,OAAOT,SAAS,MAAM,iBAAiBxD;YAC7CyD,aAAa,MAAM,iBAAiB,iBAAiBY;YACrDX,WAAW,iBAAiB;YAE5B,MAAM,EAAE3B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5CzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;QAChC;QAEAvD,GAAG,4CAA4C;YAC7C,MAAMwF,OAAOT,SAAS,MAAM,iBAAiB,IAAIvD;YACjD,sBAAsB;YAEtB,MAAM,EAAE8B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5CzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;QAChC;QAEAvD,GAAG,0DAA0D;YAC3D,MAAMwF,OAAOT,SAAS,MAAM,iBAAiB,IAAIvD;YACjD/B,GAAGkD,aAAa,CAAChD,KAAKmB,IAAI,CAACwB,aAAa,cAAc;YAEtDvC,OAAO;gBACL,MAAM,EAAEuD,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;oBAACU;iBAAK;gBAC5CzF,OAAOuD,QAAQC,YAAY,CAAC;gBAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;YAChC,GAAGqB,GAAG,CAACiB,OAAO;QAChB;QAEA7F,GAAG,uEAAuE;YACxE,MAAM8F,kBAAkBrE,oBACtB,IAAItB,qBAAqB;gBACvBkC;gBACAC,aAAa3C,KAAKmB,IAAI,CAACiD,QAAQ;YACjC;YAEF,MAAMS,YAAY;gBAACO,SAAS,MAAM,MAAM,IAAIvD;gBAASuD,SAAS,MAAM,MAAM,IAAIvD;aAAQ;YAEtF,MAAM,EAAE8B,MAAM,EAAEmC,QAAQ,EAAE,GAAGK,gBAAgBtB;YAE7CzE,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;QAChC;QAEAvD,GAAG,8EAA8E;YAC/E,MAAMuB,YAAY,IAAIC;YACtB,MAAMuE,QAAQhB,SAAS,MAAM,gBAAgBxD;YAC7C,MAAMyE,QAAQjB,SAAS,MAAM,gBAAgBxD;YAC7C,MAAM0E,QAAQlB,SAAS,MAAM,kBAAkBxD;YAE/CyD,aAAa,MAAM,eAAe,gBAAgBzD,UAAUwB,OAAO;YACnEkC,WAAW,gBAAgB;YAC3BD,aAAa,MAAM,iBAAiB,kBAAkBzD,UAAUwB,OAAO;YACvEkC,WAAW,kBAAkB;YAC7B,wBAAwB;YAExB,MAAM,EAAE3B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACiB;gBAAOC;gBAAOC;aAAM;YAE3DlG,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;YAC9BxD,OAAOuD,OAAO4C,GAAG,CAAC,CAACC,IAAMA,EAAET,OAAO,CAACvE,GAAG,EAAEiF,IAAI,IAAI3C,OAAO,CAAC;gBAAC;gBAAM;aAAK;YACpE1D,OAAO0F,QAAQ,CAAC,EAAE,CAACtE,GAAG,EAAEsD,IAAI,CAAC;QAC/B;QAEAzE,GAAG,iEAAiE;YAClE,MAAMwF,OAAOT,SAAS,MAAM,iBAAiBsB,YAAY,eAAe;YACxErB,aAAa,MAAM,mBAAmB,iBAAiBxD,KAAK8E,GAAG,KAAK;YACpErB,WAAW,iBAAiB;YAE5B,MAAM,EAAE3B,MAAM,EAAEmC,QAAQ,EAAE,GAAGX,SAAS;gBAACU;aAAK;YAE5C,2DAA2D;YAC3DzF,OAAOuD,QAAQC,YAAY,CAAC;YAC5BxD,OAAO0F,UAAUlC,YAAY,CAAC;QAChC;IACF;IAEAzD,SAAS,iBAAiB;QACxB,IAAIiE;QACJ,IAAI1B;QACJ,IAAIkE;QAEJ1G,WAAW;YACTkE,SAASpD;YACT0B,cAAc1C,KAAKmB,IAAI,CAACiD,QAAQ;YAChCwC,SAAS1E,eACP,IAAI1B,qBAAqB;gBACvBkC;gBACAC,aAAa3C,KAAKmB,IAAI,CAACiD,QAAQ;YACjC;QAEJ;QAEA/D,GAAG,+CAA+C;YAChDD,OAAOwG,OAAO,mBAAmB9B,IAAI,CAAC9E,KAAKmB,IAAI,CAACuB,aAAa;QAC/D;QAEArC,GAAG,kEAAkE;YACnED,OAAOwG,OAAO,0BAA0B9B,IAAI,CAAC9E,KAAKmB,IAAI,CAACuB,aAAa;QACtE;QAEArC,GAAG,iCAAiC;YAClCD,OAAOwG,OAAO,4BAA4B9B,IAAI,CAC5C9E,KAAKmB,IAAI,CAACuB,aAAa;QAE3B;QAEArC,GAAG,mEAAmE;YACpE,qDAAqD;YACrD,yDAAyD;YACzDD,OAAOwG,OAAO,WAAW9B,IAAI,CAAC8B,OAAO;YACrCxG,OAAOwG,OAAO,WAAW9B,IAAI,CAAC8B,OAAO;QACvC;QAEAvG,GAAG,sEAAsE;YACvE,MAAMqB,MAAM;YACZ,MAAMmF,cAAc7G,KAAKmB,IAAI,CAACuB,aAAa;YAC3C5C,GAAGiD,SAAS,CAAC8D,aAAa;gBAAEtE,WAAW;YAAK;YAC5C,MAAMO,cAAc9C,KAAKmB,IAAI,CAAC0F,aAAa;YAC3C/G,GAAGkD,aAAa,CAACF,aAAa;YAE9B1C,OAAOwG,OAAOlF,MAAMoD,IAAI,CAAC+B;YACzBzG,OAAON,GAAGgH,UAAU,CAAC9G,KAAKmB,IAAI,CAACyF,OAAOlF,MAAM,8BAA8BoD,IAAI,CAAC;QACjF;IACF;AACF"}
@@ -0,0 +1,194 @@
1
+ import * as fs from "fs";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ import { CodexSessionLocator } from "../../../providers/codex/CodexSessionLocator.js";
5
+ import { batchGetSessionFileBirthtimes } from "../../../utils/session.js";
6
+ import { matchProcessesToSessions } from "../../../utils/matching.js";
7
+ vi.mock("../../../utils/session.js", async ()=>{
8
+ const actual = await vi.importActual("../../../utils/session");
9
+ return {
10
+ ...actual,
11
+ batchGetSessionFileBirthtimes: vi.fn()
12
+ };
13
+ });
14
+ vi.mock("../../../utils/matching.js", async ()=>{
15
+ const actual = await vi.importActual("../../../utils/matching");
16
+ return {
17
+ ...actual,
18
+ matchProcessesToSessions: vi.fn()
19
+ };
20
+ });
21
+ const mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes;
22
+ const mockedMatchProcessesToSessions = matchProcessesToSessions;
23
+ describe("CodexSessionLocator", ()=>{
24
+ let tmpDir;
25
+ let sessionsDir;
26
+ let locator;
27
+ beforeEach(()=>{
28
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-locator-"));
29
+ sessionsDir = path.join(tmpDir, "sessions");
30
+ locator = new CodexSessionLocator({
31
+ sessionsDir
32
+ });
33
+ mockedBatchGetSessionFileBirthtimes.mockReset();
34
+ mockedMatchProcessesToSessions.mockReset();
35
+ });
36
+ afterEach(()=>{
37
+ fs.rmSync(tmpDir, {
38
+ recursive: true,
39
+ force: true
40
+ });
41
+ });
42
+ it("discovers live sessions from the process start day window and applies session_meta cwd and timestamp", ()=>{
43
+ const dateDir = path.join(sessionsDir, "2026", "03", "18");
44
+ fs.mkdirSync(dateDir, {
45
+ recursive: true
46
+ });
47
+ const sessionFile = path.join(dateDir, "sess-meta-time.jsonl");
48
+ fs.writeFileSync(sessionFile, JSON.stringify({
49
+ type: "session_meta",
50
+ payload: {
51
+ id: "sess-meta-time",
52
+ timestamp: "2026-03-18T15:00:05.000Z",
53
+ cwd: "/repo-a"
54
+ }
55
+ }));
56
+ mockedBatchGetSessionFileBirthtimes.mockReturnValue([
57
+ {
58
+ sessionId: "sess-meta-time",
59
+ filePath: sessionFile,
60
+ projectDir: dateDir,
61
+ birthtimeMs: new Date("2026-03-18T15:05:30.000Z").getTime(),
62
+ resolvedCwd: ""
63
+ }
64
+ ]);
65
+ const { sessions, contentCache } = locator.discoverLiveSessions([
66
+ {
67
+ pid: 1,
68
+ command: "codex",
69
+ cwd: "/repo-a",
70
+ tty: "",
71
+ startTime: new Date("2026-03-18T15:00:00Z")
72
+ }
73
+ ]);
74
+ expect(sessions).toHaveLength(1);
75
+ expect(sessions[0]).toMatchObject({
76
+ resolvedCwd: "/repo-a",
77
+ birthtimeMs: new Date("2026-03-18T15:00:05.000Z").getTime()
78
+ });
79
+ expect(contentCache.has(sessionFile)).toBe(true);
80
+ expect(mockedBatchGetSessionFileBirthtimes.mock.calls[0][0]).toEqual([
81
+ dateDir
82
+ ]);
83
+ });
84
+ it("matches resumed UUIDv7 sessions directly without legacy matching", ()=>{
85
+ const sessionId = "019eabed-4079-7071-9531-b853ddd9914e";
86
+ const sessionFile = writeSession(sessionId, "2026/06/09");
87
+ const processInfo = {
88
+ pid: 88018,
89
+ command: `codex resume ${sessionId}`,
90
+ cwd: "/repo-a",
91
+ tty: "ttys001",
92
+ startTime: new Date("2026-06-10T12:00:00.000Z")
93
+ };
94
+ const result = locator.matchRunningProcesses([
95
+ processInfo
96
+ ]);
97
+ expect(result.direct).toHaveLength(1);
98
+ expect(result.direct[0]).toMatchObject({
99
+ process: processInfo,
100
+ sessionFile: {
101
+ sessionId,
102
+ filePath: sessionFile,
103
+ resolvedCwd: "/repo-a"
104
+ }
105
+ });
106
+ expect(result.fallback).toEqual([]);
107
+ expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();
108
+ expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
109
+ });
110
+ it("falls back to walking all session files for non-time-sortable resume ids", ()=>{
111
+ const sessionId = "aaaaaaaa-bbbb-4ccc-dddd-eeeeeeeeeeee";
112
+ const sessionFile = writeSession(sessionId, "2026/01/02");
113
+ const result = locator.matchRunningProcesses([
114
+ {
115
+ pid: 42,
116
+ command: `codex resume ${sessionId}`,
117
+ cwd: "/repo-a",
118
+ tty: "ttys001"
119
+ }
120
+ ]);
121
+ expect(result.direct[0].sessionFile.filePath).toBe(sessionFile);
122
+ });
123
+ it("passes unmatched processes and discovered sessions to legacy matching", ()=>{
124
+ const dateDir = path.join(sessionsDir, "2026", "03", "18");
125
+ fs.mkdirSync(dateDir, {
126
+ recursive: true
127
+ });
128
+ const candidate = {
129
+ sessionId: "sess",
130
+ filePath: path.join(dateDir, "sess.jsonl"),
131
+ projectDir: dateDir,
132
+ birthtimeMs: new Date("2026-03-18T15:00:05Z").getTime(),
133
+ resolvedCwd: ""
134
+ };
135
+ fs.writeFileSync(candidate.filePath, JSON.stringify({
136
+ type: "session_meta",
137
+ payload: {
138
+ id: "sess",
139
+ cwd: "/repo-a",
140
+ timestamp: "2026-03-18T15:00:05Z"
141
+ }
142
+ }));
143
+ const processInfo = {
144
+ pid: 100,
145
+ command: "codex",
146
+ cwd: "/repo-a",
147
+ tty: "ttys001",
148
+ startTime: new Date("2026-03-18T15:00:00Z")
149
+ };
150
+ const legacyMatch = {
151
+ process: processInfo,
152
+ session: {
153
+ ...candidate,
154
+ resolvedCwd: "/repo-a"
155
+ },
156
+ deltaMs: 5000
157
+ };
158
+ mockedBatchGetSessionFileBirthtimes.mockReturnValue([
159
+ candidate
160
+ ]);
161
+ mockedMatchProcessesToSessions.mockReturnValue([
162
+ legacyMatch
163
+ ]);
164
+ const result = locator.matchRunningProcesses([
165
+ processInfo
166
+ ]);
167
+ expect(result.direct).toEqual([]);
168
+ expect(result.fallback).toEqual([
169
+ processInfo
170
+ ]);
171
+ expect(result.legacyMatches).toEqual([
172
+ legacyMatch
173
+ ]);
174
+ expect(result.contentCache.has(candidate.filePath)).toBe(true);
175
+ });
176
+ function writeSession(sessionId, day) {
177
+ const dateDir = path.join(sessionsDir, ...day.split("/"));
178
+ fs.mkdirSync(dateDir, {
179
+ recursive: true
180
+ });
181
+ const sessionFile = path.join(dateDir, `${sessionId}.jsonl`);
182
+ fs.writeFileSync(sessionFile, JSON.stringify({
183
+ type: "session_meta",
184
+ payload: {
185
+ id: sessionId,
186
+ timestamp: "2026-03-18T15:00:05.000Z",
187
+ cwd: "/repo-a"
188
+ }
189
+ }));
190
+ return sessionFile;
191
+ }
192
+ });
193
+
194
+ //# sourceMappingURL=CodexSessionLocator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/__tests__/providers/codex/CodexSessionLocator.test.ts"],"sourcesContent":["import type { MockedFunction } from \"vitest\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { CodexSessionLocator } from \"../../../providers/codex/CodexSessionLocator.js\";\nimport { batchGetSessionFileBirthtimes, type SessionFile } from \"../../../utils/session.js\";\nimport { matchProcessesToSessions, type MatchResult } from \"../../../utils/matching.js\";\n\nvi.mock(\"../../../utils/session.js\", async () => {\n const actual = (await vi.importActual(\n \"../../../utils/session\",\n )) as typeof import(\"../../../utils/session\");\n return {\n ...actual,\n batchGetSessionFileBirthtimes: vi.fn(),\n };\n});\n\nvi.mock(\"../../../utils/matching.js\", async () => {\n const actual = (await vi.importActual(\n \"../../../utils/matching\",\n )) as typeof import(\"../../../utils/matching\");\n return {\n ...actual,\n matchProcessesToSessions: vi.fn(),\n };\n});\n\nconst mockedBatchGetSessionFileBirthtimes = batchGetSessionFileBirthtimes as MockedFunction<\n typeof batchGetSessionFileBirthtimes\n>;\nconst mockedMatchProcessesToSessions = matchProcessesToSessions as MockedFunction<\n typeof matchProcessesToSessions\n>;\n\ndescribe(\"CodexSessionLocator\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let locator: CodexSessionLocator;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"codex-locator-\"));\n sessionsDir = path.join(tmpDir, \"sessions\");\n locator = new CodexSessionLocator({ sessionsDir });\n mockedBatchGetSessionFileBirthtimes.mockReset();\n mockedMatchProcessesToSessions.mockReset();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n it(\"discovers live sessions from the process start day window and applies session_meta cwd and timestamp\", () => {\n const dateDir = path.join(sessionsDir, \"2026\", \"03\", \"18\");\n fs.mkdirSync(dateDir, { recursive: true });\n const sessionFile = path.join(dateDir, \"sess-meta-time.jsonl\");\n fs.writeFileSync(\n sessionFile,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: \"sess-meta-time\", timestamp: \"2026-03-18T15:00:05.000Z\", cwd: \"/repo-a\" },\n }),\n );\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([\n {\n sessionId: \"sess-meta-time\",\n filePath: sessionFile,\n projectDir: dateDir,\n birthtimeMs: new Date(\"2026-03-18T15:05:30.000Z\").getTime(),\n resolvedCwd: \"\",\n },\n ]);\n\n const { sessions, contentCache } = locator.discoverLiveSessions([\n {\n pid: 1,\n command: \"codex\",\n cwd: \"/repo-a\",\n tty: \"\",\n startTime: new Date(\"2026-03-18T15:00:00Z\"),\n },\n ]);\n\n expect(sessions).toHaveLength(1);\n expect(sessions[0]).toMatchObject({\n resolvedCwd: \"/repo-a\",\n birthtimeMs: new Date(\"2026-03-18T15:00:05.000Z\").getTime(),\n });\n expect(contentCache.has(sessionFile)).toBe(true);\n expect(mockedBatchGetSessionFileBirthtimes.mock.calls[0][0]).toEqual([dateDir]);\n });\n\n it(\"matches resumed UUIDv7 sessions directly without legacy matching\", () => {\n const sessionId = \"019eabed-4079-7071-9531-b853ddd9914e\";\n const sessionFile = writeSession(sessionId, \"2026/06/09\");\n const processInfo: ProcessInfo = {\n pid: 88018,\n command: `codex resume ${sessionId}`,\n cwd: \"/repo-a\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-06-10T12:00:00.000Z\"),\n };\n\n const result = locator.matchRunningProcesses([processInfo]);\n\n expect(result.direct).toHaveLength(1);\n expect(result.direct[0]).toMatchObject({\n process: processInfo,\n sessionFile: { sessionId, filePath: sessionFile, resolvedCwd: \"/repo-a\" },\n });\n expect(result.fallback).toEqual([]);\n expect(mockedBatchGetSessionFileBirthtimes).not.toHaveBeenCalled();\n expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();\n });\n\n it(\"falls back to walking all session files for non-time-sortable resume ids\", () => {\n const sessionId = \"aaaaaaaa-bbbb-4ccc-dddd-eeeeeeeeeeee\";\n const sessionFile = writeSession(sessionId, \"2026/01/02\");\n\n const result = locator.matchRunningProcesses([\n { pid: 42, command: `codex resume ${sessionId}`, cwd: \"/repo-a\", tty: \"ttys001\" },\n ]);\n\n expect(result.direct[0].sessionFile.filePath).toBe(sessionFile);\n });\n\n it(\"passes unmatched processes and discovered sessions to legacy matching\", () => {\n const dateDir = path.join(sessionsDir, \"2026\", \"03\", \"18\");\n fs.mkdirSync(dateDir, { recursive: true });\n const candidate: SessionFile = {\n sessionId: \"sess\",\n filePath: path.join(dateDir, \"sess.jsonl\"),\n projectDir: dateDir,\n birthtimeMs: new Date(\"2026-03-18T15:00:05Z\").getTime(),\n resolvedCwd: \"\",\n };\n fs.writeFileSync(\n candidate.filePath,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: \"sess\", cwd: \"/repo-a\", timestamp: \"2026-03-18T15:00:05Z\" },\n }),\n );\n const processInfo: ProcessInfo = {\n pid: 100,\n command: \"codex\",\n cwd: \"/repo-a\",\n tty: \"ttys001\",\n startTime: new Date(\"2026-03-18T15:00:00Z\"),\n };\n const legacyMatch: MatchResult = {\n process: processInfo,\n session: { ...candidate, resolvedCwd: \"/repo-a\" },\n deltaMs: 5000,\n };\n\n mockedBatchGetSessionFileBirthtimes.mockReturnValue([candidate]);\n mockedMatchProcessesToSessions.mockReturnValue([legacyMatch]);\n\n const result = locator.matchRunningProcesses([processInfo]);\n\n expect(result.direct).toEqual([]);\n expect(result.fallback).toEqual([processInfo]);\n expect(result.legacyMatches).toEqual([legacyMatch]);\n expect(result.contentCache.has(candidate.filePath)).toBe(true);\n });\n\n function writeSession(sessionId: string, day: string): string {\n const dateDir = path.join(sessionsDir, ...day.split(\"/\"));\n fs.mkdirSync(dateDir, { recursive: true });\n const sessionFile = path.join(dateDir, `${sessionId}.jsonl`);\n fs.writeFileSync(\n sessionFile,\n JSON.stringify({\n type: \"session_meta\",\n payload: { id: sessionId, timestamp: \"2026-03-18T15:00:05.000Z\", cwd: \"/repo-a\" },\n }),\n );\n return sessionFile;\n }\n});\n"],"names":["fs","os","path","CodexSessionLocator","batchGetSessionFileBirthtimes","matchProcessesToSessions","vi","mock","actual","importActual","fn","mockedBatchGetSessionFileBirthtimes","mockedMatchProcessesToSessions","describe","tmpDir","sessionsDir","locator","beforeEach","mkdtempSync","join","tmpdir","mockReset","afterEach","rmSync","recursive","force","it","dateDir","mkdirSync","sessionFile","writeFileSync","JSON","stringify","type","payload","id","timestamp","cwd","mockReturnValue","sessionId","filePath","projectDir","birthtimeMs","Date","getTime","resolvedCwd","sessions","contentCache","discoverLiveSessions","pid","command","tty","startTime","expect","toHaveLength","toMatchObject","has","toBe","calls","toEqual","writeSession","processInfo","result","matchRunningProcesses","direct","process","fallback","not","toHaveBeenCalled","candidate","legacyMatch","session","deltaMs","legacyMatches","day","split"],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import * as fs from "fs";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ import { CodexSessionMapping } from "../../../providers/codex/CodexSessionMapping.js";
5
+ describe("CodexSessionMapping", ()=>{
6
+ let tmpDir;
7
+ let sessionsDir;
8
+ let mappingPath;
9
+ let processInfo;
10
+ beforeEach(()=>{
11
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codex-mapping-"));
12
+ sessionsDir = path.join(tmpDir, ".codex", "sessions");
13
+ mappingPath = path.join(tmpDir, ".codex", "ai-devkit", "sessions.json");
14
+ processInfo = {
15
+ pid: 5151,
16
+ command: "codex",
17
+ cwd: "/repo",
18
+ tty: "ttys001"
19
+ };
20
+ });
21
+ afterEach(()=>{
22
+ fs.rmSync(tmpDir, {
23
+ recursive: true,
24
+ force: true
25
+ });
26
+ });
27
+ it("matches a process to an existing trusted session file", ()=>{
28
+ const sessionFile = path.join(sessionsDir, "2026", "06", "26", "session.jsonl");
29
+ fs.mkdirSync(path.dirname(sessionFile), {
30
+ recursive: true
31
+ });
32
+ fs.mkdirSync(path.dirname(mappingPath), {
33
+ recursive: true
34
+ });
35
+ fs.writeFileSync(sessionFile, "");
36
+ fs.writeFileSync(mappingPath, JSON.stringify({
37
+ 5151: sessionFile
38
+ }));
39
+ expect(createMapping().match([
40
+ processInfo
41
+ ])).toEqual({
42
+ matches: [
43
+ {
44
+ process: processInfo,
45
+ filePath: sessionFile
46
+ }
47
+ ],
48
+ fallback: []
49
+ });
50
+ });
51
+ it("falls back for malformed mappings, missing files, invalid pids, and untrusted paths", ()=>{
52
+ fs.mkdirSync(path.dirname(mappingPath), {
53
+ recursive: true
54
+ });
55
+ fs.writeFileSync(mappingPath, JSON.stringify({
56
+ invalid: path.join(sessionsDir, "ignored.jsonl"),
57
+ 5151: path.join(tmpDir, "outside.jsonl"),
58
+ 9999: path.join(sessionsDir, "missing.jsonl")
59
+ }));
60
+ expect(createMapping().match([
61
+ processInfo
62
+ ])).toEqual({
63
+ matches: [],
64
+ fallback: [
65
+ processInfo
66
+ ]
67
+ });
68
+ fs.writeFileSync(mappingPath, "{not-json");
69
+ expect(createMapping().match([
70
+ processInfo
71
+ ])).toEqual({
72
+ matches: [],
73
+ fallback: [
74
+ processInfo
75
+ ]
76
+ });
77
+ });
78
+ function createMapping() {
79
+ return new CodexSessionMapping({
80
+ mappingPath,
81
+ sessionsDir
82
+ });
83
+ }
84
+ });
85
+
86
+ //# sourceMappingURL=CodexSessionMapping.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/__tests__/providers/codex/CodexSessionMapping.test.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../../adapters/AgentAdapter.js\";\nimport { CodexSessionMapping } from \"../../../providers/codex/CodexSessionMapping.js\";\n\ndescribe(\"CodexSessionMapping\", () => {\n let tmpDir: string;\n let sessionsDir: string;\n let mappingPath: string;\n let processInfo: ProcessInfo;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"codex-mapping-\"));\n sessionsDir = path.join(tmpDir, \".codex\", \"sessions\");\n mappingPath = path.join(tmpDir, \".codex\", \"ai-devkit\", \"sessions.json\");\n processInfo = { pid: 5151, command: \"codex\", cwd: \"/repo\", tty: \"ttys001\" };\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n it(\"matches a process to an existing trusted session file\", () => {\n const sessionFile = path.join(sessionsDir, \"2026\", \"06\", \"26\", \"session.jsonl\");\n fs.mkdirSync(path.dirname(sessionFile), { recursive: true });\n fs.mkdirSync(path.dirname(mappingPath), { recursive: true });\n fs.writeFileSync(sessionFile, \"\");\n fs.writeFileSync(mappingPath, JSON.stringify({ 5151: sessionFile }));\n\n expect(createMapping().match([processInfo])).toEqual({\n matches: [{ process: processInfo, filePath: sessionFile }],\n fallback: [],\n });\n });\n\n it(\"falls back for malformed mappings, missing files, invalid pids, and untrusted paths\", () => {\n fs.mkdirSync(path.dirname(mappingPath), { recursive: true });\n fs.writeFileSync(\n mappingPath,\n JSON.stringify({\n invalid: path.join(sessionsDir, \"ignored.jsonl\"),\n 5151: path.join(tmpDir, \"outside.jsonl\"),\n 9999: path.join(sessionsDir, \"missing.jsonl\"),\n }),\n );\n\n expect(createMapping().match([processInfo])).toEqual({\n matches: [],\n fallback: [processInfo],\n });\n\n fs.writeFileSync(mappingPath, \"{not-json\");\n expect(createMapping().match([processInfo])).toEqual({\n matches: [],\n fallback: [processInfo],\n });\n });\n\n function createMapping(): CodexSessionMapping {\n return new CodexSessionMapping({ mappingPath, sessionsDir });\n }\n});\n"],"names":["fs","os","path","CodexSessionMapping","describe","tmpDir","sessionsDir","mappingPath","processInfo","beforeEach","mkdtempSync","join","tmpdir","pid","command","cwd","tty","afterEach","rmSync","recursive","force","it","sessionFile","mkdirSync","dirname","writeFileSync","JSON","stringify","expect","createMapping","match","toEqual","matches","process","filePath","fallback","invalid"],"mappings":"AAAA,YAAYA,QAAQ,KAAK;AACzB,YAAYC,QAAQ,KAAK;AACzB,YAAYC,UAAU,OAAO;AAE7B,SAASC,mBAAmB,QAAQ,kDAAkD;AAEtFC,SAAS,uBAAuB;IAC9B,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IACJ,IAAIC;IAEJC,WAAW;QACTJ,SAASL,GAAGU,WAAW,CAACR,KAAKS,IAAI,CAACV,GAAGW,MAAM,IAAI;QAC/CN,cAAcJ,KAAKS,IAAI,CAACN,QAAQ,UAAU;QAC1CE,cAAcL,KAAKS,IAAI,CAACN,QAAQ,UAAU,aAAa;QACvDG,cAAc;YAAEK,KAAK;YAAMC,SAAS;YAASC,KAAK;YAASC,KAAK;QAAU;IAC5E;IAEAC,UAAU;QACRjB,GAAGkB,MAAM,CAACb,QAAQ;YAAEc,WAAW;YAAMC,OAAO;QAAK;IACnD;IAEAC,GAAG,yDAAyD;QAC1D,MAAMC,cAAcpB,KAAKS,IAAI,CAACL,aAAa,QAAQ,MAAM,MAAM;QAC/DN,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACF,cAAc;YAAEH,WAAW;QAAK;QAC1DnB,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACjB,cAAc;YAAEY,WAAW;QAAK;QAC1DnB,GAAGyB,aAAa,CAACH,aAAa;QAC9BtB,GAAGyB,aAAa,CAAClB,aAAamB,KAAKC,SAAS,CAAC;YAAE,MAAML;QAAY;QAEjEM,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS;gBAAC;oBAAEC,SAASzB;oBAAa0B,UAAUZ;gBAAY;aAAE;YAC1Da,UAAU,EAAE;QACd;IACF;IAEAd,GAAG,uFAAuF;QACxFrB,GAAGuB,SAAS,CAACrB,KAAKsB,OAAO,CAACjB,cAAc;YAAEY,WAAW;QAAK;QAC1DnB,GAAGyB,aAAa,CACdlB,aACAmB,KAAKC,SAAS,CAAC;YACbS,SAASlC,KAAKS,IAAI,CAACL,aAAa;YAChC,MAAMJ,KAAKS,IAAI,CAACN,QAAQ;YACxB,MAAMH,KAAKS,IAAI,CAACL,aAAa;QAC/B;QAGFsB,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS,EAAE;YACXG,UAAU;gBAAC3B;aAAY;QACzB;QAEAR,GAAGyB,aAAa,CAAClB,aAAa;QAC9BqB,OAAOC,gBAAgBC,KAAK,CAAC;YAACtB;SAAY,GAAGuB,OAAO,CAAC;YACnDC,SAAS,EAAE;YACXG,UAAU;gBAAC3B;aAAY;QACzB;IACF;IAEA,SAASqB;QACP,OAAO,IAAI1B,oBAAoB;YAAEI;YAAaD;QAAY;IAC5D;AACF"}