@ai-devkit/agent-manager 0.37.0 → 0.39.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 (357) hide show
  1. package/dist/AgentManager.d.ts +0 -4
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +2 -2
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/capacity/anthropic.test.js +115 -0
  6. package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
  7. package/dist/__tests__/capacity/boundaries.test.js +45 -0
  8. package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
  9. package/dist/__tests__/capacity/claude.test.js +3 -3
  10. package/dist/__tests__/capacity/claude.test.js.map +1 -1
  11. package/dist/__tests__/capacity/codex.test.js +3 -1
  12. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  13. package/dist/__tests__/capacity/openai.test.js +21 -12
  14. package/dist/__tests__/capacity/openai.test.js.map +1 -1
  15. package/dist/__tests__/capacity/wham.test.js +1 -1
  16. package/dist/__tests__/capacity/wham.test.js.map +1 -1
  17. package/dist/__tests__/capacity/zai.test.js +7 -8
  18. package/dist/__tests__/capacity/zai.test.js.map +1 -1
  19. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +2 -1
  20. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -1
  21. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -1
  22. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +7 -15
  23. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -1
  24. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +3 -1
  25. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -1
  26. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +11 -26
  27. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -1
  28. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +3 -7
  29. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -1
  30. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js +597 -0
  31. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -0
  32. package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js +91 -0
  33. package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js.map +1 -0
  34. package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js +192 -0
  35. package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js.map +1 -0
  36. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js +407 -0
  37. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -0
  38. package/dist/__tests__/harnesses/devin/fixtures.js +95 -0
  39. package/dist/__tests__/harnesses/devin/fixtures.js.map +1 -0
  40. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +5 -11
  41. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
  42. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
  43. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
  44. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
  45. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
  46. package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +95 -11
  47. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
  48. package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
  49. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
  50. package/dist/__tests__/print/DurableAgent.test.js +4 -6
  51. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  52. package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
  53. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  54. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  55. package/dist/__tests__/terminal/GhosttyBackend.test.js +334 -0
  56. package/dist/__tests__/terminal/GhosttyBackend.test.js.map +1 -0
  57. package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
  58. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  59. package/dist/adapters/AgentAdapter.d.ts +1 -1
  60. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  61. package/dist/adapters/AgentAdapter.js +2 -1
  62. package/dist/adapters/AgentAdapter.js.map +1 -1
  63. package/dist/capacity/index.d.ts +9 -19
  64. package/dist/capacity/index.d.ts.map +1 -1
  65. package/dist/capacity/index.js +11 -4
  66. package/dist/capacity/index.js.map +1 -1
  67. package/dist/capacity/providers/anthropic.d.ts +9 -0
  68. package/dist/capacity/providers/anthropic.d.ts.map +1 -0
  69. package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
  70. package/dist/capacity/providers/anthropic.js.map +1 -0
  71. package/dist/capacity/providers/openai-platform.d.ts +14 -0
  72. package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
  73. package/dist/capacity/providers/openai-platform.js +120 -0
  74. package/dist/capacity/providers/openai-platform.js.map +1 -0
  75. package/dist/capacity/providers/openai-subscription.d.ts +20 -0
  76. package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
  77. package/dist/capacity/providers/openai-subscription.js +129 -0
  78. package/dist/capacity/providers/openai-subscription.js.map +1 -0
  79. package/dist/capacity/providers/zai.d.ts +8 -0
  80. package/dist/capacity/providers/zai.d.ts.map +1 -0
  81. package/dist/capacity/{zai.js → providers/zai.js} +17 -62
  82. package/dist/capacity/providers/zai.js.map +1 -0
  83. package/dist/capacity/sources/claude.d.ts +9 -0
  84. package/dist/capacity/sources/claude.d.ts.map +1 -0
  85. package/dist/capacity/sources/claude.js +17 -0
  86. package/dist/capacity/sources/claude.js.map +1 -0
  87. package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
  88. package/dist/capacity/sources/codex.d.ts.map +1 -0
  89. package/dist/capacity/{codex.js → sources/codex.js} +31 -84
  90. package/dist/capacity/sources/codex.js.map +1 -0
  91. package/dist/capacity/sources/pi.d.ts +30 -0
  92. package/dist/capacity/sources/pi.d.ts.map +1 -0
  93. package/dist/capacity/sources/pi.js +81 -0
  94. package/dist/capacity/sources/pi.js.map +1 -0
  95. package/dist/capacity/types.d.ts +2 -0
  96. package/dist/capacity/types.d.ts.map +1 -1
  97. package/dist/capacity/types.js +1 -1
  98. package/dist/capacity/types.js.map +1 -1
  99. package/dist/harnesses/claude/credentials.d.ts +10 -0
  100. package/dist/harnesses/claude/credentials.d.ts.map +1 -0
  101. package/dist/harnesses/claude/credentials.js +112 -0
  102. package/dist/harnesses/claude/credentials.js.map +1 -0
  103. package/dist/harnesses/claude/readiness.d.ts +3 -0
  104. package/dist/harnesses/claude/readiness.d.ts.map +1 -0
  105. package/dist/harnesses/claude/readiness.js +63 -0
  106. package/dist/harnesses/claude/readiness.js.map +1 -0
  107. package/dist/harnesses/codex/credentials.d.ts +15 -0
  108. package/dist/harnesses/codex/credentials.d.ts.map +1 -0
  109. package/dist/harnesses/codex/credentials.js +58 -0
  110. package/dist/harnesses/codex/credentials.js.map +1 -0
  111. package/dist/harnesses/codex/readiness.d.ts +3 -0
  112. package/dist/harnesses/codex/readiness.d.ts.map +1 -0
  113. package/dist/harnesses/codex/readiness.js +60 -0
  114. package/dist/harnesses/codex/readiness.js.map +1 -0
  115. package/dist/harnesses/copilot/readiness.d.ts +3 -0
  116. package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
  117. package/dist/harnesses/copilot/readiness.js +39 -0
  118. package/dist/harnesses/copilot/readiness.js.map +1 -0
  119. package/dist/harnesses/devin/DevinAdapter.d.ts +39 -0
  120. package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -0
  121. package/dist/harnesses/devin/DevinAdapter.js +177 -0
  122. package/dist/harnesses/devin/DevinAdapter.js.map +1 -0
  123. package/dist/harnesses/devin/DevinAgentMapper.d.ts +11 -0
  124. package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -0
  125. package/dist/harnesses/devin/DevinAgentMapper.js +35 -0
  126. package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -0
  127. package/dist/harnesses/devin/DevinSessionLocator.d.ts +46 -0
  128. package/dist/harnesses/devin/DevinSessionLocator.d.ts.map +1 -0
  129. package/dist/harnesses/devin/DevinSessionLocator.js +176 -0
  130. package/dist/harnesses/devin/DevinSessionLocator.js.map +1 -0
  131. package/dist/harnesses/devin/DevinSessionParser.d.ts +29 -0
  132. package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -0
  133. package/dist/harnesses/devin/DevinSessionParser.js +166 -0
  134. package/dist/harnesses/devin/DevinSessionParser.js.map +1 -0
  135. package/dist/harnesses/devin/readiness.d.ts +3 -0
  136. package/dist/harnesses/devin/readiness.d.ts.map +1 -0
  137. package/dist/harnesses/devin/readiness.js +39 -0
  138. package/dist/harnesses/devin/readiness.js.map +1 -0
  139. package/dist/harnesses/index.d.ts.map +1 -1
  140. package/dist/harnesses/index.js +3 -1
  141. package/dist/harnesses/index.js.map +1 -1
  142. package/dist/harnesses/opencode/readiness.d.ts +3 -0
  143. package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
  144. package/dist/harnesses/opencode/readiness.js +50 -0
  145. package/dist/harnesses/opencode/readiness.js.map +1 -0
  146. package/dist/harnesses/pi/credentials.d.ts +22 -0
  147. package/dist/harnesses/pi/credentials.d.ts.map +1 -0
  148. package/dist/harnesses/pi/credentials.js +98 -0
  149. package/dist/harnesses/pi/credentials.js.map +1 -0
  150. package/dist/harnesses/pi/readiness.d.ts +3 -0
  151. package/dist/harnesses/pi/readiness.d.ts.map +1 -0
  152. package/dist/harnesses/pi/readiness.js +96 -0
  153. package/dist/harnesses/pi/readiness.js.map +1 -0
  154. package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
  155. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
  156. package/dist/harnesses/readiness/AgentReadiness.js +70 -0
  157. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
  158. package/dist/harnesses/readiness/checks.d.ts +31 -0
  159. package/dist/harnesses/readiness/checks.d.ts.map +1 -0
  160. package/dist/harnesses/readiness/checks.js +270 -0
  161. package/dist/harnesses/readiness/checks.js.map +1 -0
  162. package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
  163. package/dist/harnesses/readiness/types.d.ts.map +1 -0
  164. package/dist/harnesses/readiness/types.js +4 -0
  165. package/dist/harnesses/readiness/types.js.map +1 -0
  166. package/dist/harnesses/runtimeProfiles.d.ts +11 -0
  167. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
  168. package/dist/harnesses/runtimeProfiles.js +100 -0
  169. package/dist/harnesses/runtimeProfiles.js.map +1 -0
  170. package/dist/index.d.ts +16 -42
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +9 -23
  173. package/dist/index.js.map +1 -1
  174. package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
  175. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
  176. package/dist/runtime/ManagedAgentRuntime.js +6 -20
  177. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  178. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
  179. package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
  180. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  181. package/dist/runtime/tmux/PidPolling.d.ts +1 -1
  182. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
  183. package/dist/runtime/tmux/PidPolling.js.map +1 -1
  184. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
  185. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
  186. package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
  187. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
  188. package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
  189. package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
  190. package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
  191. package/dist/runtime/tmux/TmuxManager.js.map +1 -0
  192. package/dist/runtime/types.d.ts +1 -1
  193. package/dist/runtime/types.d.ts.map +1 -1
  194. package/dist/runtime/types.js.map +1 -1
  195. package/dist/terminal/TerminalFocusManager.d.ts +4 -32
  196. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  197. package/dist/terminal/TerminalFocusManager.js +17 -267
  198. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  199. package/dist/terminal/TtyWriter.d.ts +1 -44
  200. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  201. package/dist/terminal/TtyWriter.js +12 -347
  202. package/dist/terminal/TtyWriter.js.map +1 -1
  203. package/dist/terminal/backends/ghostty.d.ts +3 -0
  204. package/dist/terminal/backends/ghostty.d.ts.map +1 -0
  205. package/dist/terminal/backends/ghostty.js +161 -0
  206. package/dist/terminal/backends/ghostty.js.map +1 -0
  207. package/dist/terminal/backends/index.d.ts +5 -0
  208. package/dist/terminal/backends/index.d.ts.map +1 -0
  209. package/dist/terminal/backends/index.js +21 -0
  210. package/dist/terminal/backends/index.js.map +1 -0
  211. package/dist/terminal/backends/iterm2.d.ts +3 -0
  212. package/dist/terminal/backends/iterm2.d.ts.map +1 -0
  213. package/dist/terminal/backends/iterm2.js +135 -0
  214. package/dist/terminal/backends/iterm2.js.map +1 -0
  215. package/dist/terminal/backends/shared.d.ts +9 -0
  216. package/dist/terminal/backends/shared.d.ts.map +1 -0
  217. package/dist/terminal/backends/shared.js +38 -0
  218. package/dist/terminal/backends/shared.js.map +1 -0
  219. package/dist/terminal/backends/terminal-app.d.ts +3 -0
  220. package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
  221. package/dist/terminal/backends/terminal-app.js +129 -0
  222. package/dist/terminal/backends/terminal-app.js.map +1 -0
  223. package/dist/terminal/backends/tmux.d.ts +3 -0
  224. package/dist/terminal/backends/tmux.d.ts.map +1 -0
  225. package/dist/terminal/backends/tmux.js +76 -0
  226. package/dist/terminal/backends/tmux.js.map +1 -0
  227. package/dist/terminal/backends/wezterm.d.ts +3 -0
  228. package/dist/terminal/backends/wezterm.d.ts.map +1 -0
  229. package/dist/terminal/backends/wezterm.js +71 -0
  230. package/dist/terminal/backends/wezterm.js.map +1 -0
  231. package/dist/terminal/types.d.ts +22 -0
  232. package/dist/terminal/types.d.ts.map +1 -0
  233. package/dist/terminal/types.js +11 -0
  234. package/dist/terminal/types.js.map +1 -0
  235. package/dist/utils/process.d.ts +2 -0
  236. package/dist/utils/process.d.ts.map +1 -1
  237. package/dist/utils/process.js +3 -0
  238. package/dist/utils/process.js.map +1 -1
  239. package/package.json +1 -1
  240. package/src/AgentManager.ts +1 -1
  241. package/src/__tests__/capacity/anthropic.test.ts +105 -0
  242. package/src/__tests__/capacity/boundaries.test.ts +36 -0
  243. package/src/__tests__/capacity/claude.test.ts +3 -8
  244. package/src/__tests__/capacity/codex.test.ts +12 -35
  245. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
  246. package/src/__tests__/capacity/openai.test.ts +15 -15
  247. package/src/__tests__/capacity/wham.test.ts +1 -1
  248. package/src/__tests__/capacity/zai.test.ts +27 -62
  249. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
  250. package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
  251. package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
  252. package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
  253. package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
  254. package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
  255. package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +292 -0
  256. package/src/__tests__/harnesses/devin/DevinAgentMapper.test.ts +88 -0
  257. package/src/__tests__/harnesses/devin/DevinSessionLocator.test.ts +139 -0
  258. package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +218 -0
  259. package/src/__tests__/harnesses/devin/fixtures.ts +144 -0
  260. package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
  261. package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
  262. package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
  263. package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +77 -9
  264. package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
  265. package/src/__tests__/print/DurableAgent.test.ts +4 -13
  266. package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
  267. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
  268. package/src/__tests__/terminal/GhosttyBackend.test.ts +271 -0
  269. package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
  270. package/src/adapters/AgentAdapter.ts +1 -0
  271. package/src/capacity/index.ts +29 -23
  272. package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
  273. package/src/capacity/providers/openai-platform.ts +150 -0
  274. package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
  275. package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
  276. package/src/capacity/sources/claude.ts +30 -0
  277. package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
  278. package/src/capacity/sources/pi.ts +131 -0
  279. package/src/capacity/types.ts +3 -0
  280. package/src/harnesses/claude/credentials.ts +122 -0
  281. package/src/harnesses/claude/readiness.ts +69 -0
  282. package/src/harnesses/codex/credentials.ts +81 -0
  283. package/src/harnesses/codex/readiness.ts +72 -0
  284. package/src/harnesses/copilot/readiness.ts +33 -0
  285. package/src/harnesses/devin/DevinAdapter.ts +224 -0
  286. package/src/harnesses/devin/DevinAgentMapper.ts +43 -0
  287. package/src/harnesses/devin/DevinSessionLocator.ts +230 -0
  288. package/src/harnesses/devin/DevinSessionParser.ts +236 -0
  289. package/src/harnesses/devin/readiness.ts +36 -0
  290. package/src/harnesses/index.ts +2 -0
  291. package/src/harnesses/opencode/readiness.ts +48 -0
  292. package/src/harnesses/pi/credentials.ts +129 -0
  293. package/src/harnesses/pi/readiness.ts +104 -0
  294. package/src/harnesses/readiness/AgentReadiness.ts +89 -0
  295. package/src/harnesses/readiness/checks.ts +336 -0
  296. package/src/harnesses/readiness/types.ts +90 -0
  297. package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +35 -38
  298. package/src/index.ts +15 -128
  299. package/src/runtime/ManagedAgentRuntime.ts +7 -22
  300. package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
  301. package/src/runtime/tmux/PidPolling.ts +1 -1
  302. package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
  303. package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
  304. package/src/runtime/types.ts +1 -1
  305. package/src/terminal/TerminalFocusManager.ts +19 -292
  306. package/src/terminal/TtyWriter.ts +15 -335
  307. package/src/terminal/backends/ghostty.ts +180 -0
  308. package/src/terminal/backends/index.ts +23 -0
  309. package/src/terminal/backends/iterm2.ts +126 -0
  310. package/src/terminal/backends/shared.ts +47 -0
  311. package/src/terminal/backends/terminal-app.ts +122 -0
  312. package/src/terminal/backends/tmux.ts +62 -0
  313. package/src/terminal/backends/wezterm.ts +65 -0
  314. package/src/terminal/types.ts +23 -0
  315. package/src/utils/process.ts +5 -0
  316. package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
  317. package/dist/__tests__/utils/agents.test.js +0 -93
  318. package/dist/__tests__/utils/agents.test.js.map +0 -1
  319. package/dist/capacity/claude.d.ts +0 -17
  320. package/dist/capacity/claude.d.ts.map +0 -1
  321. package/dist/capacity/claude.js.map +0 -1
  322. package/dist/capacity/codex.d.ts.map +0 -1
  323. package/dist/capacity/codex.js.map +0 -1
  324. package/dist/capacity/openai.d.ts +0 -47
  325. package/dist/capacity/openai.d.ts.map +0 -1
  326. package/dist/capacity/openai.js +0 -307
  327. package/dist/capacity/openai.js.map +0 -1
  328. package/dist/capacity/wham.d.ts +0 -16
  329. package/dist/capacity/wham.d.ts.map +0 -1
  330. package/dist/capacity/wham.js +0 -66
  331. package/dist/capacity/wham.js.map +0 -1
  332. package/dist/capacity/zai.d.ts +0 -14
  333. package/dist/capacity/zai.d.ts.map +0 -1
  334. package/dist/capacity/zai.js.map +0 -1
  335. package/dist/readiness/AgentReadiness.d.ts.map +0 -1
  336. package/dist/readiness/AgentReadiness.js +0 -614
  337. package/dist/readiness/AgentReadiness.js.map +0 -1
  338. package/dist/terminal/TmuxManager.d.ts +0 -28
  339. package/dist/terminal/TmuxManager.d.ts.map +0 -1
  340. package/dist/terminal/TmuxManager.js.map +0 -1
  341. package/dist/terminal/index.d.ts +0 -5
  342. package/dist/terminal/index.d.ts.map +0 -1
  343. package/dist/terminal/index.js +0 -5
  344. package/dist/terminal/index.js.map +0 -1
  345. package/dist/utils/agents.d.ts +0 -16
  346. package/dist/utils/agents.d.ts.map +0 -1
  347. package/dist/utils/agents.js +0 -117
  348. package/dist/utils/agents.js.map +0 -1
  349. package/dist/utils/index.d.ts +0 -8
  350. package/dist/utils/index.d.ts.map +0 -1
  351. package/dist/utils/index.js +0 -6
  352. package/dist/utils/index.js.map +0 -1
  353. package/src/__tests__/utils/agents.test.ts +0 -105
  354. package/src/capacity/openai.ts +0 -355
  355. package/src/readiness/AgentReadiness.ts +0 -730
  356. package/src/terminal/index.ts +0 -4
  357. package/src/utils/index.ts +0 -14
