@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 +0,0 @@
1
- {"version":3,"sources":["../../src/adapters/PiAdapter.ts"],"sourcesContent":["/**\n * Pi Adapter\n *\n * Detects running Pi agents by:\n * 1. Finding running Pi processes\n * 2. Matching exact PID-to-session metadata from ~/.pi/agent/sessions.json\n * 3. Falling back to shared process/session matching over Pi JSONL session files\n * 4. Parsing Pi JSONL entries defensively for summary and conversation output\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type {\n AgentAdapter,\n AgentInfo,\n ProcessInfo,\n ConversationMessage,\n SessionSummary,\n ListSessionsOptions,\n AgentDetectionContext,\n} from './AgentAdapter.js';\nimport { AgentStatus } from './AgentAdapter.js';\nimport { captureProcessSnapshot, executableBasename, filterByProcessNames } from '../utils/process.js';\nimport { isDirectory, safeReadFile, safeReaddir, safeStat } from '../utils/session.js';\nimport type { SessionFile } from '../utils/session.js';\nimport { matchProcessesToSessions, generateAgentName } from '../utils/matching.js';\nimport { AgentRegistry } from '../utils/AgentRegistry.js';\n\ninterface PiSession {\n sessionId: string;\n projectPath: string;\n summary: string;\n sessionStart: Date;\n lastActive: Date;\n lastRole?: ConversationMessage['role'];\n}\n\ninterface PiLine {\n timestamp?: string;\n role?: string;\n type?: string;\n content?: unknown;\n text?: unknown;\n message?: unknown;\n sessionId?: string;\n session_id?: string;\n id?: string;\n cwd?: string;\n projectPath?: string;\n project_path?: string;\n payload?: Record<string, unknown>;\n data?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\ntype PiRecord = Record<string, unknown>;\n\ninterface TrackerMatch {\n process: ProcessInfo;\n filePath: string;\n}\n\ninterface TrackerAgentResult {\n agents: AgentInfo[];\n fallback: ProcessInfo[];\n}\n\nexport class PiAdapter implements AgentAdapter {\n readonly type = 'pi' as const;\n readonly processNames = ['pi', 'node'] as const;\n\n private static readonly IDLE_THRESHOLD_MINUTES = 5;\n\n private piAgentDir: string;\n private piSessionsDir: string;\n private trackerPath: string;\n private registry: AgentRegistry;\n\n constructor(registry: AgentRegistry = AgentRegistry.default()) {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n this.piAgentDir = path.join(homeDir, '.pi', 'agent');\n this.piSessionsDir = path.join(this.piAgentDir, 'sessions');\n this.trackerPath = path.join(this.piAgentDir, 'sessions.json');\n this.registry = registry;\n }\n\n canHandle(processInfo: ProcessInfo): boolean {\n return this.isPiExecutable(processInfo.command);\n }\n\n async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {\n const snapshot = context?.processes ?? await captureProcessSnapshot(this.processNames);\n const relevant = filterByProcessNames(snapshot, this.processNames);\n const processes = this.listPiProcesses(relevant);\n if (processes.length === 0) return [];\n\n const { cachedAgents, remaining } = this.tryRegistryCache(processes);\n if (remaining.length === 0) return cachedAgents;\n\n const trackerResult = this.mapTrackerMatches(remaining);\n const fallbackAgents = this.mapFallbackMatches(trackerResult.fallback);\n\n return [\n ...cachedAgents,\n ...trackerResult.agents,\n ...fallbackAgents,\n ];\n }\n\n private mapTrackerMatches(processes: ProcessInfo[]): TrackerAgentResult {\n const { matches: trackerMatches, fallback } = this.matchFromTracker(processes);\n const agents: AgentInfo[] = [];\n\n for (const match of trackerMatches) {\n const session = this.parseSession(match.filePath, match.process.cwd);\n if (session) {\n agents.push(this.mapSessionToAgent(session, match.process, match.filePath));\n } else {\n fallback.push(match.process);\n }\n }\n\n return { agents, fallback };\n }\n\n private mapFallbackMatches(processes: ProcessInfo[]): AgentInfo[] {\n if (processes.length === 0) return [];\n\n const sessions = this.discoverSessions(processes);\n if (sessions.length === 0) {\n return processes.map((p) => this.mapProcessOnlyAgent(p));\n }\n\n const matches = matchProcessesToSessions(processes, sessions);\n const matchedPids = new Set(matches.map((m) => m.process.pid));\n const agents: AgentInfo[] = [];\n\n for (const match of matches) {\n const session = this.parseSession(match.session.filePath, match.process.cwd);\n if (session) {\n agents.push(this.mapSessionToAgent(session, match.process, match.session.filePath));\n } else {\n matchedPids.delete(match.process.pid);\n }\n }\n\n for (const proc of processes) {\n if (!matchedPids.has(proc.pid)) {\n agents.push(this.mapProcessOnlyAgent(proc));\n }\n }\n\n return agents;\n }\n\n private listPiProcesses(snapshot: readonly ProcessInfo[]): ProcessInfo[] {\n const byPid = new Map<number, ProcessInfo>();\n for (const proc of snapshot) {\n if (this.canHandle(proc)) byPid.set(proc.pid, proc);\n }\n return Array.from(byPid.values());\n }\n\n private tryRegistryCache(processes: ProcessInfo[]): {\n cachedAgents: AgentInfo[];\n remaining: ProcessInfo[];\n } {\n const cachedAgents: AgentInfo[] = [];\n const remaining: ProcessInfo[] = [];\n const byPid = new Map(this.registry.list().map((e) => [e.pid, e]));\n\n for (const proc of processes) {\n const entry = byPid.get(proc.pid);\n if (\n !entry ||\n entry.type !== this.type ||\n !entry.sessionFilePath ||\n !fs.existsSync(entry.sessionFilePath)\n ) {\n remaining.push(proc);\n continue;\n }\n\n const session = this.parseSession(entry.sessionFilePath, proc.cwd);\n if (!session) {\n remaining.push(proc);\n continue;\n }\n\n cachedAgents.push(this.mapSessionToAgent(session, proc, entry.sessionFilePath));\n }\n\n return { cachedAgents, remaining };\n }\n\n private matchFromTracker(processes: ProcessInfo[]): {\n matches: TrackerMatch[];\n fallback: ProcessInfo[];\n } {\n const tracker = this.readTracker();\n if (tracker.size === 0) return { matches: [], fallback: processes };\n\n const matches: TrackerMatch[] = [];\n const fallback: ProcessInfo[] = [];\n\n for (const proc of processes) {\n const filePath = tracker.get(proc.pid);\n if (!filePath || !this.isTrustedSessionPath(filePath) || !fs.existsSync(filePath)) {\n fallback.push(proc);\n continue;\n }\n matches.push({ process: proc, filePath });\n }\n\n return { matches, fallback };\n }\n\n private readTracker(): Map<number, string> {\n const content = safeReadFile(this.trackerPath);\n if (content === undefined) return new Map();\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(content);\n } catch {\n return new Map();\n }\n\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return new Map();\n\n const map = new Map<number, string>();\n for (const [key, value] of Object.entries(parsed)) {\n const keyPid = this.toPid(key);\n if (keyPid !== null && typeof value === 'string' && value) {\n map.set(keyPid, value);\n }\n }\n return map;\n }\n\n private toPid(value: unknown): number | null {\n if (typeof value === 'number' && Number.isInteger(value) && value > 0) return value;\n if (typeof value !== 'string' || !/^\\d+$/.test(value)) return null;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;\n }\n\n private isTrustedSessionPath(filePath: string): boolean {\n const resolvedRoot = path.resolve(this.piSessionsDir);\n const resolvedPath = path.resolve(filePath);\n return resolvedPath === resolvedRoot || resolvedPath.startsWith(`${resolvedRoot}${path.sep}`);\n }\n\n private discoverSessions(processes: ProcessInfo[] = []): SessionFile[] {\n if (!isDirectory(this.piSessionsDir)) return [];\n\n const cwdByProjectDir = this.buildProjectDirCwdMap(processes);\n const sessions: SessionFile[] = [];\n for (const filePath of this.collectJsonlFiles(this.piSessionsDir)) {\n const stat = safeStat(filePath);\n if (!stat) continue;\n\n const session = this.parseSession(filePath);\n const sessionId = session?.sessionId || this.sessionIdFromFile(filePath);\n const projectDir = path.dirname(filePath);\n sessions.push({\n sessionId,\n filePath,\n projectDir,\n birthtimeMs: stat.birthtimeMs || stat.mtimeMs,\n resolvedCwd: session?.projectPath || cwdByProjectDir.get(path.basename(projectDir)) || '',\n });\n }\n\n return sessions;\n }\n\n private buildProjectDirCwdMap(processes: ProcessInfo[]): Map<string, string> {\n const map = new Map<string, string>();\n for (const proc of processes) {\n if (!proc.cwd) continue;\n map.set(this.encodeProjectDir(proc.cwd), proc.cwd);\n }\n return map;\n }\n\n private collectJsonlFiles(dir: string): string[] {\n const files: string[] = [];\n for (const entry of safeReaddir(dir)) {\n const fullPath = path.join(dir, entry);\n const stat = safeStat(fullPath);\n if (!stat) continue;\n if (stat.isDirectory()) {\n files.push(...this.collectJsonlFiles(fullPath));\n } else if (stat.isFile() && entry.endsWith('.jsonl')) {\n files.push(fullPath);\n }\n }\n return files;\n }\n\n private parseSession(filePath: string, fallbackCwd = ''): PiSession | null {\n const entries = this.readJsonl(filePath);\n if (entries.length === 0) return null;\n return this.sessionFromEntries(entries, filePath, fallbackCwd);\n }\n\n private sessionFromEntries(entries: PiLine[], filePath: string, fallbackCwd = ''): PiSession {\n const stat = safeStat(filePath);\n const timestamps = entries\n .map((entry) => this.parseTimestamp(this.entryTimestamp(entry)))\n .filter((value): value is Date => value !== null);\n\n const sessionStart = timestamps[0] ?? stat?.birthtime ?? stat?.mtime ?? new Date();\n const lastActive = timestamps[timestamps.length - 1] ?? stat?.mtime ?? sessionStart;\n const messages = this.entriesToMessages(entries, true);\n const lastUser = [...messages].reverse().find((msg) => msg.role === 'user');\n const lastMessage = messages[messages.length - 1];\n\n return {\n sessionId: this.sessionIdFromEntries(entries) || this.sessionIdFromFile(filePath),\n projectPath: this.cwdFromEntries(entries) || fallbackCwd,\n summary: lastUser?.content ? this.truncate(lastUser.content, 120) : 'Pi session active',\n sessionStart,\n lastActive,\n lastRole: lastMessage?.role,\n };\n }\n\n private readJsonl(filePath: string): PiLine[] {\n const content = safeReadFile(filePath);\n if (content === undefined) return [];\n\n const entries: PiLine[] = [];\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const parsed = JSON.parse(trimmed);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n entries.push(parsed as PiLine);\n }\n } catch {\n continue;\n }\n }\n return entries;\n }\n\n private entryToMessage(entry: PiLine, includeSystem: boolean): ConversationMessage | null {\n const role = this.entryRole(entry);\n if (!role) return null;\n if (role === 'system' && !includeSystem) return null;\n\n const content = this.entryContent(entry).trim();\n if (!content) return null;\n\n return {\n role,\n content,\n timestamp: this.entryTimestamp(entry),\n };\n }\n\n private entryRole(entry: PiLine): ConversationMessage['role'] | null {\n const message = this.messageRecord(entry);\n const raw = this.firstString(\n entry.role,\n message?.role,\n this.roleLikeType(entry.type),\n entry.payload?.role,\n entry.payload?.type,\n entry.data?.role,\n entry.data?.type,\n );\n if (!raw) return null;\n const normalized = raw.toLowerCase();\n if (normalized === 'user' || normalized === 'human') return 'user';\n if (normalized === 'assistant' || normalized === 'ai' || normalized === 'pi') return 'assistant';\n if (normalized === 'system') return 'system';\n return null;\n }\n\n private entryContent(entry: PiLine): string {\n const message = this.messageRecord(entry);\n const candidates = [\n entry.content,\n entry.text,\n message?.content,\n message?.text,\n message?.message,\n entry.message,\n entry.payload?.content,\n entry.payload?.text,\n entry.payload?.message,\n entry.data?.content,\n entry.data?.text,\n entry.data?.message,\n ];\n\n for (const candidate of candidates) {\n const text = this.contentToString(candidate);\n if (text) return text;\n }\n return '';\n }\n\n private contentToString(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) {\n return value.map((item) => this.contentToString(item)).filter(Boolean).join('');\n }\n if (!value || typeof value !== 'object') return '';\n\n const record = value as Record<string, unknown>;\n return this.contentToString(record.content ?? record.text ?? record.value);\n }\n\n private asRecord(value: unknown): PiRecord | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n return value as PiRecord;\n }\n\n private messageRecord(entry: PiLine): PiRecord | null {\n return this.asRecord(entry.message);\n }\n\n private roleLikeType(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.toLowerCase();\n if (['user', 'human', 'assistant', 'ai', 'pi', 'system'].includes(normalized)) {\n return value;\n }\n return undefined;\n }\n\n private entryTimestamp(entry: PiLine): string | undefined {\n return this.firstString(\n entry.timestamp,\n entry.payload?.timestamp,\n entry.data?.timestamp,\n entry.createdAt,\n entry.created_at,\n );\n }\n\n private sessionIdFromEntries(entries: PiLine[]): string | null {\n for (const entry of entries) {\n const sessionId = this.firstString(\n entry.sessionId,\n entry.session_id,\n entry.id,\n entry.payload?.sessionId,\n entry.payload?.session_id,\n entry.payload?.id,\n entry.data?.sessionId,\n entry.data?.session_id,\n entry.data?.id,\n );\n if (sessionId) return sessionId;\n }\n return null;\n }\n\n private cwdFromEntries(entries: PiLine[]): string {\n for (const entry of entries) {\n const cwd = this.firstString(\n entry.cwd,\n entry.projectPath,\n entry.project_path,\n entry.payload?.cwd,\n entry.payload?.projectPath,\n entry.payload?.project_path,\n entry.data?.cwd,\n entry.data?.projectPath,\n entry.data?.project_path,\n );\n if (cwd) return cwd;\n }\n return '';\n }\n\n private sessionIdFromFile(filePath: string): string {\n const base = path.basename(filePath, '.jsonl');\n const underscore = base.lastIndexOf('_');\n return underscore >= 0 ? base.slice(underscore + 1) : base;\n }\n\n private encodeProjectDir(cwd: string): string {\n const normalized = path.resolve(cwd);\n return `--${normalized.replace(/^\\//, '').replace(/\\//g, '-')}--`;\n }\n\n private firstString(...values: unknown[]): string | undefined {\n for (const value of values) {\n if (typeof value === 'string' && value) return value;\n }\n return undefined;\n }\n\n private parseTimestamp(value?: string): Date | null {\n if (!value) return null;\n const timestamp = new Date(value);\n return Number.isNaN(timestamp.getTime()) ? null : timestamp;\n }\n\n private mapSessionToAgent(session: PiSession, processInfo: ProcessInfo, filePath: string): AgentInfo {\n const projectPath = session.projectPath || processInfo.cwd || '';\n return {\n name: generateAgentName(projectPath, processInfo.pid),\n type: this.type,\n status: this.determineStatus(session),\n summary: session.summary || 'Pi session active',\n pid: processInfo.pid,\n projectPath,\n sessionId: session.sessionId,\n lastActive: session.lastActive,\n sessionFilePath: filePath,\n };\n }\n\n private mapProcessOnlyAgent(processInfo: ProcessInfo): AgentInfo {\n return {\n name: generateAgentName(processInfo.cwd || '', processInfo.pid),\n type: this.type,\n status: AgentStatus.RUNNING,\n summary: 'Pi process running',\n pid: processInfo.pid,\n projectPath: processInfo.cwd || '',\n sessionId: `pid-${processInfo.pid}`,\n lastActive: new Date(),\n };\n }\n\n private determineStatus(session: PiSession): AgentStatus {\n const diffMs = Date.now() - session.lastActive.getTime();\n const diffMinutes = diffMs / 60000;\n\n if (diffMinutes > PiAdapter.IDLE_THRESHOLD_MINUTES) return AgentStatus.IDLE;\n if (session.lastRole === 'assistant') return AgentStatus.WAITING;\n return AgentStatus.RUNNING;\n }\n\n private truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength - 3)}...`;\n }\n\n private isPiExecutable(command: string): boolean {\n for (const token of command.trim().split(/\\s+/)) {\n const base = executableBasename(token);\n if (base === 'pi' || base === 'pi.exe' || base === 'pi.js') return true;\n }\n return false;\n }\n\n getConversation(sessionFilePath: string, options?: { verbose?: boolean }): ConversationMessage[] {\n const includeSystem = options?.verbose ?? false;\n return this.entriesToMessages(this.readJsonl(sessionFilePath), includeSystem);\n }\n\n private entriesToMessages(entries: PiLine[], includeSystem: boolean): ConversationMessage[] {\n return entries\n .map((entry) => this.entryToMessage(entry, includeSystem))\n .filter((msg): msg is ConversationMessage => msg !== null);\n }\n\n async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {\n if (!isDirectory(this.piSessionsDir)) return [];\n\n const summaries: SessionSummary[] = [];\n for (const filePath of this.collectJsonlFiles(this.piSessionsDir)) {\n const summary = this.fileToSessionSummary(filePath);\n if (!summary) continue;\n if (opts?.cwd !== undefined && summary.cwd !== opts.cwd) continue;\n summaries.push(summary);\n }\n return summaries;\n }\n\n private fileToSessionSummary(filePath: string): SessionSummary | null {\n const entries = this.readJsonl(filePath);\n if (entries.length === 0) return null;\n\n const session = this.sessionFromEntries(entries, filePath);\n const firstUserMessage = this.entriesToMessages(entries, false)\n .find((msg) => msg.role === 'user')?.content ?? '';\n return {\n type: this.type,\n sessionId: session.sessionId,\n cwd: session.projectPath,\n firstUserMessage,\n lastActive: session.lastActive,\n startedAt: session.sessionStart,\n sessionFilePath: filePath,\n };\n }\n}\n"],"names":["fs","path","AgentStatus","captureProcessSnapshot","executableBasename","filterByProcessNames","isDirectory","safeReadFile","safeReaddir","safeStat","matchProcessesToSessions","generateAgentName","AgentRegistry","PiAdapter","type","processNames","IDLE_THRESHOLD_MINUTES","piAgentDir","piSessionsDir","trackerPath","registry","default","homeDir","process","env","HOME","USERPROFILE","join","canHandle","processInfo","isPiExecutable","command","detectAgents","context","snapshot","processes","relevant","listPiProcesses","length","cachedAgents","remaining","tryRegistryCache","trackerResult","mapTrackerMatches","fallbackAgents","mapFallbackMatches","fallback","agents","matches","trackerMatches","matchFromTracker","match","session","parseSession","filePath","cwd","push","mapSessionToAgent","sessions","discoverSessions","map","p","mapProcessOnlyAgent","matchedPids","Set","m","pid","delete","proc","has","byPid","Map","set","Array","from","values","list","e","entry","get","sessionFilePath","existsSync","tracker","readTracker","size","isTrustedSessionPath","content","undefined","parsed","JSON","parse","isArray","key","value","Object","entries","keyPid","toPid","Number","isInteger","test","isSafeInteger","resolvedRoot","resolve","resolvedPath","startsWith","sep","cwdByProjectDir","buildProjectDirCwdMap","collectJsonlFiles","stat","sessionId","sessionIdFromFile","projectDir","dirname","birthtimeMs","mtimeMs","resolvedCwd","projectPath","basename","encodeProjectDir","dir","files","fullPath","isFile","endsWith","fallbackCwd","readJsonl","sessionFromEntries","timestamps","parseTimestamp","entryTimestamp","filter","sessionStart","birthtime","mtime","Date","lastActive","messages","entriesToMessages","lastUser","reverse","find","msg","role","lastMessage","sessionIdFromEntries","cwdFromEntries","summary","truncate","lastRole","line","split","trimmed","trim","entryToMessage","includeSystem","entryRole","entryContent","timestamp","message","messageRecord","raw","firstString","roleLikeType","payload","data","normalized","toLowerCase","candidates","text","candidate","contentToString","item","Boolean","record","asRecord","includes","createdAt","created_at","session_id","id","project_path","base","underscore","lastIndexOf","slice","replace","isNaN","getTime","name","status","determineStatus","RUNNING","diffMs","now","diffMinutes","IDLE","WAITING","maxLength","token","getConversation","options","verbose","listSessions","opts","summaries","fileToSessionSummary","firstUserMessage","startedAt"],"mappings":"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"}
@@ -1,458 +0,0 @@
1
- /**
2
- * Tests for PiAdapter
3
- */
4
-
5
- import type { MockedFunction } from 'vitest';
6
- import * as fs from 'fs';
7
- import * as os from 'os';
8
- import * as path from 'path';
9
-
10
- import { PiAdapter } from '../../adapters/PiAdapter.js';
11
- import type { ProcessInfo } from '../../adapters/AgentAdapter.js';
12
- import { AgentStatus } from '../../adapters/AgentAdapter.js';
13
- import { AgentRegistry } from '../../utils/AgentRegistry.js';
14
- import { listAgentProcesses, enrichProcesses, captureProcessSnapshot } from '../../utils/process.js';
15
- import { matchProcessesToSessions, generateAgentName } from '../../utils/matching.js';
16
-
17
- vi.mock('../../utils/process.js', async (importOriginal) => {
18
- const actual = await importOriginal() as typeof import('../../utils/process.js');
19
- return {
20
- ...actual,
21
- listAgentProcesses: vi.fn(),
22
- enrichProcesses: vi.fn(),
23
- captureProcessSnapshot: vi.fn(),
24
- };
25
- });
26
-
27
- vi.mock('../../utils/matching.js', () => ({
28
- matchProcessesToSessions: vi.fn(),
29
- generateAgentName: vi.fn(),
30
- }));
31
-
32
- const mockedListAgentProcesses = listAgentProcesses as MockedFunction<typeof listAgentProcesses>;
33
- const mockedEnrichProcesses = enrichProcesses as MockedFunction<typeof enrichProcesses>;
34
- const mockedCaptureProcessSnapshot = captureProcessSnapshot as MockedFunction<typeof captureProcessSnapshot>;
35
- const mockedMatchProcessesToSessions = matchProcessesToSessions as MockedFunction<typeof matchProcessesToSessions>;
36
- const mockedGenerateAgentName = generateAgentName as MockedFunction<typeof generateAgentName>;
37
-
38
- describe('PiAdapter', () => {
39
- let adapter: PiAdapter;
40
- let tmpHome: string;
41
- let sessionsDir: string;
42
-
43
- beforeEach(() => {
44
- tmpHome = fs.mkdtempSync(path.join(os.tmpdir(), 'pi-adapter-test-'));
45
- process.env.HOME = tmpHome;
46
- sessionsDir = path.join(tmpHome, '.pi', 'agent', 'sessions');
47
- fs.mkdirSync(sessionsDir, { recursive: true });
48
-
49
- adapter = new PiAdapter(new AgentRegistry(path.join(tmpHome, 'agents.json')));
50
- mockedListAgentProcesses.mockReset();
51
- mockedEnrichProcesses.mockReset();
52
- mockedCaptureProcessSnapshot.mockReset();
53
- mockedMatchProcessesToSessions.mockReset();
54
- mockedGenerateAgentName.mockReset();
55
-
56
- mockedEnrichProcesses.mockImplementation((procs) => procs);
57
- // Compatibility shim for standalone adapter discovery; the manager captures once and slices by name.
58
- mockedCaptureProcessSnapshot.mockImplementation(async (names) => (
59
- enrichProcesses(names.flatMap((name) => listAgentProcesses(name)))
60
- ));
61
- mockedMatchProcessesToSessions.mockReturnValue([]);
62
- mockedGenerateAgentName.mockImplementation((cwd: string, pid: number) => {
63
- const folder = path.basename(cwd) || 'unknown';
64
- return `${folder} (${pid})`;
65
- });
66
- });
67
-
68
- afterEach(() => {
69
- fs.rmSync(tmpHome, { recursive: true, force: true });
70
- });
71
-
72
- it('exposes pi type', () => {
73
- expect(adapter.type).toBe('pi');
74
- });
75
-
76
- it('identifies Pi commands without matching unrelated paths', () => {
77
- expect(adapter.canHandle({ pid: 1, command: 'pi', cwd: '/repo', tty: 'ttys001' })).toBe(true);
78
- expect(adapter.canHandle({ pid: 2, command: '/usr/local/bin/PI --model x', cwd: '/repo', tty: 'ttys002' })).toBe(true);
79
- expect(adapter.canHandle({ pid: 3, command: 'node /opt/pi/bin/pi.js', cwd: '/repo', tty: 'ttys003' })).toBe(true);
80
- expect(adapter.canHandle({ pid: 4, command: 'node /repo/feature-pi-adapter/script.js', cwd: '/repo', tty: 'ttys004' })).toBe(false);
81
- expect(adapter.canHandle({ pid: 5, command: 'C:\\tools\\node.exe C:\\lib\\pi.js', cwd: '/repo', tty: 'ttys005' })).toBe(true);
82
- });
83
-
84
- it('rejects foreign executables from a hand-built snapshot context', async () => {
85
- const foreign: ProcessInfo = {
86
- pid: 6,
87
- command: 'claude --resume /Users/x/repos/pi/session.jsonl',
88
- cwd: '/repo',
89
- tty: 'ttys006',
90
- };
91
-
92
- expect(await adapter.detectAgents({ processes: [foreign] })).toEqual([]);
93
- });
94
-
95
- it('maps a running Pi process to the tracker session for its PID', async () => {
96
- const cwd = '/repo/project-a';
97
- const proc = makeProcess({ pid: 101, cwd });
98
- const sessionFile = writePiSession(cwd, [
99
- { type: 'session_meta', timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-101', cwd },
100
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'implement Pi adapter' },
101
- { role: 'assistant', timestamp: new Date().toISOString(), content: 'working on it' },
102
- ]);
103
- fs.writeFileSync(
104
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
105
- JSON.stringify({ 101: sessionFile }),
106
- );
107
- mockedListAgentProcesses.mockReturnValue([proc]);
108
-
109
- const agents = await adapter.detectAgents();
110
-
111
- expect(agents).toHaveLength(1);
112
- expect(agents[0]).toMatchObject({
113
- type: 'pi',
114
- pid: 101,
115
- projectPath: cwd,
116
- sessionId: 'sess-101',
117
- summary: 'implement Pi adapter',
118
- status: AgentStatus.WAITING,
119
- sessionFilePath: sessionFile,
120
- });
121
- expect(mockedMatchProcessesToSessions).not.toHaveBeenCalled();
122
- });
123
-
124
- it('truncates long user prompts in detected agent summaries', async () => {
125
- const cwd = '/repo/project-long-summary';
126
- const proc = makeProcess({ pid: 112, cwd });
127
- const longPrompt = 'x'.repeat(140);
128
- const sessionFile = writePiSession(cwd, [
129
- { type: 'session', timestamp: '2026-06-10T08:58:20.754Z', id: 'sess-long', cwd },
130
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: longPrompt },
131
- ]);
132
- fs.writeFileSync(
133
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
134
- JSON.stringify({ 112: sessionFile }),
135
- );
136
- mockedListAgentProcesses.mockReturnValue([proc]);
137
-
138
- const agents = await adapter.detectAgents();
139
-
140
- expect(agents[0].summary).toHaveLength(120);
141
- expect(agents[0].summary.endsWith('...')).toBe(true);
142
- });
143
-
144
- it('uses the filename session id fallback and reports running when the latest message is from the user', async () => {
145
- const cwd = '/repo/project-filename-fallback';
146
- const proc = makeProcess({ pid: 113, cwd });
147
- const sessionFile = writePiSessionWithFileName(cwd, 'plain-session.jsonl', [
148
- { role: 'user', timestamp: new Date().toISOString(), content: 'still working' },
149
- ]);
150
- fs.writeFileSync(
151
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
152
- JSON.stringify({ 113: sessionFile }),
153
- );
154
- mockedListAgentProcesses.mockReturnValue([proc]);
155
-
156
- const agents = await adapter.detectAgents();
157
-
158
- expect(agents[0]).toMatchObject({
159
- sessionId: 'plain-session',
160
- summary: 'still working',
161
- status: AgentStatus.RUNNING,
162
- });
163
- });
164
-
165
- it('falls back to legacy matching when sessions.json is missing', async () => {
166
- const cwd = '/repo/project-b';
167
- const proc = makeProcess({ pid: 202, cwd });
168
- const sessionFile = writePiSession(cwd, [
169
- { timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-202' },
170
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'fallback matching please' },
171
- ]);
172
- mockedListAgentProcesses.mockReturnValue([proc]);
173
- mockedMatchProcessesToSessions.mockReturnValue([
174
- {
175
- process: proc,
176
- session: {
177
- sessionId: 'sess-202',
178
- filePath: sessionFile,
179
- projectDir: path.dirname(sessionFile),
180
- birthtimeMs: Date.now(),
181
- resolvedCwd: cwd,
182
- },
183
- deltaMs: 0,
184
- },
185
- ]);
186
-
187
- const agents = await adapter.detectAgents();
188
-
189
- expect(agents).toHaveLength(1);
190
- expect(agents[0]).toMatchObject({
191
- type: 'pi',
192
- pid: 202,
193
- projectPath: cwd,
194
- sessionId: 'sess-202',
195
- summary: 'fallback matching please',
196
- });
197
- expect(mockedMatchProcessesToSessions).toHaveBeenCalledWith(
198
- [proc],
199
- expect.arrayContaining([
200
- expect.objectContaining({ filePath: sessionFile, resolvedCwd: cwd }),
201
- ]),
202
- );
203
- });
204
-
205
- it('ignores malformed tracker metadata and still falls back to legacy matching', async () => {
206
- const cwd = '/repo/project-c';
207
- const proc = makeProcess({ pid: 303, cwd });
208
- const sessionFile = writePiSession(cwd, [
209
- { timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-303', cwd },
210
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'recover from bad tracker' },
211
- ]);
212
- fs.writeFileSync(path.join(tmpHome, '.pi', 'agent', 'sessions.json'), '{bad json');
213
- mockedListAgentProcesses.mockReturnValue([proc]);
214
- mockedMatchProcessesToSessions.mockReturnValue([
215
- {
216
- process: proc,
217
- session: {
218
- sessionId: 'sess-303',
219
- filePath: sessionFile,
220
- projectDir: path.dirname(sessionFile),
221
- birthtimeMs: Date.now(),
222
- resolvedCwd: cwd,
223
- },
224
- deltaMs: 0,
225
- },
226
- ]);
227
-
228
- const agents = await adapter.detectAgents();
229
-
230
- expect(agents).toHaveLength(1);
231
- expect(agents[0].sessionId).toBe('sess-303');
232
- });
233
-
234
- it('falls back to legacy matching when a trusted tracker session is unparseable', async () => {
235
- const cwd = '/repo/project-bad-tracker-session';
236
- const proc = makeProcess({ pid: 304, cwd });
237
- const badSessionFile = writePiSessionWithFileName(cwd, 'bad.jsonl', ['{not json']);
238
- const fallbackSessionFile = writePiSession(cwd, [
239
- { timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-304', cwd },
240
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'fallback after bad tracker session' },
241
- ]);
242
- fs.writeFileSync(
243
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
244
- JSON.stringify({ 304: badSessionFile }),
245
- );
246
- mockedListAgentProcesses.mockReturnValue([proc]);
247
- mockedMatchProcessesToSessions.mockReturnValue([
248
- {
249
- process: proc,
250
- session: {
251
- sessionId: 'sess-304',
252
- filePath: fallbackSessionFile,
253
- projectDir: path.dirname(fallbackSessionFile),
254
- birthtimeMs: Date.now(),
255
- resolvedCwd: cwd,
256
- },
257
- deltaMs: 0,
258
- },
259
- ]);
260
-
261
- const agents = await adapter.detectAgents();
262
-
263
- expect(agents).toHaveLength(1);
264
- expect(agents[0]).toMatchObject({
265
- sessionId: 'sess-304',
266
- summary: 'fallback after bad tracker session',
267
- sessionFilePath: fallbackSessionFile,
268
- });
269
- expect(mockedMatchProcessesToSessions).toHaveBeenCalled();
270
- });
271
-
272
- it('does not trust tracker paths outside the Pi sessions directory', async () => {
273
- const cwd = '/repo/project-d';
274
- const proc = makeProcess({ pid: 404, cwd });
275
- const outside = path.join(tmpHome, 'outside.jsonl');
276
- fs.writeFileSync(outside, JSON.stringify({ role: 'user', content: 'nope' }));
277
- fs.writeFileSync(
278
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
279
- JSON.stringify({ 404: outside }),
280
- );
281
- mockedListAgentProcesses.mockReturnValue([proc]);
282
-
283
- const agents = await adapter.detectAgents();
284
-
285
- expect(agents).toHaveLength(1);
286
- expect(agents[0]).toMatchObject({
287
- type: 'pi',
288
- pid: 404,
289
- sessionId: 'pid-404',
290
- summary: 'Pi process running',
291
- });
292
- });
293
-
294
- it('returns a process-only agent when no session can be matched', async () => {
295
- const proc = makeProcess({ pid: 505, cwd: '/repo/project-e' });
296
- mockedListAgentProcesses.mockReturnValue([proc]);
297
-
298
- const agents = await adapter.detectAgents();
299
-
300
- expect(agents).toHaveLength(1);
301
- expect(agents[0]).toMatchObject({
302
- type: 'pi',
303
- status: AgentStatus.RUNNING,
304
- pid: 505,
305
- projectPath: '/repo/project-e',
306
- sessionId: 'pid-505',
307
- summary: 'Pi process running',
308
- });
309
- });
310
-
311
- it('reads user and assistant conversation messages from JSONL', () => {
312
- const cwd = '/repo/project-f';
313
- const sessionFile = writePiSession(cwd, [
314
- { role: 'system', timestamp: '2026-06-10T08:58:20.000Z', content: 'hidden' },
315
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'hello pi' },
316
- { type: 'assistant', timestamp: '2026-06-10T08:58:22.000Z', message: { content: 'hello human' } },
317
- '{not json',
318
- ]);
319
-
320
- expect(adapter.getConversation(sessionFile)).toEqual([
321
- { role: 'user', content: 'hello pi', timestamp: '2026-06-10T08:58:21.000Z' },
322
- { role: 'assistant', content: 'hello human', timestamp: '2026-06-10T08:58:22.000Z' },
323
- ]);
324
- });
325
-
326
- it('includes system entries only in verbose conversation mode', () => {
327
- const cwd = '/repo/project-verbose';
328
- const sessionFile = writePiSession(cwd, [
329
- { role: 'system', timestamp: '2026-06-10T08:58:20.000Z', content: 'model changed' },
330
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'visible' },
331
- ]);
332
-
333
- expect(adapter.getConversation(sessionFile)).toEqual([
334
- { role: 'user', content: 'visible', timestamp: '2026-06-10T08:58:21.000Z' },
335
- ]);
336
- expect(adapter.getConversation(sessionFile, { verbose: true })).toEqual([
337
- { role: 'system', content: 'model changed', timestamp: '2026-06-10T08:58:20.000Z' },
338
- { role: 'user', content: 'visible', timestamp: '2026-06-10T08:58:21.000Z' },
339
- ]);
340
- });
341
-
342
- it('reads real Pi message entries with nested role and text parts', async () => {
343
- const cwd = '/repo/project-real';
344
- const proc = makeProcess({ pid: 606, cwd });
345
- const sessionFile = writePiSession(cwd, [
346
- { type: 'session', version: 3, id: 'sess-real', timestamp: '2026-06-10T13:27:17.581Z', cwd },
347
- { type: 'model_change', id: 'model-1', timestamp: '2026-06-10T13:27:17.655Z', modelId: 'claude-sonnet-4-6' },
348
- {
349
- type: 'message',
350
- id: 'msg-user',
351
- timestamp: '2026-06-10T13:27:37.975Z',
352
- message: {
353
- role: 'user',
354
- content: [{ type: 'text', text: 'hello' }],
355
- timestamp: 1781098057974,
356
- },
357
- },
358
- {
359
- type: 'message',
360
- id: 'msg-assistant',
361
- timestamp: '2026-06-10T13:27:40.161Z',
362
- message: {
363
- role: 'assistant',
364
- content: [{ type: 'text', text: 'Hello! How can I help you today?' }],
365
- provider: 'anthropic',
366
- model: 'claude-sonnet-4-6',
367
- timestamp: 1781098058012,
368
- },
369
- },
370
- ]);
371
- fs.writeFileSync(
372
- path.join(tmpHome, '.pi', 'agent', 'sessions.json'),
373
- JSON.stringify({ 606: sessionFile }),
374
- );
375
- mockedListAgentProcesses.mockReturnValue([proc]);
376
-
377
- expect(adapter.getConversation(sessionFile)).toEqual([
378
- { role: 'user', content: 'hello', timestamp: '2026-06-10T13:27:37.975Z' },
379
- { role: 'assistant', content: 'Hello! How can I help you today?', timestamp: '2026-06-10T13:27:40.161Z' },
380
- ]);
381
-
382
- const agents = await adapter.detectAgents();
383
- expect(agents[0]).toMatchObject({
384
- sessionId: 'sess-real',
385
- summary: 'hello',
386
- lastActive: new Date('2026-06-10T13:27:40.161Z'),
387
- });
388
- });
389
-
390
- it('lists historical sessions and applies cwd filtering', async () => {
391
- const matchingCwd = '/repo/project-g';
392
- const otherCwd = '/repo/project-h';
393
- const matchingSession = writePiSession(matchingCwd, [
394
- { timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-g', cwd: matchingCwd },
395
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'first matching message' },
396
- ]);
397
- writePiSession(otherCwd, [
398
- { timestamp: '2026-06-10T08:58:20.754Z', sessionId: 'sess-h', cwd: otherCwd },
399
- { role: 'user', timestamp: '2026-06-10T08:58:21.000Z', content: 'other message' },
400
- ]);
401
-
402
- const sessions = await adapter.listSessions({ cwd: matchingCwd });
403
-
404
- expect(sessions).toEqual([
405
- expect.objectContaining({
406
- type: 'pi',
407
- sessionId: 'sess-g',
408
- cwd: matchingCwd,
409
- firstUserMessage: 'first matching message',
410
- sessionFilePath: matchingSession,
411
- }),
412
- ]);
413
- });
414
-
415
- function makeProcess(overrides: Partial<ProcessInfo>): ProcessInfo {
416
- return {
417
- pid: 1,
418
- command: 'pi',
419
- cwd: '/repo',
420
- tty: 'ttys001',
421
- startTime: new Date('2026-06-10T08:58:20.000Z'),
422
- ...overrides,
423
- };
424
- }
425
-
426
- function writePiSession(cwd: string, entries: Array<Record<string, unknown> | string>): string {
427
- const projectDir = path.join(sessionsDir, encodeProjectDir(cwd));
428
- fs.mkdirSync(projectDir, { recursive: true });
429
- const sessionId = entries
430
- .map((entry) => typeof entry === 'string' ? undefined : entry.sessionId)
431
- .find((value): value is string => typeof value === 'string') ?? cryptoRandomSessionId();
432
- const filePath = path.join(projectDir, `2026-06-10T08-58-20-754Z_${sessionId}.jsonl`);
433
- fs.writeFileSync(
434
- filePath,
435
- entries.map((entry) => typeof entry === 'string' ? entry : JSON.stringify(entry)).join('\n'),
436
- );
437
- return filePath;
438
- }
439
-
440
- function writePiSessionWithFileName(cwd: string, fileName: string, entries: Array<Record<string, unknown> | string>): string {
441
- const projectDir = path.join(sessionsDir, encodeProjectDir(cwd));
442
- fs.mkdirSync(projectDir, { recursive: true });
443
- const filePath = path.join(projectDir, fileName);
444
- fs.writeFileSync(
445
- filePath,
446
- entries.map((entry) => typeof entry === 'string' ? entry : JSON.stringify(entry)).join('\n'),
447
- );
448
- return filePath;
449
- }
450
-
451
- function encodeProjectDir(cwd: string): string {
452
- return cwd.replace(/\//g, '-').replace(/^-?/, '--') + '--';
453
- }
454
-
455
- function cryptoRandomSessionId(): string {
456
- return `019eb0c1-06d2-71ed-90ee-${Math.random().toString(16).slice(2, 14).padEnd(12, '0')}`;
457
- }
458
- });
@@ -1,102 +0,0 @@
1
- import fs from 'fs';
2
- import os from 'os';
3
- import path from 'path';
4
- import Database from 'better-sqlite3';
5
- import { afterEach, describe, expect, it } from 'vitest';
6
- import { DatabaseConnection } from '../../database/connection.js';
7
- import { getSchemaVersion } from '../../database/schema.js';
8
-
9
- const roots: string[] = [];
10
-
11
- afterEach(() => {
12
- for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true });
13
- });
14
-
15
- function dbPath(): string {
16
- const root = fs.mkdtempSync(path.join(os.tmpdir(), 'durable-agent-db-'));
17
- roots.push(root);
18
- return path.join(root, 'state', 'agents.db');
19
- }
20
-
21
- describe('durable agents schema', () => {
22
- it('migrates to version 4 with durable constraints and indexes', () => {
23
- const connection = new DatabaseConnection({ dbPath: dbPath() });
24
- expect(getSchemaVersion(connection)).toBe(4);
25
- const table = connection.queryOne<{ sql: string }>(
26
- "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'durable_agents'",
27
- );
28
- expect(table?.sql).toContain("DEFAULT 'durable'");
29
- expect(table?.sql).toContain("state IN ('ready','running','degraded')");
30
- expect(connection.query<{ name: string }>(
31
- "SELECT name FROM sqlite_master WHERE type = 'index' AND tbl_name = 'durable_agents'",
32
- ).map(({ name }) => name)).toEqual(expect.arrayContaining([
33
- 'idx_durable_agents_state', 'idx_durable_agents_list',
34
- ]));
35
- connection.close();
36
- });
37
-
38
- it('upgrades a version 3 database to nullable, unique provider sessions', () => {
39
- const file = dbPath();
40
- fs.mkdirSync(path.dirname(file), { recursive: true });
41
- const raw = new Database(file);
42
- raw.exec(`
43
- CREATE TABLE durable_agents (
44
- id TEXT PRIMARY KEY,
45
- provider_session_id TEXT NOT NULL UNIQUE
46
- );
47
- INSERT INTO durable_agents (id, provider_session_id) VALUES ('existing', 'existing-session');
48
- PRAGMA user_version = 3;
49
- `);
50
- raw.close();
51
-
52
- const connection = new DatabaseConnection({ dbPath: file });
53
- expect(getSchemaVersion(connection)).toBe(4);
54
- expect(() => connection.execute(
55
- 'INSERT INTO durable_agents (id, provider_session_id) VALUES (?, NULL)', ['codex'],
56
- )).not.toThrow();
57
- expect(() => connection.execute(
58
- 'INSERT INTO durable_agents (id, provider_session_id) VALUES (?, ?)', ['duplicate', 'existing-session'],
59
- )).toThrow(/UNIQUE/i);
60
- connection.close();
61
- });
62
-
63
- it('enforces case-insensitive names and active-run consistency but permits new providers', () => {
64
- const connection = new DatabaseConnection({ dbPath: dbPath() });
65
- const insert = (name: string, provider: string, state = 'ready') => connection.execute(`
66
- INSERT INTO durable_agents (
67
- id, name, provider, mode, cwd, provider_session_id, state, session_health,
68
- created_at, updated_at
69
- ) VALUES (?, ?, ?, 'durable', '/tmp', ?, ?, 'uninitialized', ?, ?)
70
- `, [crypto.randomUUID(), name, provider, crypto.randomUUID(), state, new Date().toISOString(), new Date().toISOString()]);
71
- expect(() => insert('Alpha', 'future-provider')).not.toThrow();
72
- expect(() => insert('alpha', 'claude')).toThrow(/UNIQUE/i);
73
- expect(() => insert('Broken', 'claude', 'running')).toThrow(/CHECK/i);
74
- connection.close();
75
- });
76
- });
77
-
78
- describe('readonly DatabaseConnection', () => {
79
- it('opens an already migrated database without changing it', () => {
80
- const file = dbPath();
81
- const writable = new DatabaseConnection({ dbPath: file });
82
- writable.close();
83
- const before = fs.statSync(file).mtimeMs;
84
- const readonly = new DatabaseConnection({ dbPath: file, readonly: true });
85
- expect(readonly.queryOne<{ user_version: number }>('PRAGMA user_version')?.user_version).toBe(4);
86
- readonly.close();
87
- expect(fs.statSync(file).mtimeMs).toBe(before);
88
- });
89
-
90
- it('does not create a missing database or migrate an old one', () => {
91
- const missing = dbPath();
92
- expect(() => new DatabaseConnection({ dbPath: missing, readonly: true })).toThrow(/readonly.*exist/i);
93
- expect(fs.existsSync(missing)).toBe(false);
94
-
95
- fs.mkdirSync(path.dirname(missing), { recursive: true });
96
- const raw = new Database(missing);
97
- raw.pragma('user_version = 2');
98
- raw.close();
99
- expect(() => new DatabaseConnection({ dbPath: missing, readonly: true })).toThrow(/schema version 3/i);
100
- expect(new Database(missing, { readonly: true }).pragma('user_version', { simple: true })).toBe(2);
101
- });
102
- });