@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/providers/claude/ClaudeSessionLocator.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport type { ProcessInfo } from '../../adapters/AgentAdapter.js';\nimport { AgentStatus } from '../../adapters/AgentAdapter.js';\nimport { matchProcessesToSessions, type MatchResult } from '../../utils/matching.js';\nimport {\n batchGetSessionFileBirthtimes,\n isDirectory,\n listJsonl,\n safeReaddir,\n safeStat,\n type SessionFile,\n} from '../../utils/session.js';\n\n/**\n * Entry in ~/.claude/sessions/<pid>.json written by Claude Code.\n * Maps a running process to its session file via PID.\n */\ninterface PidFileEntry {\n pid: number;\n sessionId: string;\n cwd: string;\n /** Epoch milliseconds when the Claude Code process started */\n startedAt: number;\n kind: string;\n entrypoint: string;\n /**\n * Authoritative live status published by the Claude Code process\n * (e.g., 'running', 'waiting', 'idle'). Preferred over JSONL-derived\n * status because trailing entries like 'permission-mode' / 'ai-title'\n * can mask the real conversational state.\n */\n status?: string;\n /** Short description of what the agent is waiting on (e.g., \"approve Read\"). */\n waitingFor?: string;\n}\n\n/**\n * A process directly matched to a session via PID file (authoritative path).\n *\n * When the matching PID file also exposes live status/waitingFor metadata,\n * those values are carried here so the agent mapper can prefer them over\n * the JSONL-derived heuristic.\n */\nexport interface ClaudeDirectMatch {\n process: ProcessInfo;\n sessionFile: SessionFile;\n pidStatus?: AgentStatus;\n waitingFor?: string;\n}\n\nexport interface ClaudeProcessSessionMatches {\n direct: ClaudeDirectMatch[];\n legacyMatches: MatchResult[];\n}\n\nexport interface ClaudeSessionLocatorOptions {\n projectsDir?: string;\n sessionsDir?: string;\n}\n\n/** Maximum allowed delta (ms) between process start time and PID file startedAt. */\nconst PID_FILE_STALENESS_MS = 60000;\n\nexport class ClaudeSessionLocator {\n private readonly projectsDir: string;\n private readonly sessionsDir: string;\n\n constructor(options: ClaudeSessionLocatorOptions = {}) {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n this.projectsDir = options.projectsDir ?? path.join(homeDir, '.claude', 'projects');\n this.sessionsDir = options.sessionsDir ?? path.join(homeDir, '.claude', 'sessions');\n }\n\n /**\n * Pair live Claude processes with their session files.\n *\n * Runs three staged strategies, each handing its unmatched processes\n * to the next:\n * 1. `--resume <id>` on the command line — authoritative for resumed\n * sessions whose JSONL predates the process.\n * 2. PID-file matching via ~/.claude/sessions/<pid>.json.\n * 3. Legacy CWD+birthtime heuristic, for processes with no PID file.\n */\n matchRunningProcesses(processes: ProcessInfo[]): ClaudeProcessSessionMatches {\n const { direct: resumeDirect, fallback: noResume } = this.tryResumeMatching(processes);\n const { direct: pidDirect, fallback } = this.tryPidFileMatching(noResume);\n const legacySessions = this.discoverLiveSessions(fallback);\n const legacyMatches =\n fallback.length > 0 && legacySessions.length > 0\n ? matchProcessesToSessions(fallback, legacySessions)\n : [];\n\n return {\n direct: [...resumeDirect, ...pidDirect],\n legacyMatches,\n };\n }\n\n /**\n * Discover candidate session files for listing historical sessions.\n *\n * Always walks every subdirectory of `projectsDir`. We can't use the\n * encoded-dir shortcut for the cwd-scoped path because Claude Code\n * indexes session files by where the *process was launched*, not by\n * the recorded `cwd` field inside the session — these diverge in\n * worktrees and similar setups. The cwd filter is applied later\n * against `session.lastCwd` so callers see exactly the sessions whose\n * recorded cwd matches.\n */\n discoverHistoricalSessionFiles(): Array<{ filePath: string; defaultCwd: string }> {\n const out: Array<{ filePath: string; defaultCwd: string }> = [];\n\n if (!isDirectory(this.projectsDir)) return out;\n\n for (const dirName of safeReaddir(this.projectsDir)) {\n const projectDir = path.join(this.projectsDir, dirName);\n if (!isDirectory(projectDir)) continue;\n\n // Best-effort decode for the rare case session content has no\n // recorded cwd: '-Users-foo-bar' → '/Users/foo/bar'. Lossy for\n // paths containing '-'; session content's lastCwd overrides\n // this when available.\n const decoded = dirName.replace(/-/g, '/');\n for (const name of listJsonl(projectDir)) {\n out.push({ filePath: path.join(projectDir, name), defaultCwd: decoded });\n }\n }\n\n return out;\n }\n\n /**\n * Derive the Claude Code project directory for a given CWD.\n *\n * Claude Code encodes paths by replacing every non-alphanumeric\n * character with '-', so '/', '_', '.', spaces, etc. all collapse:\n * /Users/foo/bar → -Users-foo-bar\n * /Users/foo/my_project → -Users-foo-my-project\n * /Users/foo/.worktrees/x → -Users-foo--worktrees-x\n *\n * The encoding is lossy — multiple real paths can collide on the\n * same encoded dir. Callers that need to disambiguate must read the\n * `cwd` field inside each session JSONL.\n */\n private getProjectDir(cwd: string): string {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, '-');\n return path.join(this.projectsDir, encoded);\n }\n\n /**\n * Discover session files for the given processes.\n *\n * For each unique process CWD, encodes it to derive the expected\n * ~/.claude/projects/<encoded>/ directory, then gets session file birthtimes\n * via a single batched stat call across all directories.\n */\n discoverLiveSessions(processes: ProcessInfo[]): SessionFile[] {\n const dirToCwd = new Map<string, string>();\n\n for (const proc of processes) {\n if (!proc.cwd) continue;\n\n const projectDir = this.getProjectDir(proc.cwd);\n if (dirToCwd.has(projectDir)) continue;\n\n try {\n if (!fs.statSync(projectDir).isDirectory()) continue;\n } catch {\n continue;\n }\n\n dirToCwd.set(projectDir, proc.cwd);\n }\n\n if (dirToCwd.size === 0) return [];\n\n const files = batchGetSessionFileBirthtimes([...dirToCwd.keys()]);\n\n for (const file of files) {\n file.resolvedCwd = dirToCwd.get(file.projectDir) || '';\n }\n\n return files;\n }\n\n /**\n * Match processes via `claude --resume <uuid>` in their command line.\n * This works for resumed sessions, where the JSONL was created earlier\n * (so its birthtime is far from the process startTime and the legacy\n * matcher can't pair them) and the PID file may also be misaligned.\n */\n private tryResumeMatching(processes: ProcessInfo[]): {\n direct: ClaudeDirectMatch[];\n fallback: ProcessInfo[];\n } {\n const direct: ClaudeDirectMatch[] = [];\n const fallback: ProcessInfo[] = [];\n\n for (const proc of processes) {\n const sessionId = this.extractResumeSessionId(proc.command);\n if (!sessionId || !proc.cwd) {\n fallback.push(proc);\n continue;\n }\n\n const projectDir = this.getProjectDir(proc.cwd);\n const jsonlPath = path.join(projectDir, `${sessionId}.jsonl`);\n\n const stat = safeStat(jsonlPath);\n if (!stat) {\n fallback.push(proc);\n continue;\n }\n\n // Best-effort: the PID file (if present for this proc) is the\n // authoritative source of live status. We still match the session\n // via --resume, but we read the PID file alongside to capture\n // status/waitingFor.\n const pidEntry = this.readMatchingPidFile(proc.pid, proc.startTime);\n\n direct.push({\n process: proc,\n sessionFile: {\n sessionId,\n filePath: jsonlPath,\n projectDir,\n birthtimeMs: stat.birthtimeMs,\n resolvedCwd: proc.cwd,\n },\n pidStatus: this.mapPidStatus(pidEntry?.status),\n waitingFor: pidEntry?.waitingFor,\n });\n }\n\n return { direct, fallback };\n }\n\n private extractResumeSessionId(command: string): string | null {\n const match = command.match(/--resume\\s+([0-9a-f-]{36})/i);\n return match?.[1] ?? null;\n }\n\n /**\n * Read and parse ~/.claude/sessions/<pid>.json, returning null on any\n * I/O / parse failure or when the file is stale relative to the live\n * process.\n *\n * \"Stale\" means the PID file's startedAt diverges from the process's\n * start time by more than {@link PID_FILE_STALENESS_MS} — typically\n * a previous Claude Code process recycled the same PID without cleanup.\n */\n private readMatchingPidFile(pid: number, procStartTime?: Date): PidFileEntry | null {\n const pidFilePath = path.join(this.sessionsDir, `${pid}.json`);\n try {\n const entry = JSON.parse(\n fs.readFileSync(pidFilePath, 'utf-8'),\n ) as PidFileEntry;\n\n if (procStartTime) {\n const deltaMs = Math.abs(procStartTime.getTime() - entry.startedAt);\n if (deltaMs > PID_FILE_STALENESS_MS) {\n return null;\n }\n }\n\n return entry;\n } catch {\n return null;\n }\n }\n\n /**\n * Map the PID file's live status string to {@link AgentStatus}.\n *\n * Returns undefined for missing / unrecognized values so the caller\n * can fall back to JSONL-derived heuristics.\n */\n private mapPidStatus(status: string | undefined): AgentStatus | undefined {\n switch (status) {\n case 'running':\n return AgentStatus.RUNNING;\n case 'waiting':\n return AgentStatus.WAITING;\n case 'idle':\n return AgentStatus.IDLE;\n default:\n return undefined;\n }\n }\n\n /**\n * Attempt to match each process to its session via ~/.claude/sessions/<pid>.json.\n *\n * Returns:\n * direct — processes matched authoritatively via PID file\n * fallback — processes with no valid PID file (sent to legacy matching)\n *\n * Per-process fallback triggers on: file absent, malformed JSON,\n * stale startedAt (>60s from proc.startTime), or missing JSONL.\n */\n private tryPidFileMatching(processes: ProcessInfo[]): {\n direct: ClaudeDirectMatch[];\n fallback: ProcessInfo[];\n } {\n const direct: ClaudeDirectMatch[] = [];\n const fallback: ProcessInfo[] = [];\n\n for (const proc of processes) {\n const entry = this.readMatchingPidFile(proc.pid, proc.startTime);\n if (!entry) {\n fallback.push(proc);\n continue;\n }\n\n const projectDir = this.getProjectDir(entry.cwd);\n const jsonlPath = path.join(projectDir, `${entry.sessionId}.jsonl`);\n\n if (!fs.existsSync(jsonlPath)) {\n fallback.push(proc);\n continue;\n }\n\n direct.push({\n process: proc,\n sessionFile: {\n sessionId: entry.sessionId,\n filePath: jsonlPath,\n projectDir,\n birthtimeMs: entry.startedAt,\n resolvedCwd: entry.cwd,\n },\n pidStatus: this.mapPidStatus(entry.status),\n waitingFor: entry.waitingFor,\n });\n }\n\n return { direct, fallback };\n }\n}\n"],"names":["fs","path","AgentStatus","matchProcessesToSessions","batchGetSessionFileBirthtimes","isDirectory","listJsonl","safeReaddir","safeStat","PID_FILE_STALENESS_MS","ClaudeSessionLocator","projectsDir","sessionsDir","options","homeDir","process","env","HOME","USERPROFILE","join","matchRunningProcesses","processes","direct","resumeDirect","fallback","noResume","tryResumeMatching","pidDirect","tryPidFileMatching","legacySessions","discoverLiveSessions","legacyMatches","length","discoverHistoricalSessionFiles","out","dirName","projectDir","decoded","replace","name","push","filePath","defaultCwd","getProjectDir","cwd","encoded","dirToCwd","Map","proc","has","statSync","set","size","files","keys","file","resolvedCwd","get","sessionId","extractResumeSessionId","command","jsonlPath","stat","pidEntry","readMatchingPidFile","pid","startTime","sessionFile","birthtimeMs","pidStatus","mapPidStatus","status","waitingFor","match","procStartTime","pidFilePath","entry","JSON","parse","readFileSync","deltaMs","Math","abs","getTime","startedAt","RUNNING","WAITING","IDLE","undefined","existsSync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/providers/claude/ClaudeSessionLocator.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { ProcessInfo } from \"../../adapters/AgentAdapter.js\";\nimport { AgentStatus } from \"../../adapters/AgentAdapter.js\";\nimport { matchProcessesToSessions, type MatchResult } from \"../../utils/matching.js\";\nimport {\n batchGetSessionFileBirthtimes,\n isDirectory,\n listJsonl,\n safeReaddir,\n safeStat,\n type SessionFile,\n} from \"../../utils/session.js\";\n\n/**\n * Entry in ~/.claude/sessions/<pid>.json written by Claude Code.\n * Maps a running process to its session file via PID.\n */\ninterface PidFileEntry {\n pid: number;\n sessionId: string;\n cwd: string;\n /** Epoch milliseconds when the Claude Code process started */\n startedAt: number;\n kind: string;\n entrypoint: string;\n /**\n * Authoritative live status published by the Claude Code process\n * (e.g., 'running', 'waiting', 'idle'). Preferred over JSONL-derived\n * status because trailing entries like 'permission-mode' / 'ai-title'\n * can mask the real conversational state.\n */\n status?: string;\n /** Short description of what the agent is waiting on (e.g., \"approve Read\"). */\n waitingFor?: string;\n}\n\n/**\n * A process directly matched to a session via PID file (authoritative path).\n *\n * When the matching PID file also exposes live status/waitingFor metadata,\n * those values are carried here so the agent mapper can prefer them over\n * the JSONL-derived heuristic.\n */\nexport interface ClaudeDirectMatch {\n process: ProcessInfo;\n sessionFile: SessionFile;\n pidStatus?: AgentStatus;\n waitingFor?: string;\n}\n\nexport interface ClaudeProcessSessionMatches {\n direct: ClaudeDirectMatch[];\n legacyMatches: MatchResult[];\n}\n\nexport interface ClaudeSessionLocatorOptions {\n projectsDir?: string;\n sessionsDir?: string;\n}\n\n/** Maximum allowed delta (ms) between process start time and PID file startedAt. */\nconst PID_FILE_STALENESS_MS = 60000;\n\nexport class ClaudeSessionLocator {\n private readonly projectsDir: string;\n private readonly sessionsDir: string;\n\n constructor(options: ClaudeSessionLocatorOptions = {}) {\n const homeDir = process.env.HOME || process.env.USERPROFILE || \"\";\n this.projectsDir = options.projectsDir ?? path.join(homeDir, \".claude\", \"projects\");\n this.sessionsDir = options.sessionsDir ?? path.join(homeDir, \".claude\", \"sessions\");\n }\n\n /**\n * Pair live Claude processes with their session files.\n *\n * Runs three staged strategies, each handing its unmatched processes\n * to the next:\n * 1. `--resume <id>` on the command line — authoritative for resumed\n * sessions whose JSONL predates the process.\n * 2. PID-file matching via ~/.claude/sessions/<pid>.json.\n * 3. Legacy CWD+birthtime heuristic, for processes with no PID file.\n */\n matchRunningProcesses(processes: ProcessInfo[]): ClaudeProcessSessionMatches {\n const { direct: resumeDirect, fallback: noResume } = this.tryResumeMatching(processes);\n const { direct: pidDirect, fallback } = this.tryPidFileMatching(noResume);\n const legacySessions = this.discoverLiveSessions(fallback);\n const legacyMatches =\n fallback.length > 0 && legacySessions.length > 0\n ? matchProcessesToSessions(fallback, legacySessions)\n : [];\n\n return {\n direct: [...resumeDirect, ...pidDirect],\n legacyMatches,\n };\n }\n\n /**\n * Discover candidate session files for listing historical sessions.\n *\n * Always walks every subdirectory of `projectsDir`. We can't use the\n * encoded-dir shortcut for the cwd-scoped path because Claude Code\n * indexes session files by where the *process was launched*, not by\n * the recorded `cwd` field inside the session — these diverge in\n * worktrees and similar setups. The cwd filter is applied later\n * against `session.lastCwd` so callers see exactly the sessions whose\n * recorded cwd matches.\n */\n discoverHistoricalSessionFiles(): Array<{ filePath: string; defaultCwd: string }> {\n const out: Array<{ filePath: string; defaultCwd: string }> = [];\n\n if (!isDirectory(this.projectsDir)) return out;\n\n for (const dirName of safeReaddir(this.projectsDir)) {\n const projectDir = path.join(this.projectsDir, dirName);\n if (!isDirectory(projectDir)) continue;\n\n // Best-effort decode for the rare case session content has no\n // recorded cwd: '-Users-foo-bar' → '/Users/foo/bar'. Lossy for\n // paths containing '-'; session content's lastCwd overrides\n // this when available.\n const decoded = dirName.replace(/-/g, \"/\");\n for (const name of listJsonl(projectDir)) {\n out.push({ filePath: path.join(projectDir, name), defaultCwd: decoded });\n }\n }\n\n return out;\n }\n\n /**\n * Derive the Claude Code project directory for a given CWD.\n *\n * Claude Code encodes paths by replacing every non-alphanumeric\n * character with '-', so '/', '_', '.', spaces, etc. all collapse:\n * /Users/foo/bar → -Users-foo-bar\n * /Users/foo/my_project → -Users-foo-my-project\n * /Users/foo/.worktrees/x → -Users-foo--worktrees-x\n *\n * The encoding is lossy — multiple real paths can collide on the\n * same encoded dir. Callers that need to disambiguate must read the\n * `cwd` field inside each session JSONL.\n */\n private getProjectDir(cwd: string): string {\n const encoded = cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n return path.join(this.projectsDir, encoded);\n }\n\n /**\n * Discover session files for the given processes.\n *\n * For each unique process CWD, encodes it to derive the expected\n * ~/.claude/projects/<encoded>/ directory, then gets session file birthtimes\n * via a single batched stat call across all directories.\n */\n discoverLiveSessions(processes: ProcessInfo[]): SessionFile[] {\n const dirToCwd = new Map<string, string>();\n\n for (const proc of processes) {\n if (!proc.cwd) continue;\n\n const projectDir = this.getProjectDir(proc.cwd);\n if (dirToCwd.has(projectDir)) continue;\n\n try {\n if (!fs.statSync(projectDir).isDirectory()) continue;\n } catch {\n continue;\n }\n\n dirToCwd.set(projectDir, proc.cwd);\n }\n\n if (dirToCwd.size === 0) return [];\n\n const files = batchGetSessionFileBirthtimes([...dirToCwd.keys()]);\n\n for (const file of files) {\n file.resolvedCwd = dirToCwd.get(file.projectDir) || \"\";\n }\n\n return files;\n }\n\n /**\n * Match processes via `claude --resume <uuid>` in their command line.\n * This works for resumed sessions, where the JSONL was created earlier\n * (so its birthtime is far from the process startTime and the legacy\n * matcher can't pair them) and the PID file may also be misaligned.\n */\n private tryResumeMatching(processes: ProcessInfo[]): {\n direct: ClaudeDirectMatch[];\n fallback: ProcessInfo[];\n } {\n const direct: ClaudeDirectMatch[] = [];\n const fallback: ProcessInfo[] = [];\n\n for (const proc of processes) {\n const sessionId = this.extractResumeSessionId(proc.command);\n if (!sessionId || !proc.cwd) {\n fallback.push(proc);\n continue;\n }\n\n const projectDir = this.getProjectDir(proc.cwd);\n const jsonlPath = path.join(projectDir, `${sessionId}.jsonl`);\n\n const stat = safeStat(jsonlPath);\n if (!stat) {\n fallback.push(proc);\n continue;\n }\n\n // Best-effort: the PID file (if present for this proc) is the\n // authoritative source of live status. We still match the session\n // via --resume, but we read the PID file alongside to capture\n // status/waitingFor.\n const pidEntry = this.readMatchingPidFile(proc.pid, proc.startTime);\n\n direct.push({\n process: proc,\n sessionFile: {\n sessionId,\n filePath: jsonlPath,\n projectDir,\n birthtimeMs: stat.birthtimeMs,\n resolvedCwd: proc.cwd,\n },\n pidStatus: this.mapPidStatus(pidEntry?.status),\n waitingFor: pidEntry?.waitingFor,\n });\n }\n\n return { direct, fallback };\n }\n\n private extractResumeSessionId(command: string): string | null {\n const match = command.match(/--resume\\s+([0-9a-f-]{36})/i);\n return match?.[1] ?? null;\n }\n\n /**\n * Read and parse ~/.claude/sessions/<pid>.json, returning null on any\n * I/O / parse failure or when the file is stale relative to the live\n * process.\n *\n * \"Stale\" means the PID file's startedAt diverges from the process's\n * start time by more than {@link PID_FILE_STALENESS_MS} — typically\n * a previous Claude Code process recycled the same PID without cleanup.\n */\n private readMatchingPidFile(pid: number, procStartTime?: Date): PidFileEntry | null {\n const pidFilePath = path.join(this.sessionsDir, `${pid}.json`);\n try {\n const entry = JSON.parse(fs.readFileSync(pidFilePath, \"utf-8\")) as PidFileEntry;\n\n if (procStartTime) {\n const deltaMs = Math.abs(procStartTime.getTime() - entry.startedAt);\n if (deltaMs > PID_FILE_STALENESS_MS) {\n return null;\n }\n }\n\n return entry;\n } catch {\n return null;\n }\n }\n\n /**\n * Map the PID file's live status string to {@link AgentStatus}.\n *\n * Returns undefined for missing / unrecognized values so the caller\n * can fall back to JSONL-derived heuristics.\n */\n private mapPidStatus(status: string | undefined): AgentStatus | undefined {\n switch (status) {\n case \"running\":\n return AgentStatus.RUNNING;\n case \"waiting\":\n return AgentStatus.WAITING;\n case \"idle\":\n return AgentStatus.IDLE;\n default:\n return undefined;\n }\n }\n\n /**\n * Attempt to match each process to its session via ~/.claude/sessions/<pid>.json.\n *\n * Returns:\n * direct — processes matched authoritatively via PID file\n * fallback — processes with no valid PID file (sent to legacy matching)\n *\n * Per-process fallback triggers on: file absent, malformed JSON,\n * stale startedAt (>60s from proc.startTime), or missing JSONL.\n */\n private tryPidFileMatching(processes: ProcessInfo[]): {\n direct: ClaudeDirectMatch[];\n fallback: ProcessInfo[];\n } {\n const direct: ClaudeDirectMatch[] = [];\n const fallback: ProcessInfo[] = [];\n\n for (const proc of processes) {\n const entry = this.readMatchingPidFile(proc.pid, proc.startTime);\n if (!entry) {\n fallback.push(proc);\n continue;\n }\n\n const projectDir = this.getProjectDir(entry.cwd);\n const jsonlPath = path.join(projectDir, `${entry.sessionId}.jsonl`);\n\n if (!fs.existsSync(jsonlPath)) {\n fallback.push(proc);\n continue;\n }\n\n direct.push({\n process: proc,\n sessionFile: {\n sessionId: entry.sessionId,\n filePath: jsonlPath,\n projectDir,\n birthtimeMs: entry.startedAt,\n resolvedCwd: entry.cwd,\n },\n pidStatus: this.mapPidStatus(entry.status),\n waitingFor: entry.waitingFor,\n });\n }\n\n return { direct, fallback };\n }\n}\n"],"names":["fs","path","AgentStatus","matchProcessesToSessions","batchGetSessionFileBirthtimes","isDirectory","listJsonl","safeReaddir","safeStat","PID_FILE_STALENESS_MS","ClaudeSessionLocator","projectsDir","sessionsDir","options","homeDir","process","env","HOME","USERPROFILE","join","matchRunningProcesses","processes","direct","resumeDirect","fallback","noResume","tryResumeMatching","pidDirect","tryPidFileMatching","legacySessions","discoverLiveSessions","legacyMatches","length","discoverHistoricalSessionFiles","out","dirName","projectDir","decoded","replace","name","push","filePath","defaultCwd","getProjectDir","cwd","encoded","dirToCwd","Map","proc","has","statSync","set","size","files","keys","file","resolvedCwd","get","sessionId","extractResumeSessionId","command","jsonlPath","stat","pidEntry","readMatchingPidFile","pid","startTime","sessionFile","birthtimeMs","pidStatus","mapPidStatus","status","waitingFor","match","procStartTime","pidFilePath","entry","JSON","parse","readFileSync","deltaMs","Math","abs","getTime","startedAt","RUNNING","WAITING","IDLE","undefined","existsSync"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { ConversationMessage } from '../../adapters/AgentAdapter.js';
2
- import { AgentStatus } from '../../adapters/AgentAdapter.js';
1
+ import type { ConversationMessage } from "../../adapters/AgentAdapter.js";
2
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
3
3
  /**
4
4
  * Content block within a Claude Code JSONL message entry.
5
5
  * Handles text, tool_use, and tool_result block types.
@@ -1 +1 @@
1
- {"version":3,"file":"ClaudeSessionParser.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/ClaudeSessionParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;KACrC,CAAC;CACL;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAoBD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC5B;;;;;;;;OAQG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAmFxE;;;;;;;;;OASG;IACH,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW;IA6BpD;;;;;OAKG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE;IA6ChG;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAwC9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACH,OAAO,CAAC,0BAA0B;CAmCrC"}
1
+ {"version":3,"file":"ClaudeSessionParser.d.ts","sourceRoot":"","sources":["../../../src/providers/claude/ClaudeSessionParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAAC;KACnC,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAcD;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAC9B;;;;;;;;OAQG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAiFxE;;;;;;;;;OASG;IACH,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,WAAW;IAwBpD;;;;;OAKG;IACH,eAAe,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,mBAAmB,EAAE;IA6ChG;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAwC9B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B;;OAEG;IACH,OAAO,CAAC,0BAA0B;CAoCnC"}
@@ -1,6 +1,6 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { AgentStatus } from '../../adapters/AgentAdapter.js';
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
4
4
  /**
5
5
  * Top-level JSONL entry types that represent conversation/agent state.
6
6
  *
@@ -11,11 +11,11 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
11
11
  * last conversation turn — otherwise polling between writes lands on a
12
12
  * UI-state entry and `determineStatus` falls through to UNKNOWN.
13
13
  */ const CONVERSATION_ENTRY_TYPES = new Set([
14
- 'user',
15
- 'assistant',
16
- 'system',
17
- 'progress',
18
- 'thinking'
14
+ "user",
15
+ "assistant",
16
+ "system",
17
+ "progress",
18
+ "thinking"
19
19
  ]);
20
20
  /**
21
21
  * Parses Claude Code session JSONL files into structured data.
@@ -25,22 +25,22 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
25
25
  * event (user turn, assistant response, tool call, etc.).
26
26
  */ export class ClaudeSessionParser {
27
27
  /**
28
- * Parse a session JSONL file into a ClaudeSession summary.
29
- *
30
- * Iterates all lines to extract: session start time (from first entry),
31
- * last activity timestamp, last entry type (for status), whether the
32
- * session was interrupted, and the last meaningful user message.
33
- *
34
- * Returns null if the file is unreadable or empty.
35
- */ readSession(filePath, projectPath) {
36
- const sessionId = path.basename(filePath, '.jsonl');
28
+ * Parse a session JSONL file into a ClaudeSession summary.
29
+ *
30
+ * Iterates all lines to extract: session start time (from first entry),
31
+ * last activity timestamp, last entry type (for status), whether the
32
+ * session was interrupted, and the last meaningful user message.
33
+ *
34
+ * Returns null if the file is unreadable or empty.
35
+ */ readSession(filePath, projectPath) {
36
+ const sessionId = path.basename(filePath, ".jsonl");
37
37
  let content;
38
38
  try {
39
- content = fs.readFileSync(filePath, 'utf-8');
39
+ content = fs.readFileSync(filePath, "utf-8");
40
40
  } catch {
41
41
  return null;
42
42
  }
43
- const allLines = content.trim().split('\n');
43
+ const allLines = content.trim().split("\n");
44
44
  if (allLines.length === 0) {
45
45
  return null;
46
46
  }
@@ -60,14 +60,14 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
60
60
  lastActive = ts;
61
61
  }
62
62
  }
63
- if (typeof entry.cwd === 'string' && entry.cwd.trim().length > 0) {
63
+ if (typeof entry.cwd === "string" && entry.cwd.trim().length > 0) {
64
64
  lastCwd = entry.cwd;
65
65
  }
66
66
  if (entry.type && CONVERSATION_ENTRY_TYPES.has(entry.type)) {
67
67
  lastEntryType = entry.type;
68
- if (entry.type === 'user') {
68
+ if (entry.type === "user") {
69
69
  const msgContent = entry.message?.content;
70
- isInterrupted = Array.isArray(msgContent) && msgContent.some((c)=>c.type === 'text' && c.text?.includes('[Request interrupted') || c.type === 'tool_result' && c.content?.includes('[Request interrupted'));
70
+ isInterrupted = Array.isArray(msgContent) && msgContent.some((c)=>c.type === "text" && c.text?.includes("[Request interrupted") || c.type === "tool_result" && c.content?.includes("[Request interrupted"));
71
71
  const text = this.extractUserMessageText(msgContent);
72
72
  if (text) {
73
73
  lastUserMessage = text;
@@ -85,7 +85,7 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
85
85
  }
86
86
  return {
87
87
  sessionId,
88
- projectPath: projectPath || lastCwd || '',
88
+ projectPath: projectPath || lastCwd || "",
89
89
  lastCwd,
90
90
  sessionStart: sessionStart || lastActive || new Date(),
91
91
  lastActive: lastActive || new Date(),
@@ -96,46 +96,46 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
96
96
  };
97
97
  }
98
98
  /**
99
- * Determine agent status from parsed session state.
100
- *
101
- * Status mapping:
102
- * - "user" + interrupted → WAITING (agent finished, awaiting new input)
103
- * - "user" + not interrupted → RUNNING (agent is processing)
104
- * - "progress" / "thinking" → RUNNING
105
- * - "assistant" → WAITING (agent responded, awaiting user)
106
- * - "system" → IDLE
107
- */ determineStatus(session) {
99
+ * Determine agent status from parsed session state.
100
+ *
101
+ * Status mapping:
102
+ * - "user" + interrupted → WAITING (agent finished, awaiting new input)
103
+ * - "user" + not interrupted → RUNNING (agent is processing)
104
+ * - "progress" / "thinking" → RUNNING
105
+ * - "assistant" → WAITING (agent responded, awaiting user)
106
+ * - "system" → IDLE
107
+ */ determineStatus(session) {
108
108
  if (!session.lastEntryType) {
109
109
  return AgentStatus.UNKNOWN;
110
110
  }
111
- if (session.lastEntryType === 'user') {
111
+ if (session.lastEntryType === "user") {
112
112
  return session.isInterrupted ? AgentStatus.WAITING : AgentStatus.RUNNING;
113
113
  }
114
- if (session.lastEntryType === 'progress' || session.lastEntryType === 'thinking') {
114
+ if (session.lastEntryType === "progress" || session.lastEntryType === "thinking") {
115
115
  return AgentStatus.RUNNING;
116
116
  }
117
- if (session.lastEntryType === 'assistant') {
117
+ if (session.lastEntryType === "assistant") {
118
118
  return AgentStatus.WAITING;
119
119
  }
120
- if (session.lastEntryType === 'system') {
120
+ if (session.lastEntryType === "system") {
121
121
  return AgentStatus.IDLE;
122
122
  }
123
123
  return AgentStatus.UNKNOWN;
124
124
  }
125
125
  /**
126
- * Read the full conversation from a session JSONL file.
127
- *
128
- * Default mode returns only text content from user/assistant/system messages.
129
- * Verbose mode also includes tool_use and tool_result blocks.
130
- */ getConversation(sessionFilePath, options) {
126
+ * Read the full conversation from a session JSONL file.
127
+ *
128
+ * Default mode returns only text content from user/assistant/system messages.
129
+ * Verbose mode also includes tool_use and tool_result blocks.
130
+ */ getConversation(sessionFilePath, options) {
131
131
  const verbose = options?.verbose ?? false;
132
132
  let content;
133
133
  try {
134
- content = fs.readFileSync(sessionFilePath, 'utf-8');
134
+ content = fs.readFileSync(sessionFilePath, "utf-8");
135
135
  } catch {
136
136
  return [];
137
137
  }
138
- const lines = content.trim().split('\n');
138
+ const lines = content.trim().split("\n");
139
139
  const messages = [];
140
140
  for (const line of lines){
141
141
  let entry;
@@ -145,12 +145,12 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
145
145
  continue;
146
146
  }
147
147
  let role;
148
- if (entry.type === 'user') {
149
- role = 'user';
150
- } else if (entry.type === 'assistant') {
151
- role = 'assistant';
152
- } else if (entry.type === 'system') {
153
- role = 'system';
148
+ if (entry.type === "user") {
149
+ role = "user";
150
+ } else if (entry.type === "assistant") {
151
+ role = "assistant";
152
+ } else if (entry.type === "system") {
153
+ role = "system";
154
154
  } else {
155
155
  continue;
156
156
  }
@@ -165,12 +165,12 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
165
165
  return messages;
166
166
  }
167
167
  /**
168
- * Parse session start time from the first JSONL line.
169
- *
170
- * Claude Code may emit a "file-history-snapshot" as the first entry,
171
- * which stores its timestamp inside "snapshot.timestamp" rather than
172
- * at the root level.
173
- */ parseSessionStart(firstLine) {
168
+ * Parse session start time from the first JSONL line.
169
+ *
170
+ * Claude Code may emit a "file-history-snapshot" as the first entry,
171
+ * which stores its timestamp inside "snapshot.timestamp" rather than
172
+ * at the root level.
173
+ */ parseSessionStart(firstLine) {
174
174
  try {
175
175
  const firstEntry = JSON.parse(firstLine);
176
176
  const rawTs = firstEntry.timestamp || firstEntry.snapshot?.timestamp;
@@ -185,24 +185,24 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
185
185
  return null;
186
186
  }
187
187
  /**
188
- * Extract meaningful text from a user message content field.
189
- *
190
- * Handles multiple formats:
191
- * - Plain string content
192
- * - Array of content blocks (extracts first text block)
193
- * - Skill slash-commands (<command-message> tags)
194
- * - Expanded skill content (extracts ARGUMENTS line)
195
- * - Filters noise messages (interruptions, tool loaded, session continued)
196
- */ extractUserMessageText(content) {
188
+ * Extract meaningful text from a user message content field.
189
+ *
190
+ * Handles multiple formats:
191
+ * - Plain string content
192
+ * - Array of content blocks (extracts first text block)
193
+ * - Skill slash-commands (<command-message> tags)
194
+ * - Expanded skill content (extracts ARGUMENTS line)
195
+ * - Filters noise messages (interruptions, tool loaded, session continued)
196
+ */ extractUserMessageText(content) {
197
197
  if (!content) {
198
198
  return undefined;
199
199
  }
200
200
  let raw;
201
- if (typeof content === 'string') {
201
+ if (typeof content === "string") {
202
202
  raw = content.trim();
203
203
  } else if (Array.isArray(content)) {
204
204
  for (const block of content){
205
- if (block.type === 'text' && block.text?.trim()) {
205
+ if (block.type === "text" && block.text?.trim()) {
206
206
  raw = block.text.trim();
207
207
  break;
208
208
  }
@@ -211,10 +211,10 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
211
211
  if (!raw) {
212
212
  return undefined;
213
213
  }
214
- if (raw.startsWith('<command-message>')) {
214
+ if (raw.startsWith("<command-message>")) {
215
215
  return this.parseCommandMessage(raw);
216
216
  }
217
- if (raw.startsWith('Base directory for this skill:')) {
217
+ if (raw.startsWith("Base directory for this skill:")) {
218
218
  const argsMatch = raw.match(/\nARGUMENTS:\s*(.+)/);
219
219
  return argsMatch?.[1]?.trim() || undefined;
220
220
  }
@@ -224,8 +224,8 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
224
224
  return raw;
225
225
  }
226
226
  /**
227
- * Parse a <command-message> string into "/command args" format.
228
- */ parseCommandMessage(raw) {
227
+ * Parse a <command-message> string into "/command args" format.
228
+ */ parseCommandMessage(raw) {
229
229
  const nameMatch = raw.match(/<command-name>([^<]+)<\/command-name>/);
230
230
  const argsMatch = raw.match(/<command-args>([^<]+)<\/command-args>/);
231
231
  const name = nameMatch?.[1]?.trim();
@@ -236,32 +236,32 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
236
236
  return args ? `${name} ${args}` : name;
237
237
  }
238
238
  /**
239
- * Extract displayable content from a message content field for conversation output.
240
- */ extractConversationContent(content, role, verbose) {
239
+ * Extract displayable content from a message content field for conversation output.
240
+ */ extractConversationContent(content, role, verbose) {
241
241
  if (!content) return undefined;
242
- if (typeof content === 'string') {
242
+ if (typeof content === "string") {
243
243
  const cleaned = stripHarnessTags(content);
244
- if (role === 'user' && isNoiseMessage(cleaned)) return undefined;
244
+ if (role === "user" && isNoiseMessage(cleaned)) return undefined;
245
245
  return cleaned || undefined;
246
246
  }
247
247
  if (!Array.isArray(content)) return undefined;
248
248
  const parts = [];
249
249
  for (const block of content){
250
- if (block.type === 'text' && block.text?.trim()) {
250
+ if (block.type === "text" && block.text?.trim()) {
251
251
  const cleaned = stripHarnessTags(block.text);
252
252
  if (!cleaned) continue;
253
- if (role === 'user' && isNoiseMessage(cleaned)) continue;
253
+ if (role === "user" && isNoiseMessage(cleaned)) continue;
254
254
  parts.push(cleaned);
255
- } else if (block.type === 'tool_use' && verbose) {
256
- const inputSummary = block.input?.file_path || block.input?.pattern || block.input?.command || '';
257
- parts.push(`[Tool: ${block.name}]${inputSummary ? ' ' + inputSummary : ''}`);
258
- } else if (block.type === 'tool_result' && verbose) {
259
- const truncated = truncateToolResult(block.content || '');
260
- const prefix = block.is_error ? '[Tool Error]' : '[Tool Result]';
255
+ } else if (block.type === "tool_use" && verbose) {
256
+ const inputSummary = block.input?.file_path || block.input?.pattern || block.input?.command || "";
257
+ parts.push(`[Tool: ${block.name}]${inputSummary ? " " + inputSummary : ""}`);
258
+ } else if (block.type === "tool_result" && verbose) {
259
+ const truncated = truncateToolResult(block.content || "");
260
+ const prefix = block.is_error ? "[Tool Error]" : "[Tool Result]";
261
261
  parts.push(`${prefix} ${truncated}`);
262
262
  }
263
263
  }
264
- return parts.length > 0 ? parts.join('\n') : undefined;
264
+ return parts.length > 0 ? parts.join("\n") : undefined;
265
265
  }
266
266
  }
267
267
  /**
@@ -269,18 +269,18 @@ import { AgentStatus } from '../../adapters/AgentAdapter.js';
269
269
  * harness-injected prompt context (system reminders, hook output, command
270
270
  * stdout), not meaningful conversation content.
271
271
  */ const HARNESS_DROP_TAGS = [
272
- 'system-reminder',
273
- 'local-command-stdout',
274
- 'local-command-stderr',
275
- 'user-prompt-submit-hook',
276
- 'command-stdout',
277
- 'command-stderr',
278
- 'bash-input',
279
- 'bash-stdout',
280
- 'bash-stderr',
281
- 'command-message'
272
+ "system-reminder",
273
+ "local-command-stdout",
274
+ "local-command-stderr",
275
+ "user-prompt-submit-hook",
276
+ "command-stdout",
277
+ "command-stderr",
278
+ "bash-input",
279
+ "bash-stdout",
280
+ "bash-stderr",
281
+ "command-message"
282
282
  ];
283
- const HARNESS_DROP_RE = new RegExp(`<(${HARNESS_DROP_TAGS.join('|')})>[\\s\\S]*?</\\1>`, 'g');
283
+ const HARNESS_DROP_RE = new RegExp(`<(${HARNESS_DROP_TAGS.join("|")})>[\\s\\S]*?</\\1>`, "g");
284
284
  const COMMAND_INVOCATION_RE = /<command-name>([^<]+)<\/command-name>(?:\s*<command-args>([\s\S]*?)<\/command-args>)?/g;
285
285
  /**
286
286
  * Remove harness-injected XML blocks from message text and collapse
@@ -289,21 +289,21 @@ const COMMAND_INVOCATION_RE = /<command-name>([^<]+)<\/command-name>(?:\s*<comma
289
289
  * Returns the cleaned, trimmed text. Returns an empty string if nothing
290
290
  * survives stripping.
291
291
  */ function stripHarnessTags(text) {
292
- let out = text.replace(HARNESS_DROP_RE, '');
292
+ let out = text.replace(HARNESS_DROP_RE, "");
293
293
  out = out.replace(COMMAND_INVOCATION_RE, (_match, rawName, rawArgs)=>{
294
294
  const name = rawName.trim();
295
295
  const args = rawArgs?.trim();
296
296
  return args ? `${name} ${args}` : name;
297
297
  });
298
- return out.replace(/\n{3,}/g, '\n\n').trim();
298
+ return out.replace(/\n{3,}/g, "\n\n").trim();
299
299
  }
300
300
  /** Check if a message is noise (not a meaningful user intent). */ function isNoiseMessage(text) {
301
- return text.startsWith('[Request interrupted') || text === 'Tool loaded.' || text.startsWith('This session is being continued');
301
+ return text.startsWith("[Request interrupted") || text === "Tool loaded." || text.startsWith("This session is being continued");
302
302
  }
303
303
  function truncateToolResult(content, maxLength = 200) {
304
- const firstLine = content.split('\n')[0] || '';
304
+ const firstLine = content.split("\n")[0] || "";
305
305
  if (firstLine.length <= maxLength) return firstLine;
306
- return firstLine.slice(0, maxLength - 3) + '...';
306
+ return firstLine.slice(0, maxLength - 3) + "...";
307
307
  }
308
308
 
309
309
  //# sourceMappingURL=ClaudeSessionParser.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/providers/claude/ClaudeSessionParser.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport type { ConversationMessage } from '../../adapters/AgentAdapter.js';\nimport { AgentStatus } from '../../adapters/AgentAdapter.js';\n\n/**\n * Content block within a Claude Code JSONL message entry.\n * Handles text, tool_use, and tool_result block types.\n */\nexport interface ContentBlock {\n type?: string;\n text?: string;\n content?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n is_error?: boolean;\n}\n\n/**\n * A single line entry in a Claude Code session JSONL file.\n *\n * Each line is an independent JSON object with a type discriminator:\n * - \"user\" / \"assistant\" / \"system\" — conversation turns\n * - \"progress\" / \"thinking\" — intermediate agent state\n * - \"last-prompt\" / \"file-history-snapshot\" — metadata (not conversation state)\n */\nexport interface SessionEntry {\n type?: string;\n timestamp?: string;\n cwd?: string;\n message?: {\n content?: string | ContentBlock[];\n };\n}\n\n/**\n * Parsed session state extracted from a JSONL file.\n * Aggregates data from all entries into a single summary.\n */\nexport interface ClaudeSession {\n sessionId: string;\n projectPath: string;\n lastCwd?: string;\n sessionStart: Date;\n lastActive: Date;\n lastEntryType?: string;\n isInterrupted: boolean;\n lastUserMessage?: string;\n /** First meaningful user prompt in the session (post noise filter) */\n firstUserMessage?: string;\n}\n\n/**\n * Top-level JSONL entry types that represent conversation/agent state.\n *\n * Only these types update `lastEntryType` for status determination. All\n * other types Claude Code emits (`attachment`, `permission-mode`,\n * `ai-title`, `queued_command`, `tools_changed`, `model_changed`,\n * `hook_progress`, …) are UI-state events that must not overwrite the\n * last conversation turn — otherwise polling between writes lands on a\n * UI-state entry and `determineStatus` falls through to UNKNOWN.\n */\nconst CONVERSATION_ENTRY_TYPES = new Set([\n 'user',\n 'assistant',\n 'system',\n 'progress',\n 'thinking',\n]);\n\n/**\n * Parses Claude Code session JSONL files into structured data.\n *\n * Session files live at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl\n * and contain one JSON object per line, each representing a conversation\n * event (user turn, assistant response, tool call, etc.).\n */\nexport class ClaudeSessionParser {\n /**\n * Parse a session JSONL file into a ClaudeSession summary.\n *\n * Iterates all lines to extract: session start time (from first entry),\n * last activity timestamp, last entry type (for status), whether the\n * session was interrupted, and the last meaningful user message.\n *\n * Returns null if the file is unreadable or empty.\n */\n readSession(filePath: string, projectPath: string): ClaudeSession | null {\n const sessionId = path.basename(filePath, '.jsonl');\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n\n const allLines = content.trim().split('\\n');\n if (allLines.length === 0) {\n return null;\n }\n\n const sessionStart = this.parseSessionStart(allLines[0]);\n\n let lastEntryType: string | undefined;\n let lastActive: Date | undefined;\n let lastCwd: string | undefined;\n let isInterrupted = false;\n let lastUserMessage: string | undefined;\n let firstUserMessage: string | undefined;\n\n for (const line of allLines) {\n try {\n const entry: SessionEntry = JSON.parse(line);\n\n if (entry.timestamp) {\n const ts = new Date(entry.timestamp);\n if (!Number.isNaN(ts.getTime())) {\n lastActive = ts;\n }\n }\n\n if (typeof entry.cwd === 'string' && entry.cwd.trim().length > 0) {\n lastCwd = entry.cwd;\n }\n\n if (entry.type && CONVERSATION_ENTRY_TYPES.has(entry.type)) {\n lastEntryType = entry.type;\n\n if (entry.type === 'user') {\n const msgContent = entry.message?.content;\n isInterrupted =\n Array.isArray(msgContent) &&\n msgContent.some(\n (c) =>\n (c.type === 'text' &&\n c.text?.includes('[Request interrupted')) ||\n (c.type === 'tool_result' &&\n c.content?.includes('[Request interrupted')),\n );\n\n const text = this.extractUserMessageText(msgContent);\n if (text) {\n lastUserMessage = text;\n if (!firstUserMessage) {\n firstUserMessage = text;\n }\n }\n } else {\n isInterrupted = false;\n }\n }\n } catch {\n continue;\n }\n }\n\n return {\n sessionId,\n projectPath: projectPath || lastCwd || '',\n lastCwd,\n sessionStart: sessionStart || lastActive || new Date(),\n lastActive: lastActive || new Date(),\n lastEntryType,\n isInterrupted,\n lastUserMessage,\n firstUserMessage,\n };\n }\n\n /**\n * Determine agent status from parsed session state.\n *\n * Status mapping:\n * - \"user\" + interrupted → WAITING (agent finished, awaiting new input)\n * - \"user\" + not interrupted → RUNNING (agent is processing)\n * - \"progress\" / \"thinking\" → RUNNING\n * - \"assistant\" → WAITING (agent responded, awaiting user)\n * - \"system\" → IDLE\n */\n determineStatus(session: ClaudeSession): AgentStatus {\n if (!session.lastEntryType) {\n return AgentStatus.UNKNOWN;\n }\n\n if (session.lastEntryType === 'user') {\n return session.isInterrupted\n ? AgentStatus.WAITING\n : AgentStatus.RUNNING;\n }\n\n if (\n session.lastEntryType === 'progress' ||\n session.lastEntryType === 'thinking'\n ) {\n return AgentStatus.RUNNING;\n }\n\n if (session.lastEntryType === 'assistant') {\n return AgentStatus.WAITING;\n }\n\n if (session.lastEntryType === 'system') {\n return AgentStatus.IDLE;\n }\n\n return AgentStatus.UNKNOWN;\n }\n\n /**\n * Read the full conversation from a session JSONL file.\n *\n * Default mode returns only text content from user/assistant/system messages.\n * Verbose mode also includes tool_use and tool_result blocks.\n */\n getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {\n const verbose = options?.verbose ?? false;\n\n let content: string;\n try {\n content = fs.readFileSync(sessionFilePath, 'utf-8');\n } catch {\n return [];\n }\n\n const lines = content.trim().split('\\n');\n const messages: ConversationMessage[] = [];\n\n for (const line of lines) {\n let entry: SessionEntry;\n try {\n entry = JSON.parse(line);\n } catch {\n continue;\n }\n\n let role: ConversationMessage['role'];\n if (entry.type === 'user') {\n role = 'user';\n } else if (entry.type === 'assistant') {\n role = 'assistant';\n } else if (entry.type === 'system') {\n role = 'system';\n } else {\n continue;\n }\n\n const text = this.extractConversationContent(entry.message?.content, role, verbose);\n if (!text) continue;\n\n messages.push({\n role,\n content: text,\n timestamp: entry.timestamp,\n });\n }\n\n return messages;\n }\n\n /**\n * Parse session start time from the first JSONL line.\n *\n * Claude Code may emit a \"file-history-snapshot\" as the first entry,\n * which stores its timestamp inside \"snapshot.timestamp\" rather than\n * at the root level.\n */\n private parseSessionStart(firstLine: string): Date | null {\n try {\n const firstEntry = JSON.parse(firstLine);\n const rawTs: string | undefined =\n firstEntry.timestamp || firstEntry.snapshot?.timestamp;\n if (rawTs) {\n const ts = new Date(rawTs);\n if (!Number.isNaN(ts.getTime())) {\n return ts;\n }\n }\n } catch {\n /* malformed first line */\n }\n return null;\n }\n\n /**\n * Extract meaningful text from a user message content field.\n *\n * Handles multiple formats:\n * - Plain string content\n * - Array of content blocks (extracts first text block)\n * - Skill slash-commands (<command-message> tags)\n * - Expanded skill content (extracts ARGUMENTS line)\n * - Filters noise messages (interruptions, tool loaded, session continued)\n */\n private extractUserMessageText(\n content: string | Array<{ type?: string; text?: string }> | undefined,\n ): string | undefined {\n if (!content) {\n return undefined;\n }\n\n let raw: string | undefined;\n\n if (typeof content === 'string') {\n raw = content.trim();\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text' && block.text?.trim()) {\n raw = block.text.trim();\n break;\n }\n }\n }\n\n if (!raw) {\n return undefined;\n }\n\n if (raw.startsWith('<command-message>')) {\n return this.parseCommandMessage(raw);\n }\n\n if (raw.startsWith('Base directory for this skill:')) {\n const argsMatch = raw.match(/\\nARGUMENTS:\\s*(.+)/);\n return argsMatch?.[1]?.trim() || undefined;\n }\n\n if (isNoiseMessage(raw)) {\n return undefined;\n }\n\n return raw;\n }\n\n /**\n * Parse a <command-message> string into \"/command args\" format.\n */\n private parseCommandMessage(raw: string): string | undefined {\n const nameMatch = raw.match(/<command-name>([^<]+)<\\/command-name>/);\n const argsMatch = raw.match(/<command-args>([^<]+)<\\/command-args>/);\n const name = nameMatch?.[1]?.trim();\n if (!name) {\n return undefined;\n }\n const args = argsMatch?.[1]?.trim();\n return args ? `${name} ${args}` : name;\n }\n\n /**\n * Extract displayable content from a message content field for conversation output.\n */\n private extractConversationContent(\n content: string | ContentBlock[] | undefined,\n role: ConversationMessage['role'],\n verbose: boolean,\n ): string | undefined {\n if (!content) return undefined;\n\n if (typeof content === 'string') {\n const cleaned = stripHarnessTags(content);\n if (role === 'user' && isNoiseMessage(cleaned)) return undefined;\n return cleaned || undefined;\n }\n\n if (!Array.isArray(content)) return undefined;\n\n const parts: string[] = [];\n\n for (const block of content) {\n if (block.type === 'text' && block.text?.trim()) {\n const cleaned = stripHarnessTags(block.text);\n if (!cleaned) continue;\n if (role === 'user' && isNoiseMessage(cleaned)) continue;\n parts.push(cleaned);\n } else if (block.type === 'tool_use' && verbose) {\n const inputSummary = block.input?.file_path || block.input?.pattern || block.input?.command || '';\n parts.push(`[Tool: ${block.name}]${inputSummary ? ' ' + inputSummary : ''}`);\n } else if (block.type === 'tool_result' && verbose) {\n const truncated = truncateToolResult(block.content || '');\n const prefix = block.is_error ? '[Tool Error]' : '[Tool Result]';\n parts.push(`${prefix} ${truncated}`);\n }\n }\n\n return parts.length > 0 ? parts.join('\\n') : undefined;\n }\n}\n\n/**\n * Tags whose entire block (including content) should be dropped — they are\n * harness-injected prompt context (system reminders, hook output, command\n * stdout), not meaningful conversation content.\n */\nconst HARNESS_DROP_TAGS = [\n 'system-reminder',\n 'local-command-stdout',\n 'local-command-stderr',\n 'user-prompt-submit-hook',\n 'command-stdout',\n 'command-stderr',\n 'bash-input',\n 'bash-stdout',\n 'bash-stderr',\n 'command-message',\n] as const;\n\nconst HARNESS_DROP_RE = new RegExp(\n `<(${HARNESS_DROP_TAGS.join('|')})>[\\\\s\\\\S]*?</\\\\1>`,\n 'g',\n);\n\nconst COMMAND_INVOCATION_RE =\n /<command-name>([^<]+)<\\/command-name>(?:\\s*<command-args>([\\s\\S]*?)<\\/command-args>)?/g;\n\n/**\n * Remove harness-injected XML blocks from message text and collapse\n * <command-name>/<command-args> pairs into a \"/name args\" shorthand.\n *\n * Returns the cleaned, trimmed text. Returns an empty string if nothing\n * survives stripping.\n */\nfunction stripHarnessTags(text: string): string {\n let out = text.replace(HARNESS_DROP_RE, '');\n\n out = out.replace(COMMAND_INVOCATION_RE, (_match, rawName: string, rawArgs?: string) => {\n const name = rawName.trim();\n const args = rawArgs?.trim();\n return args ? `${name} ${args}` : name;\n });\n\n return out.replace(/\\n{3,}/g, '\\n\\n').trim();\n}\n\n/** Check if a message is noise (not a meaningful user intent). */\nfunction isNoiseMessage(text: string): boolean {\n return (\n text.startsWith('[Request interrupted') ||\n text === 'Tool loaded.' ||\n text.startsWith('This session is being continued')\n );\n}\n\nfunction truncateToolResult(content: string, maxLength = 200): string {\n const firstLine = content.split('\\n')[0] || '';\n if (firstLine.length <= maxLength) return firstLine;\n return firstLine.slice(0, maxLength - 3) + '...';\n}\n"],"names":["fs","path","AgentStatus","CONVERSATION_ENTRY_TYPES","Set","ClaudeSessionParser","readSession","filePath","projectPath","sessionId","basename","content","readFileSync","allLines","trim","split","length","sessionStart","parseSessionStart","lastEntryType","lastActive","lastCwd","isInterrupted","lastUserMessage","firstUserMessage","line","entry","JSON","parse","timestamp","ts","Date","Number","isNaN","getTime","cwd","type","has","msgContent","message","Array","isArray","some","c","text","includes","extractUserMessageText","determineStatus","session","UNKNOWN","WAITING","RUNNING","IDLE","getConversation","sessionFilePath","options","verbose","lines","messages","role","extractConversationContent","push","firstLine","firstEntry","rawTs","snapshot","undefined","raw","block","startsWith","parseCommandMessage","argsMatch","match","isNoiseMessage","nameMatch","name","args","cleaned","stripHarnessTags","parts","inputSummary","input","file_path","pattern","command","truncated","truncateToolResult","prefix","is_error","join","HARNESS_DROP_TAGS","HARNESS_DROP_RE","RegExp","COMMAND_INVOCATION_RE","out","replace","_match","rawName","rawArgs","maxLength","slice"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/providers/claude/ClaudeSessionParser.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport type { ConversationMessage } from \"../../adapters/AgentAdapter.js\";\nimport { AgentStatus } from \"../../adapters/AgentAdapter.js\";\n\n/**\n * Content block within a Claude Code JSONL message entry.\n * Handles text, tool_use, and tool_result block types.\n */\nexport interface ContentBlock {\n type?: string;\n text?: string;\n content?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n is_error?: boolean;\n}\n\n/**\n * A single line entry in a Claude Code session JSONL file.\n *\n * Each line is an independent JSON object with a type discriminator:\n * - \"user\" / \"assistant\" / \"system\" — conversation turns\n * - \"progress\" / \"thinking\" — intermediate agent state\n * - \"last-prompt\" / \"file-history-snapshot\" — metadata (not conversation state)\n */\nexport interface SessionEntry {\n type?: string;\n timestamp?: string;\n cwd?: string;\n message?: {\n content?: string | ContentBlock[];\n };\n}\n\n/**\n * Parsed session state extracted from a JSONL file.\n * Aggregates data from all entries into a single summary.\n */\nexport interface ClaudeSession {\n sessionId: string;\n projectPath: string;\n lastCwd?: string;\n sessionStart: Date;\n lastActive: Date;\n lastEntryType?: string;\n isInterrupted: boolean;\n lastUserMessage?: string;\n /** First meaningful user prompt in the session (post noise filter) */\n firstUserMessage?: string;\n}\n\n/**\n * Top-level JSONL entry types that represent conversation/agent state.\n *\n * Only these types update `lastEntryType` for status determination. All\n * other types Claude Code emits (`attachment`, `permission-mode`,\n * `ai-title`, `queued_command`, `tools_changed`, `model_changed`,\n * `hook_progress`, …) are UI-state events that must not overwrite the\n * last conversation turn — otherwise polling between writes lands on a\n * UI-state entry and `determineStatus` falls through to UNKNOWN.\n */\nconst CONVERSATION_ENTRY_TYPES = new Set([\"user\", \"assistant\", \"system\", \"progress\", \"thinking\"]);\n\n/**\n * Parses Claude Code session JSONL files into structured data.\n *\n * Session files live at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl\n * and contain one JSON object per line, each representing a conversation\n * event (user turn, assistant response, tool call, etc.).\n */\nexport class ClaudeSessionParser {\n /**\n * Parse a session JSONL file into a ClaudeSession summary.\n *\n * Iterates all lines to extract: session start time (from first entry),\n * last activity timestamp, last entry type (for status), whether the\n * session was interrupted, and the last meaningful user message.\n *\n * Returns null if the file is unreadable or empty.\n */\n readSession(filePath: string, projectPath: string): ClaudeSession | null {\n const sessionId = path.basename(filePath, \".jsonl\");\n\n let content: string;\n try {\n content = fs.readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n\n const allLines = content.trim().split(\"\\n\");\n if (allLines.length === 0) {\n return null;\n }\n\n const sessionStart = this.parseSessionStart(allLines[0]);\n\n let lastEntryType: string | undefined;\n let lastActive: Date | undefined;\n let lastCwd: string | undefined;\n let isInterrupted = false;\n let lastUserMessage: string | undefined;\n let firstUserMessage: string | undefined;\n\n for (const line of allLines) {\n try {\n const entry: SessionEntry = JSON.parse(line);\n\n if (entry.timestamp) {\n const ts = new Date(entry.timestamp);\n if (!Number.isNaN(ts.getTime())) {\n lastActive = ts;\n }\n }\n\n if (typeof entry.cwd === \"string\" && entry.cwd.trim().length > 0) {\n lastCwd = entry.cwd;\n }\n\n if (entry.type && CONVERSATION_ENTRY_TYPES.has(entry.type)) {\n lastEntryType = entry.type;\n\n if (entry.type === \"user\") {\n const msgContent = entry.message?.content;\n isInterrupted =\n Array.isArray(msgContent) &&\n msgContent.some(\n (c) =>\n (c.type === \"text\" && c.text?.includes(\"[Request interrupted\")) ||\n (c.type === \"tool_result\" && c.content?.includes(\"[Request interrupted\")),\n );\n\n const text = this.extractUserMessageText(msgContent);\n if (text) {\n lastUserMessage = text;\n if (!firstUserMessage) {\n firstUserMessage = text;\n }\n }\n } else {\n isInterrupted = false;\n }\n }\n } catch {\n continue;\n }\n }\n\n return {\n sessionId,\n projectPath: projectPath || lastCwd || \"\",\n lastCwd,\n sessionStart: sessionStart || lastActive || new Date(),\n lastActive: lastActive || new Date(),\n lastEntryType,\n isInterrupted,\n lastUserMessage,\n firstUserMessage,\n };\n }\n\n /**\n * Determine agent status from parsed session state.\n *\n * Status mapping:\n * - \"user\" + interrupted → WAITING (agent finished, awaiting new input)\n * - \"user\" + not interrupted → RUNNING (agent is processing)\n * - \"progress\" / \"thinking\" → RUNNING\n * - \"assistant\" → WAITING (agent responded, awaiting user)\n * - \"system\" → IDLE\n */\n determineStatus(session: ClaudeSession): AgentStatus {\n if (!session.lastEntryType) {\n return AgentStatus.UNKNOWN;\n }\n\n if (session.lastEntryType === \"user\") {\n return session.isInterrupted ? AgentStatus.WAITING : AgentStatus.RUNNING;\n }\n\n if (session.lastEntryType === \"progress\" || session.lastEntryType === \"thinking\") {\n return AgentStatus.RUNNING;\n }\n\n if (session.lastEntryType === \"assistant\") {\n return AgentStatus.WAITING;\n }\n\n if (session.lastEntryType === \"system\") {\n return AgentStatus.IDLE;\n }\n\n return AgentStatus.UNKNOWN;\n }\n\n /**\n * Read the full conversation from a session JSONL file.\n *\n * Default mode returns only text content from user/assistant/system messages.\n * Verbose mode also includes tool_use and tool_result blocks.\n */\n getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {\n const verbose = options?.verbose ?? false;\n\n let content: string;\n try {\n content = fs.readFileSync(sessionFilePath, \"utf-8\");\n } catch {\n return [];\n }\n\n const lines = content.trim().split(\"\\n\");\n const messages: ConversationMessage[] = [];\n\n for (const line of lines) {\n let entry: SessionEntry;\n try {\n entry = JSON.parse(line);\n } catch {\n continue;\n }\n\n let role: ConversationMessage[\"role\"];\n if (entry.type === \"user\") {\n role = \"user\";\n } else if (entry.type === \"assistant\") {\n role = \"assistant\";\n } else if (entry.type === \"system\") {\n role = \"system\";\n } else {\n continue;\n }\n\n const text = this.extractConversationContent(entry.message?.content, role, verbose);\n if (!text) continue;\n\n messages.push({\n role,\n content: text,\n timestamp: entry.timestamp,\n });\n }\n\n return messages;\n }\n\n /**\n * Parse session start time from the first JSONL line.\n *\n * Claude Code may emit a \"file-history-snapshot\" as the first entry,\n * which stores its timestamp inside \"snapshot.timestamp\" rather than\n * at the root level.\n */\n private parseSessionStart(firstLine: string): Date | null {\n try {\n const firstEntry = JSON.parse(firstLine);\n const rawTs: string | undefined = firstEntry.timestamp || firstEntry.snapshot?.timestamp;\n if (rawTs) {\n const ts = new Date(rawTs);\n if (!Number.isNaN(ts.getTime())) {\n return ts;\n }\n }\n } catch {\n /* malformed first line */\n }\n return null;\n }\n\n /**\n * Extract meaningful text from a user message content field.\n *\n * Handles multiple formats:\n * - Plain string content\n * - Array of content blocks (extracts first text block)\n * - Skill slash-commands (<command-message> tags)\n * - Expanded skill content (extracts ARGUMENTS line)\n * - Filters noise messages (interruptions, tool loaded, session continued)\n */\n private extractUserMessageText(\n content: string | Array<{ type?: string; text?: string }> | undefined,\n ): string | undefined {\n if (!content) {\n return undefined;\n }\n\n let raw: string | undefined;\n\n if (typeof content === \"string\") {\n raw = content.trim();\n } else if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === \"text\" && block.text?.trim()) {\n raw = block.text.trim();\n break;\n }\n }\n }\n\n if (!raw) {\n return undefined;\n }\n\n if (raw.startsWith(\"<command-message>\")) {\n return this.parseCommandMessage(raw);\n }\n\n if (raw.startsWith(\"Base directory for this skill:\")) {\n const argsMatch = raw.match(/\\nARGUMENTS:\\s*(.+)/);\n return argsMatch?.[1]?.trim() || undefined;\n }\n\n if (isNoiseMessage(raw)) {\n return undefined;\n }\n\n return raw;\n }\n\n /**\n * Parse a <command-message> string into \"/command args\" format.\n */\n private parseCommandMessage(raw: string): string | undefined {\n const nameMatch = raw.match(/<command-name>([^<]+)<\\/command-name>/);\n const argsMatch = raw.match(/<command-args>([^<]+)<\\/command-args>/);\n const name = nameMatch?.[1]?.trim();\n if (!name) {\n return undefined;\n }\n const args = argsMatch?.[1]?.trim();\n return args ? `${name} ${args}` : name;\n }\n\n /**\n * Extract displayable content from a message content field for conversation output.\n */\n private extractConversationContent(\n content: string | ContentBlock[] | undefined,\n role: ConversationMessage[\"role\"],\n verbose: boolean,\n ): string | undefined {\n if (!content) return undefined;\n\n if (typeof content === \"string\") {\n const cleaned = stripHarnessTags(content);\n if (role === \"user\" && isNoiseMessage(cleaned)) return undefined;\n return cleaned || undefined;\n }\n\n if (!Array.isArray(content)) return undefined;\n\n const parts: string[] = [];\n\n for (const block of content) {\n if (block.type === \"text\" && block.text?.trim()) {\n const cleaned = stripHarnessTags(block.text);\n if (!cleaned) continue;\n if (role === \"user\" && isNoiseMessage(cleaned)) continue;\n parts.push(cleaned);\n } else if (block.type === \"tool_use\" && verbose) {\n const inputSummary =\n block.input?.file_path || block.input?.pattern || block.input?.command || \"\";\n parts.push(`[Tool: ${block.name}]${inputSummary ? \" \" + inputSummary : \"\"}`);\n } else if (block.type === \"tool_result\" && verbose) {\n const truncated = truncateToolResult(block.content || \"\");\n const prefix = block.is_error ? \"[Tool Error]\" : \"[Tool Result]\";\n parts.push(`${prefix} ${truncated}`);\n }\n }\n\n return parts.length > 0 ? parts.join(\"\\n\") : undefined;\n }\n}\n\n/**\n * Tags whose entire block (including content) should be dropped — they are\n * harness-injected prompt context (system reminders, hook output, command\n * stdout), not meaningful conversation content.\n */\nconst HARNESS_DROP_TAGS = [\n \"system-reminder\",\n \"local-command-stdout\",\n \"local-command-stderr\",\n \"user-prompt-submit-hook\",\n \"command-stdout\",\n \"command-stderr\",\n \"bash-input\",\n \"bash-stdout\",\n \"bash-stderr\",\n \"command-message\",\n] as const;\n\nconst HARNESS_DROP_RE = new RegExp(`<(${HARNESS_DROP_TAGS.join(\"|\")})>[\\\\s\\\\S]*?</\\\\1>`, \"g\");\n\nconst COMMAND_INVOCATION_RE =\n /<command-name>([^<]+)<\\/command-name>(?:\\s*<command-args>([\\s\\S]*?)<\\/command-args>)?/g;\n\n/**\n * Remove harness-injected XML blocks from message text and collapse\n * <command-name>/<command-args> pairs into a \"/name args\" shorthand.\n *\n * Returns the cleaned, trimmed text. Returns an empty string if nothing\n * survives stripping.\n */\nfunction stripHarnessTags(text: string): string {\n let out = text.replace(HARNESS_DROP_RE, \"\");\n\n out = out.replace(COMMAND_INVOCATION_RE, (_match, rawName: string, rawArgs?: string) => {\n const name = rawName.trim();\n const args = rawArgs?.trim();\n return args ? `${name} ${args}` : name;\n });\n\n return out.replace(/\\n{3,}/g, \"\\n\\n\").trim();\n}\n\n/** Check if a message is noise (not a meaningful user intent). */\nfunction isNoiseMessage(text: string): boolean {\n return (\n text.startsWith(\"[Request interrupted\") ||\n text === \"Tool loaded.\" ||\n text.startsWith(\"This session is being continued\")\n );\n}\n\nfunction truncateToolResult(content: string, maxLength = 200): string {\n const firstLine = content.split(\"\\n\")[0] || \"\";\n if (firstLine.length <= maxLength) return firstLine;\n return firstLine.slice(0, maxLength - 3) + \"...\";\n}\n"],"names":["fs","path","AgentStatus","CONVERSATION_ENTRY_TYPES","Set","ClaudeSessionParser","readSession","filePath","projectPath","sessionId","basename","content","readFileSync","allLines","trim","split","length","sessionStart","parseSessionStart","lastEntryType","lastActive","lastCwd","isInterrupted","lastUserMessage","firstUserMessage","line","entry","JSON","parse","timestamp","ts","Date","Number","isNaN","getTime","cwd","type","has","msgContent","message","Array","isArray","some","c","text","includes","extractUserMessageText","determineStatus","session","UNKNOWN","WAITING","RUNNING","IDLE","getConversation","sessionFilePath","options","verbose","lines","messages","role","extractConversationContent","push","firstLine","firstEntry","rawTs","snapshot","undefined","raw","block","startsWith","parseCommandMessage","argsMatch","match","isNoiseMessage","nameMatch","name","args","cleaned","stripHarnessTags","parts","inputSummary","input","file_path","pattern","command","truncated","truncateToolResult","prefix","is_error","join","HARNESS_DROP_TAGS","HARNESS_DROP_RE","RegExp","COMMAND_INVOCATION_RE","out","replace","_match","rawName","rawArgs","maxLength","slice"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ClaudeCliProbe.d.ts","sourceRoot":"","sources":["../../../../src/providers/claude/durable/ClaudeCliProbe.ts"],"names":[],"mappings":"AAKA,KAAK,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrD,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAKlE,MAAM,WAAW,qBAAqB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;CACf;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;gBAEhB,OAAO,GAAE,qBAA0B;IAQzC,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAuBrE"}
1
+ {"version":3,"file":"ClaudeCliProbe.d.ts","sourceRoot":"","sources":["../../../../src/providers/claude/durable/ClaudeCliProbe.ts"],"names":[],"mappings":"AAKA,KAAK,UAAU,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrD,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAKlE,MAAM,WAAW,qBAAqB;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,CAAC;CACb;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;gBAEhB,OAAO,GAAE,qBAA0B;IAazC,QAAQ,IAAI,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAuBnE"}