@@ -0,0 +1,122 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { isAbsolute, join, resolve } from "node:path";
5
+ import { promisify } from "node:util";
6
+
7
+ const execFileAsync = promisify(execFile);
8
+ const CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
9
+
10
+ export type ClaudeCredentialOptions = {
11
+ env?: NodeJS.ProcessEnv;
12
+ readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
13
+ now?: () => Date;
14
+ cwd?: string;
15
+ platform?: NodeJS.Platform;
16
+ keychainRead?: (service: string) => Promise<string | null>;
17
+ };
18
+
19
+ type Credential = { token: string | null; expired: boolean };
20
+
21
+ function record(value: unknown): Record<string, unknown> | null {
22
+ return value !== null && typeof value === "object" && !Array.isArray(value)
23
+ ? (value as Record<string, unknown>)
24
+ : null;
25
+ }
26
+
27
+ function nonEmptyText(value: unknown): string | null {
28
+ return typeof value === "string" && value.trim() ? value.trim() : null;
29
+ }
30
+
31
+ function credentialsPath(options: ClaudeCredentialOptions): string {
32
+ const env = options.env ?? process.env;
33
+ const configured = nonEmptyText(env.CLAUDE_CONFIG_DIR);
34
+ if (configured) {
35
+ const profileRoot = isAbsolute(configured)
36
+ ? configured
37
+ : resolve(options.cwd ?? process.cwd(), configured);
38
+ return join(profileRoot, ".credentials.json");
39
+ }
40
+ return join(env.HOME || homedir(), ".claude", ".credentials.json");
41
+ }
42
+
43
+ function credentialFromRoot(root: Record<string, unknown> | null, now: Date): Credential {
44
+ const oauth = record(root?.claudeAiOauth);
45
+ const token = nonEmptyText(oauth?.accessToken);
46
+ if (!token) return { token: null, expired: false };
47
+ const expired =
48
+ typeof oauth?.expiresAt === "number" &&
49
+ Number.isFinite(oauth.expiresAt) &&
50
+ oauth.expiresAt <= now.getTime();
51
+ return { token: expired ? null : token, expired };
52
+ }
53
+
54
+ function credentialFromPayload(payload: string | null, now: Date): Credential {
55
+ if (!payload) return { token: null, expired: false };
56
+ try {
57
+ return credentialFromRoot(record(JSON.parse(payload)), now);
58
+ } catch {
59
+ return { token: null, expired: false };
60
+ }
61
+ }
62
+
63
+ async function readProfileCredential(
64
+ options: ClaudeCredentialOptions,
65
+ now: Date,
66
+ ): Promise<Credential> {
67
+ try {
68
+ const payload = await (options.readFile ?? readFile)(credentialsPath(options), "utf8");
69
+ return credentialFromPayload(payload, now);
70
+ } catch {
71
+ return { token: null, expired: false };
72
+ }
73
+ }
74
+
75
+ async function readClaudeKeychain(service: string): Promise<string | null> {
76
+ try {
77
+ const { stdout } = await execFileAsync(
78
+ "/usr/bin/security",
79
+ ["find-generic-password", "-s", service, "-w"],
80
+ { encoding: "utf8", timeout: 1500, maxBuffer: 1024 * 1024 },
81
+ );
82
+ return nonEmptyText(stdout);
83
+ } catch {
84
+ return null;
85
+ }
86
+ }
87
+
88
+ async function readKeychainCredential(
89
+ options: ClaudeCredentialOptions,
90
+ now: Date,
91
+ ): Promise<Credential> {
92
+ const env = options.env ?? process.env;
93
+ const usesDefaultProfile = !nonEmptyText(env.CLAUDE_CONFIG_DIR);
94
+ if (!usesDefaultProfile || (options.platform ?? process.platform) !== "darwin") {
95
+ return { token: null, expired: false };
96
+ }
97
+ try {
98
+ const payload = await (options.keychainRead ?? readClaudeKeychain)(CLAUDE_KEYCHAIN_SERVICE);
99
+ return credentialFromPayload(payload, now);
100
+ } catch {
101
+ return { token: null, expired: false };
102
+ }
103
+ }
104
+
105
+ export async function resolveClaudeAnthropicToken(
106
+ options: ClaudeCredentialOptions = {},
107
+ ): Promise<string> {
108
+ const env = options.env ?? process.env;
109
+ const environmentToken = nonEmptyText(env.CLAUDE_CODE_OAUTH_TOKEN);
110
+ if (environmentToken) return environmentToken;
111
+
112
+ const now = options.now?.() ?? new Date();
113
+ const profileCredential = await readProfileCredential(options, now);
114
+ if (profileCredential.token) return profileCredential.token;
115
+
116
+ const keychainCredential = await readKeychainCredential(options, now);
117
+ if (keychainCredential.token) return keychainCredential.token;
118
+ if (profileCredential.expired || keychainCredential.expired) {
119
+ throw new Error("Claude OAuth credentials expired");
120
+ }
121
+ throw new Error("Claude OAuth credentials not found or malformed");
122
+ }
@@ -0,0 +1,69 @@
1
+ import { join } from "node:path";
2
+ import {
3
+ record,
4
+ registrationCheck,
5
+ scriptCheck,
6
+ worstReadinessStatus,
7
+ } from "../readiness/checks.js";
8
+ import type {
9
+ AuthReadinessCheck,
10
+ HarnessReadinessProfile,
11
+ IntegrationReadinessCheck,
12
+ ReadinessRuntime,
13
+ } from "../readiness/types.js";
14
+
15
+ async function authCheck(runtime: ReadinessRuntime): Promise<AuthReadinessCheck> {
16
+ try {
17
+ const result = await runtime.runCommand("claude", ["auth", "status", "--json"]);
18
+ const parsed = record(JSON.parse(result.stdout));
19
+ const authenticated = parsed?.loggedIn === true || parsed?.authenticated === true;
20
+ const unauthenticated = parsed?.loggedIn === false || parsed?.authenticated === false;
21
+ return {
22
+ state: authenticated ? "authenticated" : unauthenticated ? "unauthenticated" : "unknown",
23
+ source: "claude auth status --json",
24
+ provider: null,
25
+ availableProviders: [],
26
+ status: authenticated ? "pass" : unauthenticated ? "fail" : "warn",
27
+ errors: authenticated
28
+ ? []
29
+ : [unauthenticated ? "Claude is not authenticated" : "Claude authentication is unknown"],
30
+ };
31
+ } catch {
32
+ return {
33
+ state: "unknown",
34
+ source: "claude auth status --json",
35
+ provider: null,
36
+ availableProviders: [],
37
+ status: "warn",
38
+ errors: ["Claude authentication probe failed"],
39
+ };
40
+ }
41
+ }
42
+
43
+ async function integrationCheck(runtime: ReadinessRuntime): Promise<IntegrationReadinessCheck> {
44
+ const script = await scriptCheck(
45
+ join(runtime.homeDir, ".claude", "hooks", "claude-prompt-hook.js"),
46
+ join(runtime.assetRoot ?? "", "claude", "claude-prompt-hook.js"),
47
+ runtime,
48
+ );
49
+ const registration = await registrationCheck(
50
+ join(runtime.homeDir, ".claude", "settings.json"),
51
+ "PreToolUse",
52
+ "node ~/.claude/hooks/claude-prompt-hook.js",
53
+ runtime,
54
+ );
55
+ const installed = script.status === "pass" && registration.status === "pass";
56
+ return {
57
+ label: "ai-devkit hook",
58
+ installed,
59
+ status: worstReadinessStatus([script.status, registration.status]),
60
+ errors: [...script.errors, ...registration.errors],
61
+ details: { promptScript: script, registration },
62
+ };
63
+ }
64
+
65
+ export const claudeReadiness: HarnessReadinessProfile = {
66
+ configDir: ".claude",
67
+ auth: authCheck,
68
+ integration: integrationCheck,
69
+ };
@@ -0,0 +1,81 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+
4
+ type UnknownRecord = Record<string, unknown>;
5
+
6
+ export type CodexCredentialOptions = {
7
+ env?: NodeJS.ProcessEnv;
8
+ readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
9
+ now?: () => Date;
10
+ };
11
+
12
+ export type CodexCredentials = {
13
+ personalAccessToken: string | null;
14
+ oauth: { access: string; accountId: string } | null;
15
+ };
16
+
17
+ function record(value: unknown): UnknownRecord | null {
18
+ return value !== null && typeof value === "object" && !Array.isArray(value)
19
+ ? (value as UnknownRecord)
20
+ : null;
21
+ }
22
+
23
+ function finiteNumber(value: unknown): number | null {
24
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
25
+ }
26
+
27
+ function nonEmptyText(value: unknown): string | null {
28
+ return typeof value === "string" && value.length > 0 ? value : null;
29
+ }
30
+
31
+ export function resolveCodexAuthPath(env: NodeJS.ProcessEnv = process.env): string {
32
+ const root = env.CODEX_HOME || join(env.HOME || "", ".codex");
33
+ return join(root, "auth.json");
34
+ }
35
+
36
+ function jwtExpiry(token: string): number | null {
37
+ const part = token.split(".")[1];
38
+ if (!part) return null;
39
+ try {
40
+ return finiteNumber(record(JSON.parse(Buffer.from(part, "base64url").toString("utf8")))?.exp);
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ function staleOAuth(tokens: UnknownRecord, token: string, now: Date): boolean {
47
+ const metadata = tokens.expires_at ?? tokens.expiresAt ?? tokens.expiry;
48
+ let expiry: number | null = finiteNumber(metadata);
49
+ if (typeof metadata === "string") {
50
+ const parsed = Date.parse(metadata);
51
+ expiry = Number.isNaN(parsed) ? null : parsed / 1000;
52
+ }
53
+ expiry ??= jwtExpiry(token);
54
+ return expiry !== null && expiry <= now.getTime() / 1000;
55
+ }
56
+
57
+ export async function resolveCodexCredentials(
58
+ options: CodexCredentialOptions = {},
59
+ ): Promise<CodexCredentials | null> {
60
+ let auth: UnknownRecord;
61
+ try {
62
+ const contents = await (options.readFile ?? readFile)(
63
+ resolveCodexAuthPath(options.env),
64
+ "utf8",
65
+ );
66
+ auth = record(JSON.parse(contents)) ?? {};
67
+ } catch {
68
+ return null;
69
+ }
70
+
71
+ const personalAccessToken = nonEmptyText(auth.personal_access_token);
72
+ const tokens = record(auth.tokens);
73
+ const access = nonEmptyText(tokens?.access_token);
74
+ const accountId = nonEmptyText(tokens?.account_id);
75
+ const now = options.now?.() ?? new Date();
76
+ const oauth =
77
+ tokens && access && accountId && !staleOAuth(tokens, access, now)
78
+ ? { access, accountId }
79
+ : null;
80
+ return { personalAccessToken, oauth };
81
+ }
@@ -0,0 +1,72 @@
1
+ import { join } from "node:path";
2
+ import {
3
+ displayHome,
4
+ mappingCheck,
5
+ registrationCheck,
6
+ scriptCheck,
7
+ worstReadinessStatus,
8
+ } from "../readiness/checks.js";
9
+ import type {
10
+ AuthReadinessCheck,
11
+ HarnessReadinessProfile,
12
+ IntegrationReadinessCheck,
13
+ ReadinessRuntime,
14
+ } from "../readiness/types.js";
15
+
16
+ async function authCheck(runtime: ReadinessRuntime): Promise<AuthReadinessCheck> {
17
+ try {
18
+ const value = await runtime.codexAuth();
19
+ return {
20
+ state: value === true ? "authenticated" : value === false ? "unauthenticated" : "unknown",
21
+ source: displayHome(join(runtime.homeDir, ".codex", "auth.json"), runtime.homeDir),
22
+ provider: null,
23
+ availableProviders: [],
24
+ status: value === true ? "pass" : value === false ? "fail" : "warn",
25
+ errors:
26
+ value === true
27
+ ? []
28
+ : [value === false ? "Codex is not authenticated" : "Codex authentication is unknown"],
29
+ };
30
+ } catch {
31
+ return {
32
+ state: "unknown",
33
+ source: "~/.codex/auth.json",
34
+ provider: null,
35
+ availableProviders: [],
36
+ status: "warn",
37
+ errors: ["Codex authentication probe failed"],
38
+ };
39
+ }
40
+ }
41
+
42
+ async function integrationCheck(runtime: ReadinessRuntime): Promise<IntegrationReadinessCheck> {
43
+ const script = await scriptCheck(
44
+ join(runtime.homeDir, ".codex", "hooks", "codex-session-mapping.cjs"),
45
+ join(runtime.assetRoot ?? "", "codex", "codex-session-mapping.cjs"),
46
+ runtime,
47
+ );
48
+ const registration = await registrationCheck(
49
+ join(runtime.homeDir, ".codex", "hooks.json"),
50
+ "SessionStart",
51
+ "node ~/.codex/hooks/codex-session-mapping.cjs",
52
+ runtime,
53
+ );
54
+ const mappingFile = await mappingCheck(
55
+ join(runtime.homeDir, ".codex", "ai-devkit", "sessions.json"),
56
+ runtime,
57
+ );
58
+ const installed = script.status === "pass" && registration.status === "pass";
59
+ return {
60
+ label: "ai-devkit hook",
61
+ installed,
62
+ status: worstReadinessStatus([script.status, registration.status, mappingFile.status]),
63
+ errors: [...script.errors, ...registration.errors, ...mappingFile.errors],
64
+ details: { sessionMappingScript: script, registration, mappingFile },
65
+ };
66
+ }
67
+
68
+ export const codexReadiness: HarnessReadinessProfile = {
69
+ configDir: ".codex",
70
+ auth: authCheck,
71
+ integration: integrationCheck,
72
+ };
@@ -0,0 +1,33 @@
1
+ import type {
2
+ AuthReadinessCheck,
3
+ HarnessReadinessProfile,
4
+ ReadinessRuntime,
5
+ } from "../readiness/types.js";
6
+
7
+ async function authCheck(runtime: ReadinessRuntime): Promise<AuthReadinessCheck> {
8
+ try {
9
+ await runtime.runCommand("gh", ["auth", "status", "--hostname", "github.com"]);
10
+ return {
11
+ state: "authenticated",
12
+ source: "gh auth status --hostname github.com",
13
+ provider: "github",
14
+ availableProviders: ["GitHub"],
15
+ status: "pass",
16
+ errors: [],
17
+ };
18
+ } catch {
19
+ return {
20
+ state: "unknown",
21
+ source: "gh auth status --hostname github.com",
22
+ provider: null,
23
+ availableProviders: ["GitHub"],
24
+ status: "warn",
25
+ errors: ["Copilot authentication could not be verified through GitHub CLI"],
26
+ };
27
+ }
28
+ }
29
+
30
+ export const copilotReadiness: HarnessReadinessProfile = {
31
+ configDir: ".copilot",
32
+ auth: authCheck,
33
+ };
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Devin Adapter
3
+ *
4
+ * Detects running Devin CLI agents by:
5
+ * 1. Filtering `devin` processes from a shared process snapshot, rejecting
6
+ * utility subcommands (list, doctor, ssh, ...) and `devin acp` children
7
+ * spawned by a Devin TUI
8
+ * 2. Matching processes to sessions via `session_locks/<slug>.lock` files,
9
+ * which contain the PID of the session's `devin acp` backend (lock-first;
10
+ * a TUI is matched through its backend child's ppid)
11
+ * 3. Falling back to `sessions.working_directory` matching in
12
+ * ~/.local/share/devin/cli/sessions.db (WAL SQLite, opened read-only)
13
+ *
14
+ * sessionFilePath encodes "<dbPath>::<sessionSlug>" so getConversation() can
15
+ * address a session row without extending the AgentAdapter interface.
16
+ */
17
+
18
+ import type {
19
+ AgentAdapter,
20
+ AgentInfo,
21
+ ProcessInfo,
22
+ ConversationMessage,
23
+ ConversationOptions,
24
+ SessionSummary,
25
+ ListSessionsOptions,
26
+ AgentDetectionContext,
27
+ } from "../../adapters/AgentAdapter.js";
28
+ import { DevinAgentMapper } from "./DevinAgentMapper.js";
29
+ import { DevinSessionLocator, decodeDevinSessionRef } from "./DevinSessionLocator.js";
30
+ import { DevinSessionParser } from "./DevinSessionParser.js";
31
+ import { findHarnessProcesses, matchesExecutable } from "../shared.js";
32
+ import { executablePath } from "../../utils/process.js";
33
+
34
+ /**
35
+ * `devin` invocations that are utilities, not agent sessions. `acp` is
36
+ * deliberately absent: a standalone `devin acp` serves an external client
37
+ * and is itself an agent.
38
+ */
39
+ const UTILITY_SUBCOMMANDS = new Set([
40
+ "auth",
41
+ "cloud",
42
+ "desktop",
43
+ "doctor",
44
+ "forward",
45
+ "help",
46
+ "list",
47
+ "ls",
48
+ "mcp",
49
+ "migrate",
50
+ "models",
51
+ "plugins",
52
+ "rm",
53
+ "rules",
54
+ "sandbox",
55
+ "setup",
56
+ "skills",
57
+ "ssh",
58
+ "uninstall",
59
+ "update",
60
+ "version",
61
+ ]);
62
+
63
+ /**
64
+ * Flags that always consume the next argv token as their value.
65
+ * (`devin --help`, main-command options.)
66
+ */
67
+ const REQUIRED_VALUE_FLAGS = new Set([
68
+ "--prompt-file",
69
+ "--config",
70
+ "--permission-mode",
71
+ "--model",
72
+ ]);
73
+
74
+ /**
75
+ * Flags whose value is optional: the next token is consumed only when it
76
+ * isn't itself a flag (commander `[<VALUE>]` semantics).
77
+ */
78
+ const OPTIONAL_VALUE_FLAGS = new Set([
79
+ "-p",
80
+ "--print",
81
+ "-r",
82
+ "--resume",
83
+ "--export",
84
+ "--respect-workspace-trust",
85
+ ]);
86
+
87
+ /**
88
+ * First positional argv token after argv[0] — the subcommand candidate.
89
+ * Flag values are skipped (so `devin -p "update deps"` isn't mistaken for
90
+ * the `update` subcommand); `--` ends the search.
91
+ */
92
+ function firstPositionalToken(command: string): string | null {
93
+ const argv0 = executablePath(command);
94
+ const tokens = command
95
+ .trim()
96
+ .slice(argv0.length)
97
+ .trim()
98
+ .split(/\s+/);
99
+ for (let i = 0; i < tokens.length; i++) {
100
+ const token = tokens[i];
101
+ if (!token) continue;
102
+ if (token === "--") return null;
103
+ if (!token.startsWith("-")) return token;
104
+ const flag = token.split("=", 1)[0];
105
+ if (flag === token) {
106
+ if (REQUIRED_VALUE_FLAGS.has(flag)) {
107
+ i++;
108
+ } else if (OPTIONAL_VALUE_FLAGS.has(flag) && !tokens[i + 1]?.startsWith("-")) {
109
+ i++;
110
+ }
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+
116
+ export class DevinAdapter implements AgentAdapter {
117
+ readonly type = "devin" as const;
118
+ readonly processNames = ["devin"] as const;
119
+
120
+ private readonly parser: DevinSessionParser;
121
+ private readonly locator: DevinSessionLocator;
122
+ private readonly mapper: DevinAgentMapper;
123
+ private readonly cleanup = (): void => this.close();
124
+
125
+ constructor(dbPath?: string, locksDir?: string) {
126
+ this.parser = new DevinSessionParser();
127
+ // Locator defaults resolve dbPath itself and derive locksDir from it.
128
+ this.locator = new DevinSessionLocator(dbPath, locksDir, this.parser);
129
+ this.mapper = new DevinAgentMapper(this.locator.dbFilePath);
130
+ process.once("exit", this.cleanup);
131
+ process.once("SIGINT", this.cleanup);
132
+ process.once("SIGTERM", this.cleanup);
133
+ }
134
+
135
+ close(): void {
136
+ process.off("exit", this.cleanup);
137
+ process.off("SIGINT", this.cleanup);
138
+ process.off("SIGTERM", this.cleanup);
139
+ this.locator.close();
140
+ }
141
+
142
+ canHandle(processInfo: ProcessInfo): boolean {
143
+ if (!matchesExecutable(processInfo.command, "devin")) return false;
144
+ const subcommand = firstPositionalToken(processInfo.command);
145
+ return subcommand === null || !UTILITY_SUBCOMMANDS.has(subcommand.toLowerCase());
146
+ }
147
+
148
+ async detectAgents(context?: AgentDetectionContext): Promise<AgentInfo[]> {
149
+ const { processes } = await findHarnessProcesses(this, context);
150
+ if (processes.length === 0) return [];
151
+
152
+ const db = this.locator.openDb();
153
+ const processByPid = new Map(processes.map((proc) => [proc.pid, proc]));
154
+
155
+ // Locks map a session to its holder PID (the `devin acp` backend); a TUI
156
+ // is matched through its backend child's ppid. Only trust locks whose
157
+ // holder is a live devin process in this snapshot (stale files and PID
158
+ // reuse are filtered out).
159
+ const sessionByPid = new Map<number, string>();
160
+ for (const lock of this.locator.listActiveLocks()) {
161
+ const holder = processByPid.get(lock.pid);
162
+ if (!holder || !this.canHandle(holder)) continue;
163
+ sessionByPid.set(lock.pid, lock.sessionId);
164
+ if (holder.ppid !== undefined) sessionByPid.set(holder.ppid, lock.sessionId);
165
+ }
166
+
167
+ const agents: AgentInfo[] = [];
168
+
169
+ for (const proc of processes) {
170
+ if (this.isAcpBackendChild(proc, processByPid)) continue;
171
+
172
+ const slug = sessionByPid.get(proc.pid);
173
+ const session = !db
174
+ ? null
175
+ : slug
176
+ ? this.locator.findSessionById(db, slug)
177
+ : proc.cwd
178
+ ? this.locator.findSessionForDirectory(db, proc.cwd)
179
+ : null;
180
+
181
+ if (!session || !db) {
182
+ agents.push(this.mapper.mapProcessOnlyAgent(proc));
183
+ continue;
184
+ }
185
+
186
+ const stats = this.parser.getSessionStats(db, session.sessionId);
187
+ agents.push(this.mapper.mapSessionToAgent(session, stats, proc));
188
+ }
189
+
190
+ return agents;
191
+ }
192
+
193
+ getConversation(sessionFilePath: string, options?: ConversationOptions): ConversationMessage[] {
194
+ const sessionId = decodeDevinSessionRef(sessionFilePath);
195
+ if (!sessionId) return [];
196
+
197
+ const db = this.locator.openDb();
198
+ if (!db) return [];
199
+
200
+ return this.parser.getConversation(db, sessionId, options);
201
+ }
202
+
203
+ async listSessions(opts?: ListSessionsOptions): Promise<SessionSummary[]> {
204
+ return this.locator.listSessions(opts);
205
+ }
206
+
207
+ async findSessionsById(sessionId: string): Promise<SessionSummary[]> {
208
+ return this.locator.findSessionsById(sessionId);
209
+ }
210
+
211
+ /**
212
+ * A `devin acp` process spawned by another devin process is that session's
213
+ * backend, not a separate agent. Standalone `acp` processes (external ACP
214
+ * clients) keep their own agent entry.
215
+ */
216
+ private isAcpBackendChild(
217
+ proc: ProcessInfo,
218
+ processByPid: Map<number, ProcessInfo>,
219
+ ): boolean {
220
+ if (firstPositionalToken(proc.command)?.toLowerCase() !== "acp") return false;
221
+ if (proc.ppid === undefined) return false;
222
+ return processByPid.has(proc.ppid);
223
+ }
224
+ }
@@ -0,0 +1,43 @@
1
+ import type { AgentInfo, ProcessInfo } from "../../adapters/AgentAdapter.js";
2
+ import { AgentStatus } from "../../adapters/AgentAdapter.js";
3
+ import { generateAgentName } from "../../utils/matching.js";
4
+ import type { DevinSession } from "./DevinSessionLocator.js";
5
+ import { encodeDevinSessionRef } from "./DevinSessionLocator.js";
6
+ import type { DevinSessionStats } from "./DevinSessionParser.js";
7
+ import { isIdle, processOnlyAgent } from "../shared.js";
8
+
9
+ export class DevinAgentMapper {
10
+ constructor(private readonly dbPath: string) {}
11
+
12
+ mapSessionToAgent(
13
+ session: DevinSession,
14
+ stats: DevinSessionStats,
15
+ proc: ProcessInfo,
16
+ ): AgentInfo {
17
+ const lastActive =
18
+ stats.lastTimeUpdated > 0
19
+ ? new Date(stats.lastTimeUpdated)
20
+ : new Date(session.lastActivityAt || session.timeCreated);
21
+
22
+ return {
23
+ name: generateAgentName(session.directory || proc.cwd || "", proc.pid),
24
+ type: "devin",
25
+ status: this.determineStatus(stats, lastActive),
26
+ summary: stats.summary || session.title || "Devin session active",
27
+ pid: proc.pid,
28
+ projectPath: session.directory || proc.cwd || "",
29
+ sessionId: session.sessionId,
30
+ lastActive,
31
+ sessionFilePath: encodeDevinSessionRef(this.dbPath, session.sessionId),
32
+ };
33
+ }
34
+
35
+ mapProcessOnlyAgent(proc: ProcessInfo): AgentInfo {
36
+ return processOnlyAgent("devin", proc, { summary: "Devin process running" });
37
+ }
38
+
39
+ private determineStatus(stats: DevinSessionStats, lastActive: Date): AgentStatus {
40
+ if (isIdle(lastActive)) return AgentStatus.IDLE;
41
+ return stats.lastRole === "assistant" ? AgentStatus.WAITING : AgentStatus.RUNNING;
42
+ }
43
+ }