@ai-devkit/agent-manager 0.37.0 → 0.38.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 (295) 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/pi/durable/PiCliProbe.test.js +5 -11
  31. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
  32. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
  33. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
  34. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
  35. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
  36. package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +31 -10
  37. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
  38. package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
  39. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
  40. package/dist/__tests__/print/DurableAgent.test.js +4 -6
  41. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  42. package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
  43. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  44. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  45. package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
  46. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  47. package/dist/capacity/index.d.ts +9 -19
  48. package/dist/capacity/index.d.ts.map +1 -1
  49. package/dist/capacity/index.js +11 -4
  50. package/dist/capacity/index.js.map +1 -1
  51. package/dist/capacity/providers/anthropic.d.ts +9 -0
  52. package/dist/capacity/providers/anthropic.d.ts.map +1 -0
  53. package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
  54. package/dist/capacity/providers/anthropic.js.map +1 -0
  55. package/dist/capacity/providers/openai-platform.d.ts +14 -0
  56. package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
  57. package/dist/capacity/providers/openai-platform.js +120 -0
  58. package/dist/capacity/providers/openai-platform.js.map +1 -0
  59. package/dist/capacity/providers/openai-subscription.d.ts +20 -0
  60. package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
  61. package/dist/capacity/providers/openai-subscription.js +129 -0
  62. package/dist/capacity/providers/openai-subscription.js.map +1 -0
  63. package/dist/capacity/providers/zai.d.ts +8 -0
  64. package/dist/capacity/providers/zai.d.ts.map +1 -0
  65. package/dist/capacity/{zai.js → providers/zai.js} +17 -62
  66. package/dist/capacity/providers/zai.js.map +1 -0
  67. package/dist/capacity/sources/claude.d.ts +9 -0
  68. package/dist/capacity/sources/claude.d.ts.map +1 -0
  69. package/dist/capacity/sources/claude.js +17 -0
  70. package/dist/capacity/sources/claude.js.map +1 -0
  71. package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
  72. package/dist/capacity/sources/codex.d.ts.map +1 -0
  73. package/dist/capacity/{codex.js → sources/codex.js} +31 -84
  74. package/dist/capacity/sources/codex.js.map +1 -0
  75. package/dist/capacity/sources/pi.d.ts +30 -0
  76. package/dist/capacity/sources/pi.d.ts.map +1 -0
  77. package/dist/capacity/sources/pi.js +81 -0
  78. package/dist/capacity/sources/pi.js.map +1 -0
  79. package/dist/capacity/types.d.ts +2 -0
  80. package/dist/capacity/types.d.ts.map +1 -1
  81. package/dist/capacity/types.js +1 -1
  82. package/dist/capacity/types.js.map +1 -1
  83. package/dist/harnesses/claude/credentials.d.ts +10 -0
  84. package/dist/harnesses/claude/credentials.d.ts.map +1 -0
  85. package/dist/harnesses/claude/credentials.js +112 -0
  86. package/dist/harnesses/claude/credentials.js.map +1 -0
  87. package/dist/harnesses/claude/readiness.d.ts +3 -0
  88. package/dist/harnesses/claude/readiness.d.ts.map +1 -0
  89. package/dist/harnesses/claude/readiness.js +63 -0
  90. package/dist/harnesses/claude/readiness.js.map +1 -0
  91. package/dist/harnesses/codex/credentials.d.ts +15 -0
  92. package/dist/harnesses/codex/credentials.d.ts.map +1 -0
  93. package/dist/harnesses/codex/credentials.js +58 -0
  94. package/dist/harnesses/codex/credentials.js.map +1 -0
  95. package/dist/harnesses/codex/readiness.d.ts +3 -0
  96. package/dist/harnesses/codex/readiness.d.ts.map +1 -0
  97. package/dist/harnesses/codex/readiness.js +60 -0
  98. package/dist/harnesses/codex/readiness.js.map +1 -0
  99. package/dist/harnesses/copilot/readiness.d.ts +3 -0
  100. package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
  101. package/dist/harnesses/copilot/readiness.js +39 -0
  102. package/dist/harnesses/copilot/readiness.js.map +1 -0
  103. package/dist/harnesses/opencode/readiness.d.ts +3 -0
  104. package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
  105. package/dist/harnesses/opencode/readiness.js +50 -0
  106. package/dist/harnesses/opencode/readiness.js.map +1 -0
  107. package/dist/harnesses/pi/credentials.d.ts +22 -0
  108. package/dist/harnesses/pi/credentials.d.ts.map +1 -0
  109. package/dist/harnesses/pi/credentials.js +98 -0
  110. package/dist/harnesses/pi/credentials.js.map +1 -0
  111. package/dist/harnesses/pi/readiness.d.ts +3 -0
  112. package/dist/harnesses/pi/readiness.d.ts.map +1 -0
  113. package/dist/harnesses/pi/readiness.js +96 -0
  114. package/dist/harnesses/pi/readiness.js.map +1 -0
  115. package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
  116. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
  117. package/dist/harnesses/readiness/AgentReadiness.js +68 -0
  118. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
  119. package/dist/harnesses/readiness/checks.d.ts +31 -0
  120. package/dist/harnesses/readiness/checks.d.ts.map +1 -0
  121. package/dist/harnesses/readiness/checks.js +270 -0
  122. package/dist/harnesses/readiness/checks.js.map +1 -0
  123. package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
  124. package/dist/harnesses/readiness/types.d.ts.map +1 -0
  125. package/dist/harnesses/readiness/types.js +4 -0
  126. package/dist/harnesses/readiness/types.js.map +1 -0
  127. package/dist/harnesses/runtimeProfiles.d.ts +11 -0
  128. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
  129. package/dist/harnesses/runtimeProfiles.js +99 -0
  130. package/dist/harnesses/runtimeProfiles.js.map +1 -0
  131. package/dist/index.d.ts +16 -42
  132. package/dist/index.d.ts.map +1 -1
  133. package/dist/index.js +9 -23
  134. package/dist/index.js.map +1 -1
  135. package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
  136. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
  137. package/dist/runtime/ManagedAgentRuntime.js +6 -20
  138. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  139. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
  140. package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
  141. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  142. package/dist/runtime/tmux/PidPolling.d.ts +1 -1
  143. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
  144. package/dist/runtime/tmux/PidPolling.js.map +1 -1
  145. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
  146. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
  147. package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
  148. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
  149. package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
  150. package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
  151. package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
  152. package/dist/runtime/tmux/TmuxManager.js.map +1 -0
  153. package/dist/runtime/types.d.ts +1 -1
  154. package/dist/runtime/types.d.ts.map +1 -1
  155. package/dist/runtime/types.js.map +1 -1
  156. package/dist/terminal/TerminalFocusManager.d.ts +4 -32
  157. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  158. package/dist/terminal/TerminalFocusManager.js +17 -267
  159. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  160. package/dist/terminal/TtyWriter.d.ts +1 -44
  161. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  162. package/dist/terminal/TtyWriter.js +11 -347
  163. package/dist/terminal/TtyWriter.js.map +1 -1
  164. package/dist/terminal/backends/index.d.ts +5 -0
  165. package/dist/terminal/backends/index.d.ts.map +1 -0
  166. package/dist/terminal/backends/index.js +19 -0
  167. package/dist/terminal/backends/index.js.map +1 -0
  168. package/dist/terminal/backends/iterm2.d.ts +3 -0
  169. package/dist/terminal/backends/iterm2.d.ts.map +1 -0
  170. package/dist/terminal/backends/iterm2.js +135 -0
  171. package/dist/terminal/backends/iterm2.js.map +1 -0
  172. package/dist/terminal/backends/shared.d.ts +7 -0
  173. package/dist/terminal/backends/shared.d.ts.map +1 -0
  174. package/dist/terminal/backends/shared.js +35 -0
  175. package/dist/terminal/backends/shared.js.map +1 -0
  176. package/dist/terminal/backends/terminal-app.d.ts +3 -0
  177. package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
  178. package/dist/terminal/backends/terminal-app.js +129 -0
  179. package/dist/terminal/backends/terminal-app.js.map +1 -0
  180. package/dist/terminal/backends/tmux.d.ts +3 -0
  181. package/dist/terminal/backends/tmux.d.ts.map +1 -0
  182. package/dist/terminal/backends/tmux.js +76 -0
  183. package/dist/terminal/backends/tmux.js.map +1 -0
  184. package/dist/terminal/backends/wezterm.d.ts +3 -0
  185. package/dist/terminal/backends/wezterm.d.ts.map +1 -0
  186. package/dist/terminal/backends/wezterm.js +71 -0
  187. package/dist/terminal/backends/wezterm.js.map +1 -0
  188. package/dist/terminal/types.d.ts +21 -0
  189. package/dist/terminal/types.d.ts.map +1 -0
  190. package/dist/terminal/types.js +10 -0
  191. package/dist/terminal/types.js.map +1 -0
  192. package/package.json +1 -1
  193. package/src/AgentManager.ts +1 -1
  194. package/src/__tests__/capacity/anthropic.test.ts +105 -0
  195. package/src/__tests__/capacity/boundaries.test.ts +36 -0
  196. package/src/__tests__/capacity/claude.test.ts +3 -8
  197. package/src/__tests__/capacity/codex.test.ts +12 -35
  198. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
  199. package/src/__tests__/capacity/openai.test.ts +15 -15
  200. package/src/__tests__/capacity/wham.test.ts +1 -1
  201. package/src/__tests__/capacity/zai.test.ts +27 -62
  202. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
  203. package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
  204. package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
  205. package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
  206. package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
  207. package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
  208. package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
  209. package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
  210. package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
  211. package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +36 -9
  212. package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
  213. package/src/__tests__/print/DurableAgent.test.ts +4 -13
  214. package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
  215. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
  216. package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
  217. package/src/capacity/index.ts +29 -23
  218. package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
  219. package/src/capacity/providers/openai-platform.ts +150 -0
  220. package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
  221. package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
  222. package/src/capacity/sources/claude.ts +30 -0
  223. package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
  224. package/src/capacity/sources/pi.ts +131 -0
  225. package/src/capacity/types.ts +3 -0
  226. package/src/harnesses/claude/credentials.ts +122 -0
  227. package/src/harnesses/claude/readiness.ts +69 -0
  228. package/src/harnesses/codex/credentials.ts +81 -0
  229. package/src/harnesses/codex/readiness.ts +72 -0
  230. package/src/harnesses/copilot/readiness.ts +33 -0
  231. package/src/harnesses/opencode/readiness.ts +48 -0
  232. package/src/harnesses/pi/credentials.ts +129 -0
  233. package/src/harnesses/pi/readiness.ts +104 -0
  234. package/src/harnesses/readiness/AgentReadiness.ts +87 -0
  235. package/src/harnesses/readiness/checks.ts +336 -0
  236. package/src/harnesses/readiness/types.ts +90 -0
  237. package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +34 -38
  238. package/src/index.ts +15 -128
  239. package/src/runtime/ManagedAgentRuntime.ts +7 -22
  240. package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
  241. package/src/runtime/tmux/PidPolling.ts +1 -1
  242. package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
  243. package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
  244. package/src/runtime/types.ts +1 -1
  245. package/src/terminal/TerminalFocusManager.ts +19 -292
  246. package/src/terminal/TtyWriter.ts +16 -336
  247. package/src/terminal/backends/index.ts +21 -0
  248. package/src/terminal/backends/iterm2.ts +126 -0
  249. package/src/terminal/backends/shared.ts +42 -0
  250. package/src/terminal/backends/terminal-app.ts +122 -0
  251. package/src/terminal/backends/tmux.ts +62 -0
  252. package/src/terminal/backends/wezterm.ts +65 -0
  253. package/src/terminal/types.ts +22 -0
  254. package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
  255. package/dist/__tests__/utils/agents.test.js +0 -93
  256. package/dist/__tests__/utils/agents.test.js.map +0 -1
  257. package/dist/capacity/claude.d.ts +0 -17
  258. package/dist/capacity/claude.d.ts.map +0 -1
  259. package/dist/capacity/claude.js.map +0 -1
  260. package/dist/capacity/codex.d.ts.map +0 -1
  261. package/dist/capacity/codex.js.map +0 -1
  262. package/dist/capacity/openai.d.ts +0 -47
  263. package/dist/capacity/openai.d.ts.map +0 -1
  264. package/dist/capacity/openai.js +0 -307
  265. package/dist/capacity/openai.js.map +0 -1
  266. package/dist/capacity/wham.d.ts +0 -16
  267. package/dist/capacity/wham.d.ts.map +0 -1
  268. package/dist/capacity/wham.js +0 -66
  269. package/dist/capacity/wham.js.map +0 -1
  270. package/dist/capacity/zai.d.ts +0 -14
  271. package/dist/capacity/zai.d.ts.map +0 -1
  272. package/dist/capacity/zai.js.map +0 -1
  273. package/dist/readiness/AgentReadiness.d.ts.map +0 -1
  274. package/dist/readiness/AgentReadiness.js +0 -614
  275. package/dist/readiness/AgentReadiness.js.map +0 -1
  276. package/dist/terminal/TmuxManager.d.ts +0 -28
  277. package/dist/terminal/TmuxManager.d.ts.map +0 -1
  278. package/dist/terminal/TmuxManager.js.map +0 -1
  279. package/dist/terminal/index.d.ts +0 -5
  280. package/dist/terminal/index.d.ts.map +0 -1
  281. package/dist/terminal/index.js +0 -5
  282. package/dist/terminal/index.js.map +0 -1
  283. package/dist/utils/agents.d.ts +0 -16
  284. package/dist/utils/agents.d.ts.map +0 -1
  285. package/dist/utils/agents.js +0 -117
  286. package/dist/utils/agents.js.map +0 -1
  287. package/dist/utils/index.d.ts +0 -8
  288. package/dist/utils/index.d.ts.map +0 -1
  289. package/dist/utils/index.js +0 -6
  290. package/dist/utils/index.js.map +0 -1
  291. package/src/__tests__/utils/agents.test.ts +0 -105
  292. package/src/capacity/openai.ts +0 -355
  293. package/src/readiness/AgentReadiness.ts +0 -730
  294. package/src/terminal/index.ts +0 -4
  295. package/src/utils/index.ts +0 -14
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/__tests__/harnesses/runtimeProfiles.test.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport {\n HARNESS_RUNTIME_PROFILES,\n runtimeAgentMatchesHarness,\n} from \"../../harnesses/runtimeProfiles.js\";\n\ndescribe(\"harness runtime profiles\", () => {\n it(\"keeps launch and runtime identity metadata together\", () => {\n expect(HARNESS_RUNTIME_PROFILES.antigravity_cli).toMatchObject({\n command: \"agy\",\n runtimeKind: \"agy\",\n discoveryAliases: [\"agy\", \"antigravity\", \"antigravity_cli\"],\n });\n expect(HARNESS_RUNTIME_PROFILES.antigravity_cli.matches(\"/usr/local/bin/agy\")).toBe(true);\n });\n\n it(\"recognizes agent commands without matching similar argument text\", () => {\n expect(HARNESS_RUNTIME_PROFILES.copilot.matches(\"/opt/copilot-cli/1.0/copilot\")).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.copilot.matches(\"node /repo/copilot-cli/script.js\")).toBe(\n false,\n );\n expect(HARNESS_RUNTIME_PROFILES.grok_cli.matches(\"/Users/dev/.grok/bin/grok --approve\")).toBe(\n true,\n );\n expect(HARNESS_RUNTIME_PROFILES.grok_cli.matches(\"node /repo/grok-cli/script.js\")).toBe(false);\n expect(\n HARNESS_RUNTIME_PROFILES.gemini_cli.matches(\"node --no-warnings /usr/local/bin/gemini\"),\n ).toBe(true);\n });\n\n it(\"matches runtime discovery names through the owning harness profile\", () => {\n expect(runtimeAgentMatchesHarness(\"kiro-cli\", \"kiro\")).toBe(true);\n expect(runtimeAgentMatchesHarness(\"gemini\", \"gemini_cli\")).toBe(true);\n expect(runtimeAgentMatchesHarness(\"codex\", \"claude\")).toBe(false);\n });\n});\n\ndescribe(\"harness matchers with executables under paths containing spaces\", () => {\n let root: string;\n\n function install(relativePath: string): string {\n const fullPath = path.join(root, relativePath);\n fs.mkdirSync(path.dirname(fullPath), { recursive: true });\n fs.writeFileSync(fullPath, \"\");\n return fullPath;\n }\n\n beforeEach(() => {\n root = fs.mkdtempSync(path.join(os.tmpdir(), \"runtime-profiles-spaces-\"));\n });\n\n afterEach(() => {\n fs.rmSync(root, { recursive: true, force: true });\n });\n\n it(\"recognizes argv[0] under a spaced directory\", () => {\n const codex = install(\"Applications/Some App.app/Contents/Resources/codex\");\n const claude = install(\"Users/dev/My Tools/bin/claude\");\n\n expect(HARNESS_RUNTIME_PROFILES.codex.matches(`${codex} --sandbox workspace-write`)).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.codex.matches(codex)).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.claude.matches(`${claude} --continue`)).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.claude.matches(`${codex} exec --cd /repo`)).toBe(false);\n });\n\n it(\"recognizes argv[0] by distribution name under a spaced directory\", () => {\n const copilot = install(\"opt/Home Brew/Caskroom/copilot-cli/1.0.60/copilot\");\n\n expect(HARNESS_RUNTIME_PROFILES.copilot.matches(`${copilot} --allow-all-tools`)).toBe(true);\n });\n\n it(\"does not treat arguments containing spaces as the executable\", () => {\n const vim = install(\"usr/bin/vim\");\n const codex = install(\"Applications/Some App.app/Contents/Resources/codex\");\n\n expect(HARNESS_RUNTIME_PROFILES.claude.matches(`${vim} My Notes/claude`)).toBe(false);\n expect(\n HARNESS_RUNTIME_PROFILES.claude.matches(`${codex} exec review the Other Dir/claude`),\n ).toBe(false);\n expect(HARNESS_RUNTIME_PROFILES.copilot.matches(`${vim} Some Dir/copilot-cli/notes.md`)).toBe(\n false,\n );\n expect(HARNESS_RUNTIME_PROFILES.claude.matches(\"/usr/bin/vim My Notes/claude\")).toBe(false);\n });\n\n it(\"recognizes spaced argv[0] in script-aware matchers\", () => {\n const pi = install(\"Users/dev/Node Tools/bin/pi\");\n const kiro = install(\"Applications/Kiro CLI.app/Contents/MacOS/kiro-cli\");\n const node = install(\"Applications/Dev Tools/node/bin/node\");\n\n expect(HARNESS_RUNTIME_PROFILES.pi.matches(`${pi} --model x`)).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.kiro.matches(`${kiro} chat`)).toBe(true);\n expect(\n HARNESS_RUNTIME_PROFILES.gemini_cli.matches(`${node} /Users/dev/.npm/bin/gemini --yolo`),\n ).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.pi.matches(`${node} /opt/pi-tools/script.js`)).toBe(false);\n });\n\n it(\"does not match agent words inside an executable directory\", () => {\n const node = install(\"opt/Dev pi gemini/bin/node\");\n\n expect(HARNESS_RUNTIME_PROFILES.pi.matches(`${node} /repo/script.js`)).toBe(false);\n expect(HARNESS_RUNTIME_PROFILES.gemini_cli.matches(`${node} /repo/script.js`)).toBe(false);\n expect(HARNESS_RUNTIME_PROFILES.gemini_cli.matches(`${node} /repo/bin/gemini`)).toBe(true);\n expect(HARNESS_RUNTIME_PROFILES.pi.matches(`${node} --title pi`)).toBe(true);\n });\n});\n"],"names":["fs","os","path","afterEach","beforeEach","describe","expect","it","HARNESS_RUNTIME_PROFILES","runtimeAgentMatchesHarness","antigravity_cli","toMatchObject","command","runtimeKind","discoveryAliases","matches","toBe","copilot","grok_cli","gemini_cli","root","install","relativePath","fullPath","join","mkdirSync","dirname","recursive","writeFileSync","mkdtempSync","tmpdir","rmSync","force","codex","claude","vim","pi","kiro","node"],"mappings":"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"}
@@ -1,10 +1,8 @@
1
1
  import { describe, expect, it } from "vitest";
2
- describe("durable-agent public domain", ()=>{
3
- it("exports a classified busy error without exposing prompt data", async ()=>{
4
- const api = await import("../../index.js");
5
- expect(api).toHaveProperty("DurableAgentBusyError");
6
- const ErrorType = api.DurableAgentBusyError;
7
- const error = new ErrorType("agent-id", "reviewer");
2
+ import { DurableAgentBusyError } from "../../durable/DurableAgent.js";
3
+ describe("durable-agent errors", ()=>{
4
+ it("classifies a busy error without exposing prompt data", ()=>{
5
+ const error = new DurableAgentBusyError("agent-id", "reviewer");
8
6
  expect(error).toMatchObject({
9
7
  name: "DurableAgentBusyError",
10
8
  code: "DURABLE_AGENT_BUSY",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/print/DurableAgent.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\n\ndescribe(\"durable-agent public domain\", () => {\n it(\"exports a classified busy error without exposing prompt data\", async () => {\n const api = (await import(\"../../index.js\")) as Record<string, unknown>;\n\n expect(api).toHaveProperty(\"DurableAgentBusyError\");\n const ErrorType = api.DurableAgentBusyError as new (\n agentId: string,\n name: string,\n ) => Error & {\n code: string;\n agentId: string;\n };\n const error = new ErrorType(\"agent-id\", \"reviewer\");\n\n expect(error).toMatchObject({\n name: \"DurableAgentBusyError\",\n code: \"DURABLE_AGENT_BUSY\",\n agentId: \"agent-id\",\n message: 'Durable agent \"reviewer\" is busy.',\n });\n });\n});\n"],"names":["describe","expect","it","api","toHaveProperty","ErrorType","DurableAgentBusyError","error","toMatchObject","name","code","agentId","message"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AAE9CF,SAAS,+BAA+B;IACtCE,GAAG,gEAAgE;QACjE,MAAMC,MAAO,MAAM,MAAM,CAAC;QAE1BF,OAAOE,KAAKC,cAAc,CAAC;QAC3B,MAAMC,YAAYF,IAAIG,qBAAqB;QAO3C,MAAMC,QAAQ,IAAIF,UAAU,YAAY;QAExCJ,OAAOM,OAAOC,aAAa,CAAC;YAC1BC,MAAM;YACNC,MAAM;YACNC,SAAS;YACTC,SAAS;QACX;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/__tests__/print/DurableAgent.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { DurableAgentBusyError } from \"../../durable/DurableAgent.js\";\n\ndescribe(\"durable-agent errors\", () => {\n it(\"classifies a busy error without exposing prompt data\", () => {\n const error = new DurableAgentBusyError(\"agent-id\", \"reviewer\");\n\n expect(error).toMatchObject({\n name: \"DurableAgentBusyError\",\n code: \"DURABLE_AGENT_BUSY\",\n agentId: \"agent-id\",\n message: 'Durable agent \"reviewer\" is busy.',\n });\n });\n});\n"],"names":["describe","expect","it","DurableAgentBusyError","error","toMatchObject","name","code","agentId","message"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AAC9C,SAASC,qBAAqB,QAAQ,gCAAgC;AAEtEH,SAAS,wBAAwB;IAC/BE,GAAG,wDAAwD;QACzD,MAAME,QAAQ,IAAID,sBAAsB,YAAY;QAEpDF,OAAOG,OAAOC,aAAa,CAAC;YAC1BC,MAAM;YACNC,MAAM;YACNC,SAAS;YACTC,SAAS;QACX;IACF;AACF"}
@@ -2,6 +2,7 @@ import fs from "fs";
2
2
  import os from "os";
3
3
  import path from "path";
4
4
  import { afterEach, describe, expect, it } from "vitest";
5
+ import { DurableAgentRepository } from "../../durable/DurableAgentRepository.js";
5
6
  const tempDirs = [];
6
7
  afterEach(()=>{
7
8
  for (const dir of tempDirs.splice(0))fs.rmSync(dir, {
@@ -9,11 +10,6 @@ afterEach(()=>{
9
10
  force: true
10
11
  });
11
12
  });
12
- async function loadStore() {
13
- const api = await import("../../index.js");
14
- expect(api).toHaveProperty("DurableAgentRepository");
15
- return api.DurableAgentRepository;
16
- }
17
13
  function fixture() {
18
14
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "durable-agent-store-"));
19
15
  tempDirs.push(root);
@@ -27,7 +23,6 @@ function fixture() {
27
23
  }
28
24
  describe("DurableAgentRepository create/list/resolve", ()=>{
29
25
  it("creates distinct durable identities with a canonical cwd and lists them", async ()=>{
30
- const DurableAgentRepository = await loadStore();
31
26
  const { cwd, dbPath } = fixture();
32
27
  const repository = new DurableAgentRepository({
33
28
  dbPath,
@@ -55,7 +50,6 @@ describe("DurableAgentRepository create/list/resolve", ()=>{
55
50
  expect(fs.existsSync(dbPath)).toBe(true);
56
51
  });
57
52
  it("resolves exact ids and names and rejects duplicate names", async ()=>{
58
- const DurableAgentRepository = await loadStore();
59
53
  const { cwd, dbPath } = fixture();
60
54
  const repository = new DurableAgentRepository({
61
55
  dbPath
@@ -79,7 +73,6 @@ describe("DurableAgentRepository create/list/resolve", ()=>{
79
73
  });
80
74
  });
81
75
  it("rejects a missing cwd", async ()=>{
82
- const DurableAgentRepository = await loadStore();
83
76
  const { root, dbPath } = fixture();
84
77
  const repository = new DurableAgentRepository({
85
78
  dbPath
@@ -94,7 +87,6 @@ describe("DurableAgentRepository create/list/resolve", ()=>{
94
87
  });
95
88
  describe("DurableAgentRepository run ownership", ()=>{
96
89
  it("fails fast when another exact owner is live and completes only for its token", async ()=>{
97
- const DurableAgentRepository = await loadStore();
98
90
  const { cwd, dbPath } = fixture();
99
91
  const live = new Map([
100
92
  [
@@ -144,7 +136,6 @@ describe("DurableAgentRepository run ownership", ()=>{
144
136
  });
145
137
  });
146
138
  it("retains busy for a live provider then recovers a dead run without signaling it", async ()=>{
147
- const DurableAgentRepository = await loadStore();
148
139
  const { cwd, dbPath } = fixture();
149
140
  const live = new Map([
150
141
  [
@@ -199,7 +190,6 @@ describe("DurableAgentRepository run ownership", ()=>{
199
190
  });
200
191
  });
201
192
  it("reconciles an interrupted run to degraded during list", async ()=>{
202
- const DurableAgentRepository = await loadStore();
203
193
  const { cwd, dbPath } = fixture();
204
194
  const live = new Map([
205
195
  [
@@ -237,7 +227,6 @@ describe("DurableAgentRepository run ownership", ()=>{
237
227
  });
238
228
  });
239
229
  it("rejects send acquisition when the bound cwd is replaced by a symlink", async ()=>{
240
- const DurableAgentRepository = await loadStore();
241
230
  const { root, cwd, dbPath } = fixture();
242
231
  const repository = new DurableAgentRepository({
243
232
  dbPath
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/print/DurableAgentRepository.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { afterEach, describe, expect, it } from \"vitest\";\n\nconst tempDirs: string[] = [];\n\nafterEach(() => {\n for (const dir of tempDirs.splice(0)) fs.rmSync(dir, { recursive: true, force: true });\n});\n\nasync function loadStore(): Promise<any> {\n const api = (await import(\"../../index.js\")) as Record<string, unknown>;\n expect(api).toHaveProperty(\"DurableAgentRepository\");\n return api.DurableAgentRepository;\n}\n\nfunction fixture(): { root: string; cwd: string; dbPath: string } {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), \"durable-agent-store-\"));\n tempDirs.push(root);\n const cwd = path.join(root, \"project\");\n fs.mkdirSync(cwd);\n return { root, cwd, dbPath: path.join(root, \"state\", \"agents.db\") };\n}\n\ndescribe(\"DurableAgentRepository create/list/resolve\", () => {\n it(\"creates distinct durable identities with a canonical cwd and lists them\", async () => {\n const DurableAgentRepository = await loadStore();\n const { cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({\n dbPath,\n now: () => new Date(\"2026-08-07T09:00:00Z\"),\n });\n\n const agent = await repository.create({ name: \"reviewer\", cwd });\n\n expect(agent).toMatchObject({\n name: \"reviewer\",\n provider: \"claude\",\n mode: \"durable\",\n cwd: fs.realpathSync(cwd),\n state: \"ready\",\n sessionHealth: \"uninitialized\",\n activeRun: null,\n });\n expect(agent.id).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.providerSessionId).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.id).not.toBe(agent.providerSessionId);\n expect(await repository.list()).toEqual([agent]);\n expect(fs.existsSync(dbPath)).toBe(true);\n });\n\n it(\"resolves exact ids and names and rejects duplicate names\", async () => {\n const DurableAgentRepository = await loadStore();\n const { cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n const agent = await repository.create({ name: \"Reviewer\", cwd });\n\n expect(await repository.resolve(agent.id)).toMatchObject({ id: agent.id });\n expect(await repository.resolve(\"reviewer\")).toMatchObject({ id: agent.id });\n expect(await repository.resolve(\"view\")).toBeNull();\n await expect(repository.create({ name: \"reviewer\", cwd })).rejects.toMatchObject({\n code: \"DURABLE_AGENT_NAME_CONFLICT\",\n });\n });\n\n it(\"rejects a missing cwd\", async () => {\n const DurableAgentRepository = await loadStore();\n const { root, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n\n await expect(\n repository.create({ name: \"missing\", cwd: path.join(root, \"missing\") }),\n ).rejects.toMatchObject({ code: \"DURABLE_AGENT_REPOSITORY\" });\n });\n});\n\ndescribe(\"DurableAgentRepository run ownership\", () => {\n it(\"fails fast when another exact owner is live and completes only for its token\", async () => {\n const DurableAgentRepository = await loadStore();\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([[process.pid, \"owner-start\"]]);\n const processInspector = {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n };\n const repository = new DurableAgentRepository({ dbPath, processInspector });\n const agent = await repository.create({ name: \"runner\", cwd });\n\n const acquired = await repository.acquireRun(agent.id);\n await expect(repository.acquireRun(agent.id)).rejects.toMatchObject({\n code: \"DURABLE_AGENT_BUSY\",\n });\n await expect(\n repository.completeRun(agent.id, \"wrong-token\", {\n status: \"succeeded\",\n exitCode: 0,\n summary: \"done\",\n sessionHealth: \"healthy\",\n }),\n ).rejects.toMatchObject({ code: \"DURABLE_AGENT_REPOSITORY\" });\n\n const completed = await repository.completeRun(agent.id, acquired.token, {\n status: \"succeeded\",\n exitCode: 0,\n summary: \"done\",\n sessionHealth: \"healthy\",\n });\n expect(completed).toMatchObject({ state: \"ready\", sessionHealth: \"healthy\", activeRun: null });\n });\n\n it(\"retains busy for a live provider then recovers a dead run without signaling it\", async () => {\n const DurableAgentRepository = await loadStore();\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([\n [process.pid, \"owner-start\"],\n [4242, \"provider-start\"],\n ]);\n const processInspector = {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n };\n const first = new DurableAgentRepository({ dbPath, processInspector });\n const agent = await first.create({ name: \"recoverable\", cwd });\n const run = await first.acquireRun(agent.id);\n await first.recordProviderProcess(agent.id, run.token, {\n pid: 4242,\n startedAt: \"provider-start\",\n });\n\n live.delete(process.pid);\n await expect(first.acquireRun(agent.id)).rejects.toMatchObject({ code: \"DURABLE_AGENT_BUSY\" });\n\n live.delete(4242);\n live.set(process.pid, \"replacement-owner-start\");\n const recovered = await first.acquireRun(agent.id);\n expect(recovered.agent).toMatchObject({\n state: \"running\",\n lastResult: { status: \"interrupted\" },\n });\n await first.completeRun(agent.id, recovered.token, {\n status: \"failed\",\n exitCode: 1,\n summary: \"failed\",\n sessionHealth: \"unknown\",\n });\n });\n\n it(\"reconciles an interrupted run to degraded during list\", async () => {\n const DurableAgentRepository = await loadStore();\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([[process.pid, \"owner-start\"]]);\n const repository = new DurableAgentRepository({\n dbPath,\n incompleteLockGraceMs: 10,\n processInspector: {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n },\n });\n const agent = await repository.create({ name: \"crashed\", cwd });\n await repository.acquireRun(agent.id);\n live.clear();\n\n const listed = await repository.list();\n\n expect(listed[0]).toMatchObject({\n state: \"degraded\",\n sessionHealth: \"unknown\",\n activeRun: null,\n lastResult: { status: \"interrupted\" },\n });\n });\n\n it(\"rejects send acquisition when the bound cwd is replaced by a symlink\", async () => {\n const DurableAgentRepository = await loadStore();\n const { root, cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n const agent = await repository.create({ name: \"bound\", cwd });\n const moved = path.join(root, \"moved-project\");\n const other = path.join(root, \"other-project\");\n fs.renameSync(cwd, moved);\n fs.mkdirSync(other);\n fs.symlinkSync(other, cwd);\n\n await expect(repository.acquireRun(agent.id)).rejects.toMatchObject({\n code: \"DURABLE_AGENT_REPOSITORY\",\n });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","tempDirs","dir","splice","rmSync","recursive","force","loadStore","api","toHaveProperty","DurableAgentRepository","fixture","root","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","dbPath","repository","now","Date","agent","create","name","toMatchObject","provider","mode","realpathSync","state","sessionHealth","activeRun","id","toMatch","providerSessionId","not","toBe","list","toEqual","existsSync","resolve","toBeNull","rejects","code","live","Map","process","pid","processInspector","getIdentity","startedAt","get","acquired","acquireRun","completeRun","status","exitCode","summary","completed","token","first","run","recordProviderProcess","delete","set","recovered","lastResult","incompleteLockGraceMs","clear","listed","moved","other","renameSync","symlinkSync"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/print/DurableAgentRepository.test.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { afterEach, describe, expect, it } from \"vitest\";\nimport { DurableAgentRepository } from \"../../durable/DurableAgentRepository.js\";\n\nconst tempDirs: string[] = [];\n\nafterEach(() => {\n for (const dir of tempDirs.splice(0)) fs.rmSync(dir, { recursive: true, force: true });\n});\n\nfunction fixture(): { root: string; cwd: string; dbPath: string } {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), \"durable-agent-store-\"));\n tempDirs.push(root);\n const cwd = path.join(root, \"project\");\n fs.mkdirSync(cwd);\n return { root, cwd, dbPath: path.join(root, \"state\", \"agents.db\") };\n}\n\ndescribe(\"DurableAgentRepository create/list/resolve\", () => {\n it(\"creates distinct durable identities with a canonical cwd and lists them\", async () => {\n const { cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({\n dbPath,\n now: () => new Date(\"2026-08-07T09:00:00Z\"),\n });\n\n const agent = await repository.create({ name: \"reviewer\", cwd });\n\n expect(agent).toMatchObject({\n name: \"reviewer\",\n provider: \"claude\",\n mode: \"durable\",\n cwd: fs.realpathSync(cwd),\n state: \"ready\",\n sessionHealth: \"uninitialized\",\n activeRun: null,\n });\n expect(agent.id).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.providerSessionId).toMatch(/^[0-9a-f-]{36}$/);\n expect(agent.id).not.toBe(agent.providerSessionId);\n expect(await repository.list()).toEqual([agent]);\n expect(fs.existsSync(dbPath)).toBe(true);\n });\n\n it(\"resolves exact ids and names and rejects duplicate names\", async () => {\n const { cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n const agent = await repository.create({ name: \"Reviewer\", cwd });\n\n expect(await repository.resolve(agent.id)).toMatchObject({ id: agent.id });\n expect(await repository.resolve(\"reviewer\")).toMatchObject({ id: agent.id });\n expect(await repository.resolve(\"view\")).toBeNull();\n await expect(repository.create({ name: \"reviewer\", cwd })).rejects.toMatchObject({\n code: \"DURABLE_AGENT_NAME_CONFLICT\",\n });\n });\n\n it(\"rejects a missing cwd\", async () => {\n const { root, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n\n await expect(\n repository.create({ name: \"missing\", cwd: path.join(root, \"missing\") }),\n ).rejects.toMatchObject({ code: \"DURABLE_AGENT_REPOSITORY\" });\n });\n});\n\ndescribe(\"DurableAgentRepository run ownership\", () => {\n it(\"fails fast when another exact owner is live and completes only for its token\", async () => {\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([[process.pid, \"owner-start\"]]);\n const processInspector = {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n };\n const repository = new DurableAgentRepository({ dbPath, processInspector });\n const agent = await repository.create({ name: \"runner\", cwd });\n\n const acquired = await repository.acquireRun(agent.id);\n await expect(repository.acquireRun(agent.id)).rejects.toMatchObject({\n code: \"DURABLE_AGENT_BUSY\",\n });\n await expect(\n repository.completeRun(agent.id, \"wrong-token\", {\n status: \"succeeded\",\n exitCode: 0,\n summary: \"done\",\n sessionHealth: \"healthy\",\n }),\n ).rejects.toMatchObject({ code: \"DURABLE_AGENT_REPOSITORY\" });\n\n const completed = await repository.completeRun(agent.id, acquired.token, {\n status: \"succeeded\",\n exitCode: 0,\n summary: \"done\",\n sessionHealth: \"healthy\",\n });\n expect(completed).toMatchObject({ state: \"ready\", sessionHealth: \"healthy\", activeRun: null });\n });\n\n it(\"retains busy for a live provider then recovers a dead run without signaling it\", async () => {\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([\n [process.pid, \"owner-start\"],\n [4242, \"provider-start\"],\n ]);\n const processInspector = {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n };\n const first = new DurableAgentRepository({ dbPath, processInspector });\n const agent = await first.create({ name: \"recoverable\", cwd });\n const run = await first.acquireRun(agent.id);\n await first.recordProviderProcess(agent.id, run.token, {\n pid: 4242,\n startedAt: \"provider-start\",\n });\n\n live.delete(process.pid);\n await expect(first.acquireRun(agent.id)).rejects.toMatchObject({ code: \"DURABLE_AGENT_BUSY\" });\n\n live.delete(4242);\n live.set(process.pid, \"replacement-owner-start\");\n const recovered = await first.acquireRun(agent.id);\n expect(recovered.agent).toMatchObject({\n state: \"running\",\n lastResult: { status: \"interrupted\" },\n });\n await first.completeRun(agent.id, recovered.token, {\n status: \"failed\",\n exitCode: 1,\n summary: \"failed\",\n sessionHealth: \"unknown\",\n });\n });\n\n it(\"reconciles an interrupted run to degraded during list\", async () => {\n const { cwd, dbPath } = fixture();\n const live = new Map<number, string>([[process.pid, \"owner-start\"]]);\n const repository = new DurableAgentRepository({\n dbPath,\n incompleteLockGraceMs: 10,\n processInspector: {\n getIdentity: (pid: number) => {\n const startedAt = live.get(pid);\n return startedAt ? { pid, startedAt } : null;\n },\n },\n });\n const agent = await repository.create({ name: \"crashed\", cwd });\n await repository.acquireRun(agent.id);\n live.clear();\n\n const listed = await repository.list();\n\n expect(listed[0]).toMatchObject({\n state: \"degraded\",\n sessionHealth: \"unknown\",\n activeRun: null,\n lastResult: { status: \"interrupted\" },\n });\n });\n\n it(\"rejects send acquisition when the bound cwd is replaced by a symlink\", async () => {\n const { root, cwd, dbPath } = fixture();\n const repository = new DurableAgentRepository({ dbPath });\n const agent = await repository.create({ name: \"bound\", cwd });\n const moved = path.join(root, \"moved-project\");\n const other = path.join(root, \"other-project\");\n fs.renameSync(cwd, moved);\n fs.mkdirSync(other);\n fs.symlinkSync(other, cwd);\n\n await expect(repository.acquireRun(agent.id)).rejects.toMatchObject({\n code: \"DURABLE_AGENT_REPOSITORY\",\n });\n });\n});\n"],"names":["fs","os","path","afterEach","describe","expect","it","DurableAgentRepository","tempDirs","dir","splice","rmSync","recursive","force","fixture","root","mkdtempSync","join","tmpdir","push","cwd","mkdirSync","dbPath","repository","now","Date","agent","create","name","toMatchObject","provider","mode","realpathSync","state","sessionHealth","activeRun","id","toMatch","providerSessionId","not","toBe","list","toEqual","existsSync","resolve","toBeNull","rejects","code","live","Map","process","pid","processInspector","getIdentity","startedAt","get","acquired","acquireRun","completeRun","status","exitCode","summary","completed","token","first","run","recordProviderProcess","delete","set","recovered","lastResult","incompleteLockGraceMs","clear","listed","moved","other","renameSync","symlinkSync"],"mappings":"AAAA,OAAOA,QAAQ,KAAK;AACpB,OAAOC,QAAQ,KAAK;AACpB,OAAOC,UAAU,OAAO;AACxB,SAASC,SAAS,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AACzD,SAASC,sBAAsB,QAAQ,0CAA0C;AAEjF,MAAMC,WAAqB,EAAE;AAE7BL,UAAU;IACR,KAAK,MAAMM,OAAOD,SAASE,MAAM,CAAC,GAAIV,GAAGW,MAAM,CAACF,KAAK;QAAEG,WAAW;QAAMC,OAAO;IAAK;AACtF;AAEA,SAASC;IACP,MAAMC,OAAOf,GAAGgB,WAAW,CAACd,KAAKe,IAAI,CAAChB,GAAGiB,MAAM,IAAI;IACnDV,SAASW,IAAI,CAACJ;IACd,MAAMK,MAAMlB,KAAKe,IAAI,CAACF,MAAM;IAC5Bf,GAAGqB,SAAS,CAACD;IACb,OAAO;QAAEL;QAAMK;QAAKE,QAAQpB,KAAKe,IAAI,CAACF,MAAM,SAAS;IAAa;AACpE;AAEAX,SAAS,8CAA8C;IACrDE,GAAG,2EAA2E;QAC5E,MAAM,EAAEc,GAAG,EAAEE,MAAM,EAAE,GAAGR;QACxB,MAAMS,aAAa,IAAIhB,uBAAuB;YAC5Ce;YACAE,KAAK,IAAM,IAAIC,KAAK;QACtB;QAEA,MAAMC,QAAQ,MAAMH,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAYR;QAAI;QAE9Df,OAAOqB,OAAOG,aAAa,CAAC;YAC1BD,MAAM;YACNE,UAAU;YACVC,MAAM;YACNX,KAAKpB,GAAGgC,YAAY,CAACZ;YACrBa,OAAO;YACPC,eAAe;YACfC,WAAW;QACb;QACA9B,OAAOqB,MAAMU,EAAE,EAAEC,OAAO,CAAC;QACzBhC,OAAOqB,MAAMY,iBAAiB,EAAED,OAAO,CAAC;QACxChC,OAAOqB,MAAMU,EAAE,EAAEG,GAAG,CAACC,IAAI,CAACd,MAAMY,iBAAiB;QACjDjC,OAAO,MAAMkB,WAAWkB,IAAI,IAAIC,OAAO,CAAC;YAAChB;SAAM;QAC/CrB,OAAOL,GAAG2C,UAAU,CAACrB,SAASkB,IAAI,CAAC;IACrC;IAEAlC,GAAG,4DAA4D;QAC7D,MAAM,EAAEc,GAAG,EAAEE,MAAM,EAAE,GAAGR;QACxB,MAAMS,aAAa,IAAIhB,uBAAuB;YAAEe;QAAO;QACvD,MAAMI,QAAQ,MAAMH,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAYR;QAAI;QAE9Df,OAAO,MAAMkB,WAAWqB,OAAO,CAAClB,MAAMU,EAAE,GAAGP,aAAa,CAAC;YAAEO,IAAIV,MAAMU,EAAE;QAAC;QACxE/B,OAAO,MAAMkB,WAAWqB,OAAO,CAAC,aAAaf,aAAa,CAAC;YAAEO,IAAIV,MAAMU,EAAE;QAAC;QAC1E/B,OAAO,MAAMkB,WAAWqB,OAAO,CAAC,SAASC,QAAQ;QACjD,MAAMxC,OAAOkB,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAYR;QAAI,IAAI0B,OAAO,CAACjB,aAAa,CAAC;YAC/EkB,MAAM;QACR;IACF;IAEAzC,GAAG,yBAAyB;QAC1B,MAAM,EAAES,IAAI,EAAEO,MAAM,EAAE,GAAGR;QACzB,MAAMS,aAAa,IAAIhB,uBAAuB;YAAEe;QAAO;QAEvD,MAAMjB,OACJkB,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAWR,KAAKlB,KAAKe,IAAI,CAACF,MAAM;QAAW,IACrE+B,OAAO,CAACjB,aAAa,CAAC;YAAEkB,MAAM;QAA2B;IAC7D;AACF;AAEA3C,SAAS,wCAAwC;IAC/CE,GAAG,gFAAgF;QACjF,MAAM,EAAEc,GAAG,EAAEE,MAAM,EAAE,GAAGR;QACxB,MAAMkC,OAAO,IAAIC,IAAoB;YAAC;gBAACC,QAAQC,GAAG;gBAAE;aAAc;SAAC;QACnE,MAAMC,mBAAmB;YACvBC,aAAa,CAACF;gBACZ,MAAMG,YAAYN,KAAKO,GAAG,CAACJ;gBAC3B,OAAOG,YAAY;oBAAEH;oBAAKG;gBAAU,IAAI;YAC1C;QACF;QACA,MAAM/B,aAAa,IAAIhB,uBAAuB;YAAEe;YAAQ8B;QAAiB;QACzE,MAAM1B,QAAQ,MAAMH,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAUR;QAAI;QAE5D,MAAMoC,WAAW,MAAMjC,WAAWkC,UAAU,CAAC/B,MAAMU,EAAE;QACrD,MAAM/B,OAAOkB,WAAWkC,UAAU,CAAC/B,MAAMU,EAAE,GAAGU,OAAO,CAACjB,aAAa,CAAC;YAClEkB,MAAM;QACR;QACA,MAAM1C,OACJkB,WAAWmC,WAAW,CAAChC,MAAMU,EAAE,EAAE,eAAe;YAC9CuB,QAAQ;YACRC,UAAU;YACVC,SAAS;YACT3B,eAAe;QACjB,IACAY,OAAO,CAACjB,aAAa,CAAC;YAAEkB,MAAM;QAA2B;QAE3D,MAAMe,YAAY,MAAMvC,WAAWmC,WAAW,CAAChC,MAAMU,EAAE,EAAEoB,SAASO,KAAK,EAAE;YACvEJ,QAAQ;YACRC,UAAU;YACVC,SAAS;YACT3B,eAAe;QACjB;QACA7B,OAAOyD,WAAWjC,aAAa,CAAC;YAAEI,OAAO;YAASC,eAAe;YAAWC,WAAW;QAAK;IAC9F;IAEA7B,GAAG,kFAAkF;QACnF,MAAM,EAAEc,GAAG,EAAEE,MAAM,EAAE,GAAGR;QACxB,MAAMkC,OAAO,IAAIC,IAAoB;YACnC;gBAACC,QAAQC,GAAG;gBAAE;aAAc;YAC5B;gBAAC;gBAAM;aAAiB;SACzB;QACD,MAAMC,mBAAmB;YACvBC,aAAa,CAACF;gBACZ,MAAMG,YAAYN,KAAKO,GAAG,CAACJ;gBAC3B,OAAOG,YAAY;oBAAEH;oBAAKG;gBAAU,IAAI;YAC1C;QACF;QACA,MAAMU,QAAQ,IAAIzD,uBAAuB;YAAEe;YAAQ8B;QAAiB;QACpE,MAAM1B,QAAQ,MAAMsC,MAAMrC,MAAM,CAAC;YAAEC,MAAM;YAAeR;QAAI;QAC5D,MAAM6C,MAAM,MAAMD,MAAMP,UAAU,CAAC/B,MAAMU,EAAE;QAC3C,MAAM4B,MAAME,qBAAqB,CAACxC,MAAMU,EAAE,EAAE6B,IAAIF,KAAK,EAAE;YACrDZ,KAAK;YACLG,WAAW;QACb;QAEAN,KAAKmB,MAAM,CAACjB,QAAQC,GAAG;QACvB,MAAM9C,OAAO2D,MAAMP,UAAU,CAAC/B,MAAMU,EAAE,GAAGU,OAAO,CAACjB,aAAa,CAAC;YAAEkB,MAAM;QAAqB;QAE5FC,KAAKmB,MAAM,CAAC;QACZnB,KAAKoB,GAAG,CAAClB,QAAQC,GAAG,EAAE;QACtB,MAAMkB,YAAY,MAAML,MAAMP,UAAU,CAAC/B,MAAMU,EAAE;QACjD/B,OAAOgE,UAAU3C,KAAK,EAAEG,aAAa,CAAC;YACpCI,OAAO;YACPqC,YAAY;gBAAEX,QAAQ;YAAc;QACtC;QACA,MAAMK,MAAMN,WAAW,CAAChC,MAAMU,EAAE,EAAEiC,UAAUN,KAAK,EAAE;YACjDJ,QAAQ;YACRC,UAAU;YACVC,SAAS;YACT3B,eAAe;QACjB;IACF;IAEA5B,GAAG,yDAAyD;QAC1D,MAAM,EAAEc,GAAG,EAAEE,MAAM,EAAE,GAAGR;QACxB,MAAMkC,OAAO,IAAIC,IAAoB;YAAC;gBAACC,QAAQC,GAAG;gBAAE;aAAc;SAAC;QACnE,MAAM5B,aAAa,IAAIhB,uBAAuB;YAC5Ce;YACAiD,uBAAuB;YACvBnB,kBAAkB;gBAChBC,aAAa,CAACF;oBACZ,MAAMG,YAAYN,KAAKO,GAAG,CAACJ;oBAC3B,OAAOG,YAAY;wBAAEH;wBAAKG;oBAAU,IAAI;gBAC1C;YACF;QACF;QACA,MAAM5B,QAAQ,MAAMH,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAAWR;QAAI;QAC7D,MAAMG,WAAWkC,UAAU,CAAC/B,MAAMU,EAAE;QACpCY,KAAKwB,KAAK;QAEV,MAAMC,SAAS,MAAMlD,WAAWkB,IAAI;QAEpCpC,OAAOoE,MAAM,CAAC,EAAE,EAAE5C,aAAa,CAAC;YAC9BI,OAAO;YACPC,eAAe;YACfC,WAAW;YACXmC,YAAY;gBAAEX,QAAQ;YAAc;QACtC;IACF;IAEArD,GAAG,wEAAwE;QACzE,MAAM,EAAES,IAAI,EAAEK,GAAG,EAAEE,MAAM,EAAE,GAAGR;QAC9B,MAAMS,aAAa,IAAIhB,uBAAuB;YAAEe;QAAO;QACvD,MAAMI,QAAQ,MAAMH,WAAWI,MAAM,CAAC;YAAEC,MAAM;YAASR;QAAI;QAC3D,MAAMsD,QAAQxE,KAAKe,IAAI,CAACF,MAAM;QAC9B,MAAM4D,QAAQzE,KAAKe,IAAI,CAACF,MAAM;QAC9Bf,GAAG4E,UAAU,CAACxD,KAAKsD;QACnB1E,GAAGqB,SAAS,CAACsD;QACb3E,GAAG6E,WAAW,CAACF,OAAOvD;QAEtB,MAAMf,OAAOkB,WAAWkC,UAAU,CAAC/B,MAAMU,EAAE,GAAGU,OAAO,CAACjB,aAAa,CAAC;YAClEkB,MAAM;QACR;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/runtime/ManagedAgentRuntime.test.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport {\n AgentNameInUseError,\n AgentPidPollTimeoutError,\n AgentTerminalNotFoundError,\n DEFAULT_PID_POLL_TIMEOUT_MS,\n focusAgent,\n sendAgentPrompt,\n startAgent,\n stopAgent,\n TmuxUnavailableError,\n type StartAgentOptions,\n} from \"../../runtime/ManagedAgentRuntime.js\";\nimport type { AgentInfo } from \"../../adapters/AgentAdapter.js\";\nimport type { AgentRegistry, RegistryEntry } from \"../../utils/AgentRegistry.js\";\nimport type { TmuxManager } from \"../../terminal/TmuxManager.js\";\nimport type { InteractiveAgentRuntime } from \"../../runtime/types.js\";\n\nfunction makeAgent(overrides: Partial<AgentInfo> = {}): AgentInfo {\n return {\n name: \"repo-a\",\n type: \"claude\",\n status: \"running\" as AgentInfo[\"status\"],\n summary: \"Working\",\n pid: 10,\n projectPath: \"/repo\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n lastActive: new Date(\"2026-05-14T00:00:00.000Z\"),\n ...overrides,\n };\n}\n\nfunction makeTmux(over: Partial<TmuxManager> = {}): TmuxManager {\n return {\n isAvailable: vi.fn().mockResolvedValue(true),\n sessionExists: vi.fn().mockResolvedValue(false),\n createSession: vi.fn().mockResolvedValue(undefined),\n sendKeys: vi.fn().mockResolvedValue(undefined),\n killSession: vi.fn().mockResolvedValue(undefined),\n findAgentPid: vi.fn().mockResolvedValue(12345),\n ...over,\n } as unknown as TmuxManager;\n}\n\nfunction makeRegistry(over: Partial<AgentRegistry> = {}): AgentRegistry {\n return {\n prune: vi.fn(),\n lookup: vi.fn().mockReturnValue(null),\n list: vi.fn().mockReturnValue([]),\n register: vi.fn(),\n isAlive: vi.fn().mockReturnValue(false),\n ...over,\n } as unknown as AgentRegistry;\n}\n\nfunction makeRuntime(over: Partial<InteractiveAgentRuntime> = {}): InteractiveAgentRuntime {\n return {\n provider: \"herdr\",\n isAvailable: vi.fn().mockResolvedValue({ ok: true, insideRuntime: false }),\n startAgent: vi.fn().mockResolvedValue({\n pid: 12345,\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n }),\n send: vi.fn().mockResolvedValue(undefined),\n wait: vi.fn().mockResolvedValue(undefined),\n readOutput: vi.fn().mockResolvedValue(\"done\\n\"),\n focus: vi.fn().mockResolvedValue(true),\n stop: vi.fn().mockResolvedValue(undefined),\n ...over,\n } as unknown as InteractiveAgentRuntime;\n}\n\nconst startOpts: StartAgentOptions = {\n type: \"claude\",\n name: \"agent1\",\n cwd: \"/work\",\n pollIntervalMs: 1,\n pollTimeoutMs: 50,\n};\n\ndescribe(\"managed agent runtime defaults\", () => {\n it(\"allows slower agent startup before PID polling times out\", () => {\n expect(DEFAULT_PID_POLL_TIMEOUT_MS).toBe(15_000);\n });\n});\n\ndescribe(\"stopAgent\", () => {\n it(\"sends SIGTERM to the agent PID\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(killProcess).toHaveBeenCalledWith(123, \"SIGTERM\");\n expect(tmux.killSession).not.toHaveBeenCalled();\n expect(result).toEqual({\n agentName: \"repo-a\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: null,\n });\n });\n\n it(\"kills the registry tmux session when present\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: { session: \"repo-a\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(killProcess).toHaveBeenCalledWith(123, \"SIGTERM\");\n expect(tmux.killSession).toHaveBeenCalledWith(\"repo-a\");\n expect(result.runtimeRef).toEqual({ session: \"repo-a\" });\n });\n\n it(\"delegates Herdr-backed agents to Herdr without sending SIGTERM directly\", async () => {\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"\",\n sessionFilePath: \"\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n runtime,\n registry,\n killProcess,\n });\n\n expect(runtime.stop).toHaveBeenCalledWith(\n expect.objectContaining({\n runtimeRef: { session: \"default\", paneId: \"w1:p2\" },\n }),\n );\n expect(killProcess).not.toHaveBeenCalled();\n expect(result.runtime).toBe(\"herdr\");\n });\n\n it(\"still kills tmux session when the process is already gone\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: { session: \"repo-a\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const error = Object.assign(new Error(\"gone\"), { code: \"ESRCH\" });\n const killProcess = vi.fn(() => {\n throw error;\n });\n\n await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(tmux.killSession).toHaveBeenCalledWith(\"repo-a\");\n });\n\n it(\"rethrows unexpected process kill errors\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const error = Object.assign(new Error(\"permission denied\"), { code: \"EPERM\" });\n const killProcess = vi.fn(() => {\n throw error;\n });\n\n await expect(\n stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n }),\n ).rejects.toThrow(\"permission denied\");\n\n expect(tmux.killSession).not.toHaveBeenCalled();\n });\n});\n\ndescribe(\"focusAgent\", () => {\n it(\"delegates Herdr-backed agents to Herdr focus\", async () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"repo-a\" };\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 10,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const focusManager = {\n findTerminal: vi.fn(),\n focusTerminal: vi.fn(),\n };\n\n const result = await focusAgent(makeAgent(), { registry, runtime, focusManager });\n\n expect(runtime.focus).toHaveBeenCalledWith(expect.objectContaining({ runtimeRef }));\n expect(focusManager.findTerminal).not.toHaveBeenCalled();\n expect(result).toEqual({ focused: true });\n });\n\n it(\"reports when a tmux-backed terminal cannot be found\", async () => {\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(null),\n focusTerminal: vi.fn(),\n };\n\n const result = await focusAgent(makeAgent({ pid: 10 }), {\n registry: makeRegistry(),\n focusManager,\n });\n\n expect(focusManager.findTerminal).toHaveBeenCalledWith(10);\n expect(focusManager.focusTerminal).not.toHaveBeenCalled();\n expect(result).toEqual({ focused: false, reason: \"terminal-not-found\" });\n });\n\n it(\"reports when focusing a found terminal fails\", async () => {\n const location = { type: \"tmux\", identifier: \"1:1\", tty: \"/dev/ttys030\" };\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(location),\n focusTerminal: vi.fn().mockResolvedValue(false),\n };\n\n const result = await focusAgent(makeAgent({ pid: 10 }), {\n registry: makeRegistry(),\n focusManager,\n });\n\n expect(focusManager.focusTerminal).toHaveBeenCalledWith(location);\n expect(result).toEqual({ focused: false, reason: \"focus-failed\" });\n });\n});\n\ndescribe(\"sendAgentPrompt\", () => {\n it(\"sends Herdr-backed prompts through Herdr\", async () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"repo-a\" };\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 10,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const focusManager = {\n findTerminal: vi.fn(),\n };\n\n await sendAgentPrompt(makeAgent(), \"hello\", {\n registry,\n runtime,\n focusManager,\n });\n\n expect(runtime.send).toHaveBeenCalledWith(\n expect.objectContaining({ runtimeRef, prompt: \"hello\" }),\n expect.objectContaining({ focusManager }),\n );\n expect(focusManager.findTerminal).not.toHaveBeenCalled();\n });\n\n it(\"writes tmux-backed prompts to the resolved terminal\", async () => {\n const location = { type: \"tmux\", identifier: \"1:1\", tty: \"/dev/ttys030\" };\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(location),\n };\n const writer = vi.fn().mockResolvedValue(undefined);\n\n await sendAgentPrompt(makeAgent({ pid: 10 }), \"hello\", {\n registry: makeRegistry(),\n focusManager,\n writer,\n });\n\n expect(focusManager.findTerminal).toHaveBeenCalledWith(10);\n expect(writer).toHaveBeenCalledWith(location, \"hello\");\n });\n\n it(\"throws when a tmux-backed terminal cannot be found\", async () => {\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(null),\n };\n\n const err = await sendAgentPrompt(makeAgent({ pid: 10 }), \"hello\", {\n registry: makeRegistry(),\n focusManager,\n }).catch((error) => error);\n\n expect(err).toBeInstanceOf(AgentTerminalNotFoundError);\n expect(err.message).toBe('Cannot find terminal for agent \"repo-a\" (PID: 10).');\n });\n});\n\ndescribe(\"startAgent\", () => {\n it(\"happy path: creates session, sends command, polls, registers, returns entry\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, pollTimeoutMs: 250 }, { tmux, registry });\n\n expect(tmux.createSession).toHaveBeenCalledWith(\"agent1\", \"/work\");\n expect(tmux.sendKeys).toHaveBeenCalledWith(\"agent1\", \"claude\");\n expect(registry.prune).toHaveBeenCalled();\n expect(registry.register).toHaveBeenCalledOnce();\n expect(entry).toMatchObject({\n name: \"agent1\",\n type: \"claude\",\n pid: 12345,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n cwd: \"/work\",\n pinned: false,\n });\n expect(entry.startedAt).toMatch(/^\\d{4}-\\d{2}-\\d{2}T/);\n });\n\n it(\"throws TmuxUnavailableError when tmux is missing\", async () => {\n const tmux = makeTmux({\n isAvailable: vi.fn().mockResolvedValue(false),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n await expect(startAgent(startOpts, { tmux, registry })).rejects.toBeInstanceOf(\n TmuxUnavailableError,\n );\n expect(tmux.createSession).not.toHaveBeenCalled();\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"starts Herdr-backed agents through the configured runtime and persists runtime metadata\", async () => {\n const runtime = makeRuntime();\n const registry = makeRegistry();\n\n const entry = await startAgent(\n { ...startOpts, runtimeProvider: \"herdr\" },\n { runtime, registry },\n );\n\n expect(runtime.isAvailable).toHaveBeenCalledOnce();\n expect(runtime.startAgent).toHaveBeenCalledWith({\n name: \"agent1\",\n cwd: \"/work\",\n kind: \"claude\",\n args: [],\n timeoutMs: 50,\n });\n expect(entry).toMatchObject({\n name: \"agent1\",\n type: \"claude\",\n pid: 12345,\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n cwd: \"/work\",\n pinned: false,\n });\n expect(registry.register).toHaveBeenCalledWith(\n expect.objectContaining({\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n }),\n );\n });\n\n it(\"fails Herdr starts when the configured runtime is unavailable\", async () => {\n const runtime = makeRuntime({\n isAvailable: vi.fn().mockResolvedValue({\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n }),\n });\n const registry = makeRegistry();\n\n await expect(\n startAgent({ ...startOpts, runtimeProvider: \"herdr\" }, { runtime, registry }),\n ).rejects.toMatchObject({\n name: \"AgentRuntimeUnavailableError\",\n provider: \"herdr\",\n reason: \"binary-missing\",\n });\n expect(runtime.startAgent).not.toHaveBeenCalled();\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"throws AgentNameInUseError when registry already has a live entry\", async () => {\n const tmux = makeTmux();\n const liveEntry: RegistryEntry = {\n name: \"agent1\",\n type: \"claude\",\n pid: 999,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n cwd: \"/old\",\n startedAt: \"2026-01-01T00:00:00.000Z\",\n };\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue(liveEntry),\n } as Partial<AgentRegistry>);\n\n const err = await startAgent(startOpts, { tmux, registry }).catch((e) => e);\n expect(err).toBeInstanceOf(AgentNameInUseError);\n expect(err.pid).toBe(999);\n expect(tmux.createSession).not.toHaveBeenCalled();\n });\n\n it(\"detects the agent PID when the agent is installed under a path containing spaces\", async () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), \"managed-runtime-spaces-\"));\n try {\n const codexPath = path.join(root, \"Applications/Some App.app/Contents/Resources/codex\");\n fs.mkdirSync(path.dirname(codexPath), { recursive: true });\n fs.writeFileSync(codexPath, \"\");\n const processTree = [\n { pid: 100, command: \"-zsh\" },\n { pid: 200, command: `${codexPath} --sandbox workspace-write` },\n { pid: 300, command: \"/usr/local/bin/node /opt/mcp/server.js\" },\n ];\n const findAgentPid = vi.fn(\n async (_session: string, matches: (psCommand: string) => boolean) =>\n processTree.filter((proc) => matches(proc.command)).at(-1)?.pid ?? null,\n );\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, type: \"codex\" }, { tmux, registry });\n\n expect(tmux.sendKeys).toHaveBeenCalledWith(\"agent1\", \"codex\");\n expect(entry).toMatchObject({ type: \"codex\", pid: 200 });\n } finally {\n fs.rmSync(root, { recursive: true, force: true });\n }\n });\n\n it(\"replaces orphan tmux session and calls onWarning\", async () => {\n const tmux = makeTmux({\n sessionExists: vi.fn().mockResolvedValue(true),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n const onWarning = vi.fn();\n\n await startAgent(startOpts, { tmux, registry, onWarning });\n\n expect(onWarning).toHaveBeenCalledOnce();\n expect(onWarning.mock.calls[0][0]).toContain(\"agent1\");\n expect(tmux.killSession).toHaveBeenCalledWith(\"agent1\");\n expect(tmux.createSession).toHaveBeenCalledWith(\"agent1\", \"/work\");\n });\n\n it(\"on PID poll timeout: kills session and throws AgentPidPollTimeoutError\", async () => {\n const tmux = makeTmux({\n findAgentPid: vi.fn().mockResolvedValue(null),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const err = await startAgent(startOpts, { tmux, registry }).catch((e) => e);\n\n expect(err).toBeInstanceOf(AgentPidPollTimeoutError);\n expect(err.command).toBe(\"claude\");\n expect(err.timeoutMs).toBe(50);\n expect(tmux.killSession).toHaveBeenLastCalledWith(\"agent1\");\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"keeps polling until findAgentPid returns a PID\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(null)\n .mockResolvedValueOnce(null)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, pollTimeoutMs: 250 }, { tmux, registry });\n\n expect(findAgentPid).toHaveBeenCalledTimes(7);\n expect(entry.pid).toBe(42);\n });\n\n it(\"waits for the launched process PID to stabilize before registering\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent(startOpts, { tmux, registry });\n\n expect(findAgentPid).toHaveBeenCalledTimes(8);\n expect(entry.pid).toBe(200);\n expect(registry.register).toHaveBeenCalledWith(expect.objectContaining({ pid: 200 }));\n });\n\n it(\"treats an unstabilized PID as a poll timeout\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const err = await startAgent({ ...startOpts, pollTimeoutMs: 3 }, { tmux, registry }).catch(\n (e) => e,\n );\n\n expect(err).toBeInstanceOf(AgentPidPollTimeoutError);\n expect(registry.register).not.toHaveBeenCalled();\n expect(tmux.killSession).toHaveBeenLastCalledWith(\"agent1\");\n });\n\n it(\"prunes registry before checking for name collision\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const order: string[] = [];\n (registry.prune as any).mockImplementation(() => order.push(\"prune\"));\n (registry.lookup as any).mockImplementation(() => {\n order.push(\"lookup\");\n return null;\n });\n\n await startAgent(startOpts, { tmux, registry });\n expect(order).toEqual([\"prune\", \"lookup\"]);\n });\n});\n"],"names":["fs","os","path","AgentNameInUseError","AgentPidPollTimeoutError","AgentTerminalNotFoundError","DEFAULT_PID_POLL_TIMEOUT_MS","focusAgent","sendAgentPrompt","startAgent","stopAgent","TmuxUnavailableError","makeAgent","overrides","name","type","status","summary","pid","projectPath","sessionId","sessionFilePath","lastActive","Date","makeTmux","over","isAvailable","vi","fn","mockResolvedValue","sessionExists","createSession","undefined","sendKeys","killSession","findAgentPid","makeRegistry","prune","lookup","mockReturnValue","list","register","isAlive","makeRuntime","provider","ok","insideRuntime","runtimeRef","session","paneId","agentName","send","wait","readOutput","focus","stop","startOpts","cwd","pollIntervalMs","pollTimeoutMs","describe","it","expect","toBe","tmux","registry","killProcess","result","toHaveBeenCalledWith","not","toHaveBeenCalled","toEqual","runtime","startedAt","objectContaining","error","Object","assign","Error","code","rejects","toThrow","focusManager","findTerminal","focusTerminal","focused","reason","location","identifier","tty","prompt","writer","err","catch","toBeInstanceOf","message","entry","toHaveBeenCalledOnce","toMatchObject","pinned","toMatch","runtimeProvider","kind","args","timeoutMs","detail","liveEntry","e","root","mkdtempSync","join","tmpdir","codexPath","mkdirSync","dirname","recursive","writeFileSync","processTree","command","_session","matches","filter","proc","at","rmSync","force","onWarning","mock","calls","toContain","toHaveBeenLastCalledWith","mockResolvedValueOnce","toHaveBeenCalledTimes","order","mockImplementation","push"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/runtime/ManagedAgentRuntime.test.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport {\n AgentNameInUseError,\n AgentPidPollTimeoutError,\n AgentTerminalNotFoundError,\n DEFAULT_PID_POLL_TIMEOUT_MS,\n focusAgent,\n sendAgentPrompt,\n startAgent,\n stopAgent,\n TmuxUnavailableError,\n type StartAgentOptions,\n} from \"../../runtime/ManagedAgentRuntime.js\";\nimport type { AgentInfo } from \"../../adapters/AgentAdapter.js\";\nimport type { AgentRegistry, RegistryEntry } from \"../../utils/AgentRegistry.js\";\nimport type { TmuxManager } from \"../../runtime/tmux/TmuxManager.js\";\nimport type { InteractiveAgentRuntime } from \"../../runtime/types.js\";\n\nfunction makeAgent(overrides: Partial<AgentInfo> = {}): AgentInfo {\n return {\n name: \"repo-a\",\n type: \"claude\",\n status: \"running\" as AgentInfo[\"status\"],\n summary: \"Working\",\n pid: 10,\n projectPath: \"/repo\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n lastActive: new Date(\"2026-05-14T00:00:00.000Z\"),\n ...overrides,\n };\n}\n\nfunction makeTmux(over: Partial<TmuxManager> = {}): TmuxManager {\n return {\n isAvailable: vi.fn().mockResolvedValue(true),\n sessionExists: vi.fn().mockResolvedValue(false),\n createSession: vi.fn().mockResolvedValue(undefined),\n sendKeys: vi.fn().mockResolvedValue(undefined),\n killSession: vi.fn().mockResolvedValue(undefined),\n findAgentPid: vi.fn().mockResolvedValue(12345),\n ...over,\n } as unknown as TmuxManager;\n}\n\nfunction makeRegistry(over: Partial<AgentRegistry> = {}): AgentRegistry {\n return {\n prune: vi.fn(),\n lookup: vi.fn().mockReturnValue(null),\n list: vi.fn().mockReturnValue([]),\n register: vi.fn(),\n isAlive: vi.fn().mockReturnValue(false),\n ...over,\n } as unknown as AgentRegistry;\n}\n\nfunction makeRuntime(over: Partial<InteractiveAgentRuntime> = {}): InteractiveAgentRuntime {\n return {\n provider: \"herdr\",\n isAvailable: vi.fn().mockResolvedValue({ ok: true, insideRuntime: false }),\n startAgent: vi.fn().mockResolvedValue({\n pid: 12345,\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n }),\n send: vi.fn().mockResolvedValue(undefined),\n wait: vi.fn().mockResolvedValue(undefined),\n readOutput: vi.fn().mockResolvedValue(\"done\\n\"),\n focus: vi.fn().mockResolvedValue(true),\n stop: vi.fn().mockResolvedValue(undefined),\n ...over,\n } as unknown as InteractiveAgentRuntime;\n}\n\nconst startOpts: StartAgentOptions = {\n type: \"claude\",\n name: \"agent1\",\n cwd: \"/work\",\n pollIntervalMs: 1,\n pollTimeoutMs: 50,\n};\n\ndescribe(\"managed agent runtime defaults\", () => {\n it(\"allows slower agent startup before PID polling times out\", () => {\n expect(DEFAULT_PID_POLL_TIMEOUT_MS).toBe(15_000);\n });\n});\n\ndescribe(\"stopAgent\", () => {\n it(\"sends SIGTERM to the agent PID\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(killProcess).toHaveBeenCalledWith(123, \"SIGTERM\");\n expect(tmux.killSession).not.toHaveBeenCalled();\n expect(result).toEqual({\n agentName: \"repo-a\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: null,\n });\n });\n\n it(\"kills the registry tmux session when present\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: { session: \"repo-a\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(killProcess).toHaveBeenCalledWith(123, \"SIGTERM\");\n expect(tmux.killSession).toHaveBeenCalledWith(\"repo-a\");\n expect(result.runtimeRef).toEqual({ session: \"repo-a\" });\n });\n\n it(\"delegates Herdr-backed agents to Herdr without sending SIGTERM directly\", async () => {\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"\",\n sessionFilePath: \"\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const killProcess = vi.fn();\n\n const result = await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n runtime,\n registry,\n killProcess,\n });\n\n expect(runtime.stop).toHaveBeenCalledWith(\n expect.objectContaining({\n runtimeRef: { session: \"default\", paneId: \"w1:p2\" },\n }),\n );\n expect(killProcess).not.toHaveBeenCalled();\n expect(result.runtime).toBe(\"herdr\");\n });\n\n it(\"still kills tmux session when the process is already gone\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 123,\n runtime: \"tmux\",\n runtimeRef: { session: \"repo-a\" },\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n sessionId: \"session-1\",\n sessionFilePath: \"/tmp/session.jsonl\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const error = Object.assign(new Error(\"gone\"), { code: \"ESRCH\" });\n const killProcess = vi.fn(() => {\n throw error;\n });\n\n await stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n });\n\n expect(tmux.killSession).toHaveBeenCalledWith(\"repo-a\");\n });\n\n it(\"rethrows unexpected process kill errors\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const error = Object.assign(new Error(\"permission denied\"), { code: \"EPERM\" });\n const killProcess = vi.fn(() => {\n throw error;\n });\n\n await expect(\n stopAgent(makeAgent({ name: \"repo-a\", pid: 123 }), {\n tmux,\n registry,\n killProcess,\n }),\n ).rejects.toThrow(\"permission denied\");\n\n expect(tmux.killSession).not.toHaveBeenCalled();\n });\n});\n\ndescribe(\"focusAgent\", () => {\n it(\"delegates Herdr-backed agents to Herdr focus\", async () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"repo-a\" };\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 10,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const focusManager = {\n findTerminal: vi.fn(),\n focusTerminal: vi.fn(),\n };\n\n const result = await focusAgent(makeAgent(), { registry, runtime, focusManager });\n\n expect(runtime.focus).toHaveBeenCalledWith(expect.objectContaining({ runtimeRef }));\n expect(focusManager.findTerminal).not.toHaveBeenCalled();\n expect(result).toEqual({ focused: true });\n });\n\n it(\"reports when a tmux-backed terminal cannot be found\", async () => {\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(null),\n focusTerminal: vi.fn(),\n };\n\n const result = await focusAgent(makeAgent({ pid: 10 }), {\n registry: makeRegistry(),\n focusManager,\n });\n\n expect(focusManager.findTerminal).toHaveBeenCalledWith(10);\n expect(focusManager.focusTerminal).not.toHaveBeenCalled();\n expect(result).toEqual({ focused: false, reason: \"terminal-not-found\" });\n });\n\n it(\"reports when focusing a found terminal fails\", async () => {\n const location = { type: \"tmux\", identifier: \"1:1\", tty: \"/dev/ttys030\" };\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(location),\n focusTerminal: vi.fn().mockResolvedValue(false),\n };\n\n const result = await focusAgent(makeAgent({ pid: 10 }), {\n registry: makeRegistry(),\n focusManager,\n });\n\n expect(focusManager.focusTerminal).toHaveBeenCalledWith(location);\n expect(result).toEqual({ focused: false, reason: \"focus-failed\" });\n });\n});\n\ndescribe(\"sendAgentPrompt\", () => {\n it(\"sends Herdr-backed prompts through Herdr\", async () => {\n const runtimeRef = { session: \"default\", paneId: \"w1:p2\", agentName: \"repo-a\" };\n const runtime = makeRuntime();\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue({\n name: \"repo-a\",\n type: \"claude\",\n pid: 10,\n runtime: \"herdr\",\n runtimeRef,\n cwd: \"/repo\",\n startedAt: \"2026-06-01T00:00:00.000Z\",\n } satisfies RegistryEntry),\n } as Partial<AgentRegistry>);\n const focusManager = {\n findTerminal: vi.fn(),\n };\n\n await sendAgentPrompt(makeAgent(), \"hello\", {\n registry,\n runtime,\n focusManager,\n });\n\n expect(runtime.send).toHaveBeenCalledWith(\n expect.objectContaining({ runtimeRef, prompt: \"hello\" }),\n expect.objectContaining({ focusManager }),\n );\n expect(focusManager.findTerminal).not.toHaveBeenCalled();\n });\n\n it(\"writes tmux-backed prompts to the resolved terminal\", async () => {\n const location = { type: \"tmux\", identifier: \"1:1\", tty: \"/dev/ttys030\" };\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(location),\n };\n const writer = vi.fn().mockResolvedValue(undefined);\n\n await sendAgentPrompt(makeAgent({ pid: 10 }), \"hello\", {\n registry: makeRegistry(),\n focusManager,\n writer,\n });\n\n expect(focusManager.findTerminal).toHaveBeenCalledWith(10);\n expect(writer).toHaveBeenCalledWith(location, \"hello\");\n });\n\n it(\"throws when a tmux-backed terminal cannot be found\", async () => {\n const focusManager = {\n findTerminal: vi.fn().mockResolvedValue(null),\n };\n\n const err = await sendAgentPrompt(makeAgent({ pid: 10 }), \"hello\", {\n registry: makeRegistry(),\n focusManager,\n }).catch((error) => error);\n\n expect(err).toBeInstanceOf(AgentTerminalNotFoundError);\n expect(err.message).toBe('Cannot find terminal for agent \"repo-a\" (PID: 10).');\n });\n});\n\ndescribe(\"startAgent\", () => {\n it(\"happy path: creates session, sends command, polls, registers, returns entry\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, pollTimeoutMs: 250 }, { tmux, registry });\n\n expect(tmux.createSession).toHaveBeenCalledWith(\"agent1\", \"/work\");\n expect(tmux.sendKeys).toHaveBeenCalledWith(\"agent1\", \"claude\");\n expect(registry.prune).toHaveBeenCalled();\n expect(registry.register).toHaveBeenCalledOnce();\n expect(entry).toMatchObject({\n name: \"agent1\",\n type: \"claude\",\n pid: 12345,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n cwd: \"/work\",\n pinned: false,\n });\n expect(entry.startedAt).toMatch(/^\\d{4}-\\d{2}-\\d{2}T/);\n });\n\n it(\"throws TmuxUnavailableError when tmux is missing\", async () => {\n const tmux = makeTmux({\n isAvailable: vi.fn().mockResolvedValue(false),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n await expect(startAgent(startOpts, { tmux, registry })).rejects.toBeInstanceOf(\n TmuxUnavailableError,\n );\n expect(tmux.createSession).not.toHaveBeenCalled();\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"starts Herdr-backed agents through the configured runtime and persists runtime metadata\", async () => {\n const runtime = makeRuntime();\n const registry = makeRegistry();\n\n const entry = await startAgent(\n { ...startOpts, runtimeProvider: \"herdr\" },\n { runtime, registry },\n );\n\n expect(runtime.isAvailable).toHaveBeenCalledOnce();\n expect(runtime.startAgent).toHaveBeenCalledWith({\n name: \"agent1\",\n cwd: \"/work\",\n kind: \"claude\",\n args: [],\n timeoutMs: 50,\n });\n expect(entry).toMatchObject({\n name: \"agent1\",\n type: \"claude\",\n pid: 12345,\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n cwd: \"/work\",\n pinned: false,\n });\n expect(registry.register).toHaveBeenCalledWith(\n expect.objectContaining({\n runtime: \"herdr\",\n runtimeRef: { session: \"default\", paneId: \"w1:p2\", agentName: \"agent1\" },\n }),\n );\n });\n\n it(\"fails Herdr starts when the configured runtime is unavailable\", async () => {\n const runtime = makeRuntime({\n isAvailable: vi.fn().mockResolvedValue({\n ok: false,\n reason: \"binary-missing\",\n detail: \"herdr command was not found in PATH.\",\n }),\n });\n const registry = makeRegistry();\n\n await expect(\n startAgent({ ...startOpts, runtimeProvider: \"herdr\" }, { runtime, registry }),\n ).rejects.toMatchObject({\n name: \"AgentRuntimeUnavailableError\",\n provider: \"herdr\",\n reason: \"binary-missing\",\n });\n expect(runtime.startAgent).not.toHaveBeenCalled();\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"throws AgentNameInUseError when registry already has a live entry\", async () => {\n const tmux = makeTmux();\n const liveEntry: RegistryEntry = {\n name: \"agent1\",\n type: \"claude\",\n pid: 999,\n runtime: \"tmux\",\n runtimeRef: { session: \"agent1\" },\n cwd: \"/old\",\n startedAt: \"2026-01-01T00:00:00.000Z\",\n };\n const registry = makeRegistry({\n lookup: vi.fn().mockReturnValue(liveEntry),\n } as Partial<AgentRegistry>);\n\n const err = await startAgent(startOpts, { tmux, registry }).catch((e) => e);\n expect(err).toBeInstanceOf(AgentNameInUseError);\n expect(err.pid).toBe(999);\n expect(tmux.createSession).not.toHaveBeenCalled();\n });\n\n it(\"detects the agent PID when the agent is installed under a path containing spaces\", async () => {\n const root = fs.mkdtempSync(path.join(os.tmpdir(), \"managed-runtime-spaces-\"));\n try {\n const codexPath = path.join(root, \"Applications/Some App.app/Contents/Resources/codex\");\n fs.mkdirSync(path.dirname(codexPath), { recursive: true });\n fs.writeFileSync(codexPath, \"\");\n const processTree = [\n { pid: 100, command: \"-zsh\" },\n { pid: 200, command: `${codexPath} --sandbox workspace-write` },\n { pid: 300, command: \"/usr/local/bin/node /opt/mcp/server.js\" },\n ];\n const findAgentPid = vi.fn(\n async (_session: string, matches: (psCommand: string) => boolean) =>\n processTree.filter((proc) => matches(proc.command)).at(-1)?.pid ?? null,\n );\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, type: \"codex\" }, { tmux, registry });\n\n expect(tmux.sendKeys).toHaveBeenCalledWith(\"agent1\", \"codex\");\n expect(entry).toMatchObject({ type: \"codex\", pid: 200 });\n } finally {\n fs.rmSync(root, { recursive: true, force: true });\n }\n });\n\n it(\"replaces orphan tmux session and calls onWarning\", async () => {\n const tmux = makeTmux({\n sessionExists: vi.fn().mockResolvedValue(true),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n const onWarning = vi.fn();\n\n await startAgent(startOpts, { tmux, registry, onWarning });\n\n expect(onWarning).toHaveBeenCalledOnce();\n expect(onWarning.mock.calls[0][0]).toContain(\"agent1\");\n expect(tmux.killSession).toHaveBeenCalledWith(\"agent1\");\n expect(tmux.createSession).toHaveBeenCalledWith(\"agent1\", \"/work\");\n });\n\n it(\"on PID poll timeout: kills session and throws AgentPidPollTimeoutError\", async () => {\n const tmux = makeTmux({\n findAgentPid: vi.fn().mockResolvedValue(null),\n } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const err = await startAgent(startOpts, { tmux, registry }).catch((e) => e);\n\n expect(err).toBeInstanceOf(AgentPidPollTimeoutError);\n expect(err.command).toBe(\"claude\");\n expect(err.timeoutMs).toBe(50);\n expect(tmux.killSession).toHaveBeenLastCalledWith(\"agent1\");\n expect(registry.register).not.toHaveBeenCalled();\n });\n\n it(\"keeps polling until findAgentPid returns a PID\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(null)\n .mockResolvedValueOnce(null)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42)\n .mockResolvedValueOnce(42);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent({ ...startOpts, pollTimeoutMs: 250 }, { tmux, registry });\n\n expect(findAgentPid).toHaveBeenCalledTimes(7);\n expect(entry.pid).toBe(42);\n });\n\n it(\"waits for the launched process PID to stabilize before registering\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200)\n .mockResolvedValueOnce(200);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const entry = await startAgent(startOpts, { tmux, registry });\n\n expect(findAgentPid).toHaveBeenCalledTimes(8);\n expect(entry.pid).toBe(200);\n expect(registry.register).toHaveBeenCalledWith(expect.objectContaining({ pid: 200 }));\n });\n\n it(\"treats an unstabilized PID as a poll timeout\", async () => {\n const findAgentPid = vi\n .fn()\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100)\n .mockResolvedValueOnce(100);\n const tmux = makeTmux({ findAgentPid } as Partial<TmuxManager>);\n const registry = makeRegistry();\n\n const err = await startAgent({ ...startOpts, pollTimeoutMs: 3 }, { tmux, registry }).catch(\n (e) => e,\n );\n\n expect(err).toBeInstanceOf(AgentPidPollTimeoutError);\n expect(registry.register).not.toHaveBeenCalled();\n expect(tmux.killSession).toHaveBeenLastCalledWith(\"agent1\");\n });\n\n it(\"prunes registry before checking for name collision\", async () => {\n const tmux = makeTmux();\n const registry = makeRegistry();\n const order: string[] = [];\n (registry.prune as any).mockImplementation(() => order.push(\"prune\"));\n (registry.lookup as any).mockImplementation(() => {\n order.push(\"lookup\");\n return null;\n });\n\n await startAgent(startOpts, { tmux, registry });\n expect(order).toEqual([\"prune\", \"lookup\"]);\n });\n});\n"],"names":["fs","os","path","AgentNameInUseError","AgentPidPollTimeoutError","AgentTerminalNotFoundError","DEFAULT_PID_POLL_TIMEOUT_MS","focusAgent","sendAgentPrompt","startAgent","stopAgent","TmuxUnavailableError","makeAgent","overrides","name","type","status","summary","pid","projectPath","sessionId","sessionFilePath","lastActive","Date","makeTmux","over","isAvailable","vi","fn","mockResolvedValue","sessionExists","createSession","undefined","sendKeys","killSession","findAgentPid","makeRegistry","prune","lookup","mockReturnValue","list","register","isAlive","makeRuntime","provider","ok","insideRuntime","runtimeRef","session","paneId","agentName","send","wait","readOutput","focus","stop","startOpts","cwd","pollIntervalMs","pollTimeoutMs","describe","it","expect","toBe","tmux","registry","killProcess","result","toHaveBeenCalledWith","not","toHaveBeenCalled","toEqual","runtime","startedAt","objectContaining","error","Object","assign","Error","code","rejects","toThrow","focusManager","findTerminal","focusTerminal","focused","reason","location","identifier","tty","prompt","writer","err","catch","toBeInstanceOf","message","entry","toHaveBeenCalledOnce","toMatchObject","pinned","toMatch","runtimeProvider","kind","args","timeoutMs","detail","liveEntry","e","root","mkdtempSync","join","tmpdir","codexPath","mkdirSync","dirname","recursive","writeFileSync","processTree","command","_session","matches","filter","proc","at","rmSync","force","onWarning","mock","calls","toContain","toHaveBeenLastCalledWith","mockResolvedValueOnce","toHaveBeenCalledTimes","order","mockImplementation","push"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { execFile } from "child_process";
2
- import { TmuxManager } from "../../terminal/TmuxManager.js";
2
+ import { TmuxManager } from "../../runtime/tmux/TmuxManager.js";
3
3
  vi.mock("child_process", ()=>({
4
4
  execFile: vi.fn()
5
5
  }));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/__tests__/terminal/TmuxManager.test.ts"],"sourcesContent":["import { execFile } from \"child_process\";\nimport type { MockedFunction } from \"vitest\";\nimport { TmuxManager } from \"../../terminal/TmuxManager.js\";\n\nvi.mock(\"child_process\", () => ({\n execFile: vi.fn(),\n}));\n\ntype ExecFileCb = (err: Error | null, result?: { stdout: string; stderr: string }) => void;\nconst mockedExecFile = execFile as unknown as MockedFunction<\n (cmd: string, args: string[], cb: ExecFileCb) => void\n>;\n\n/** Drive the promisified execFile mock with a per-call handler. */\nfunction setExecFileHandler(handler: (cmd: string, args: string[]) => string | Error) {\n mockedExecFile.mockImplementation((_cmd, _args, cb) => {\n const result = handler(_cmd, _args);\n if (result instanceof Error) cb(result);\n else cb(null, { stdout: result, stderr: \"\" });\n });\n}\n\ndescribe(\"TmuxManager\", () => {\n let tmux: TmuxManager;\n\n beforeEach(() => {\n tmux = new TmuxManager();\n mockedExecFile.mockReset();\n });\n\n describe(\"isAvailable\", () => {\n it(\"returns true when `tmux -V` succeeds\", async () => {\n setExecFileHandler(() => \"tmux 3.4\");\n expect(await tmux.isAvailable()).toBe(true);\n });\n\n it(\"returns false when tmux is missing\", async () => {\n setExecFileHandler(() => new Error(\"ENOENT\"));\n expect(await tmux.isAvailable()).toBe(false);\n });\n });\n\n describe(\"sessionExists\", () => {\n it(\"returns true when has-session succeeds\", async () => {\n setExecFileHandler(() => \"\");\n expect(await tmux.sessionExists(\"foo\")).toBe(true);\n });\n\n it(\"returns false when has-session fails\", async () => {\n setExecFileHandler(() => new Error(\"no session\"));\n expect(await tmux.sessionExists(\"foo\")).toBe(false);\n });\n });\n\n describe(\"createSession\", () => {\n it(\"issues `tmux new-session -d -s <name> -c <cwd>`\", async () => {\n setExecFileHandler(() => \"\");\n await tmux.createSession(\"foo\", \"/work\");\n expect(mockedExecFile).toHaveBeenCalledWith(\n \"tmux\",\n [\"new-session\", \"-d\", \"-s\", \"foo\", \"-c\", \"/work\"],\n expect.any(Function),\n );\n });\n });\n\n describe(\"sendKeys\", () => {\n it(\"appends Enter so the command runs\", async () => {\n setExecFileHandler(() => \"\");\n await tmux.sendKeys(\"foo\", \"claude\");\n expect(mockedExecFile).toHaveBeenCalledWith(\n \"tmux\",\n [\"send-keys\", \"-t\", \"foo\", \"claude\", \"Enter\"],\n expect.any(Function),\n );\n });\n });\n\n describe(\"killSession\", () => {\n it(\"swallows errors when session is already gone\", async () => {\n setExecFileHandler(() => new Error(\"can't find session\"));\n await expect(tmux.killSession(\"foo\")).resolves.toBeUndefined();\n });\n });\n\n describe(\"findAgentPid\", () => {\n const matchesClaude = (cmd: string) => cmd.split(/\\s+/)[0]?.endsWith(\"claude\") ?? false;\n\n it(\"returns null when the session has no pane\", async () => {\n setExecFileHandler((cmd, args) => {\n if (args[0] === \"list-panes\") return new Error(\"no session\");\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBeNull();\n });\n\n it(\"returns null when no descendant matches\", async () => {\n // pane PID 100; child 200 is \"node /unrelated\" — no match\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\" && args[0] === \"list-panes\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"node /unrelated\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBeNull();\n });\n\n it(\"returns the matching pane PID when the agent replaces the shell\", async () => {\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\" && args[0] === \"list-panes\") return \"100\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"100\") return \"/usr/local/bin/claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(100);\n });\n\n it(\"returns the matching descendant when found\", async () => {\n // pane 100 → child 200 (claude) — no grandchildren\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(200);\n });\n\n it(\"prefers the deepest match (wrapper case)\", async () => {\n // pane 100 → 200 (claude wrapper, matches) → 300 (claude, matches, deeper)\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\" && args[1] === \"200\") return \"300\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"/usr/local/bin/claude\";\n if (cmd === \"ps\" && args[1] === \"300\") return \"/usr/local/lib/claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(300);\n });\n\n it(\"skips non-matching subprocesses (MCP child case)\", async () => {\n // pane 100 → 200 (claude, matches) → 300 (mcp-server, no match)\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\" && args[1] === \"200\") return \"300\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"claude\";\n if (cmd === \"ps\" && args[1] === \"300\") return \"node mcp-server.js\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(200);\n });\n\n it(\"handles the gemini Node-script shape via a token-scan matcher\", async () => {\n const matchesGemini = (cmd: string) =>\n cmd.split(/\\s+/).some((t) => t.endsWith(\"/gemini\") || t === \"gemini\");\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"node /opt/homebrew/bin/gemini --foo\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesGemini)).toBe(200);\n });\n\n it(\"handles multiple children at the same level\", async () => {\n // pane 100 → [200 (nope), 201 (claude)]\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n201\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"bash\";\n if (cmd === \"ps\" && args[1] === \"201\") return \"claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(201);\n });\n });\n});\n"],"names":["execFile","TmuxManager","vi","mock","fn","mockedExecFile","setExecFileHandler","handler","mockImplementation","_cmd","_args","cb","result","Error","stdout","stderr","describe","tmux","beforeEach","mockReset","it","expect","isAvailable","toBe","sessionExists","createSession","toHaveBeenCalledWith","any","Function","sendKeys","killSession","resolves","toBeUndefined","matchesClaude","cmd","split","endsWith","args","findAgentPid","toBeNull","matchesGemini","some","t"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/__tests__/terminal/TmuxManager.test.ts"],"sourcesContent":["import { execFile } from \"child_process\";\nimport type { MockedFunction } from \"vitest\";\nimport { TmuxManager } from \"../../runtime/tmux/TmuxManager.js\";\n\nvi.mock(\"child_process\", () => ({\n execFile: vi.fn(),\n}));\n\ntype ExecFileCb = (err: Error | null, result?: { stdout: string; stderr: string }) => void;\nconst mockedExecFile = execFile as unknown as MockedFunction<\n (cmd: string, args: string[], cb: ExecFileCb) => void\n>;\n\n/** Drive the promisified execFile mock with a per-call handler. */\nfunction setExecFileHandler(handler: (cmd: string, args: string[]) => string | Error) {\n mockedExecFile.mockImplementation((_cmd, _args, cb) => {\n const result = handler(_cmd, _args);\n if (result instanceof Error) cb(result);\n else cb(null, { stdout: result, stderr: \"\" });\n });\n}\n\ndescribe(\"TmuxManager\", () => {\n let tmux: TmuxManager;\n\n beforeEach(() => {\n tmux = new TmuxManager();\n mockedExecFile.mockReset();\n });\n\n describe(\"isAvailable\", () => {\n it(\"returns true when `tmux -V` succeeds\", async () => {\n setExecFileHandler(() => \"tmux 3.4\");\n expect(await tmux.isAvailable()).toBe(true);\n });\n\n it(\"returns false when tmux is missing\", async () => {\n setExecFileHandler(() => new Error(\"ENOENT\"));\n expect(await tmux.isAvailable()).toBe(false);\n });\n });\n\n describe(\"sessionExists\", () => {\n it(\"returns true when has-session succeeds\", async () => {\n setExecFileHandler(() => \"\");\n expect(await tmux.sessionExists(\"foo\")).toBe(true);\n });\n\n it(\"returns false when has-session fails\", async () => {\n setExecFileHandler(() => new Error(\"no session\"));\n expect(await tmux.sessionExists(\"foo\")).toBe(false);\n });\n });\n\n describe(\"createSession\", () => {\n it(\"issues `tmux new-session -d -s <name> -c <cwd>`\", async () => {\n setExecFileHandler(() => \"\");\n await tmux.createSession(\"foo\", \"/work\");\n expect(mockedExecFile).toHaveBeenCalledWith(\n \"tmux\",\n [\"new-session\", \"-d\", \"-s\", \"foo\", \"-c\", \"/work\"],\n expect.any(Function),\n );\n });\n });\n\n describe(\"sendKeys\", () => {\n it(\"appends Enter so the command runs\", async () => {\n setExecFileHandler(() => \"\");\n await tmux.sendKeys(\"foo\", \"claude\");\n expect(mockedExecFile).toHaveBeenCalledWith(\n \"tmux\",\n [\"send-keys\", \"-t\", \"foo\", \"claude\", \"Enter\"],\n expect.any(Function),\n );\n });\n });\n\n describe(\"killSession\", () => {\n it(\"swallows errors when session is already gone\", async () => {\n setExecFileHandler(() => new Error(\"can't find session\"));\n await expect(tmux.killSession(\"foo\")).resolves.toBeUndefined();\n });\n });\n\n describe(\"findAgentPid\", () => {\n const matchesClaude = (cmd: string) => cmd.split(/\\s+/)[0]?.endsWith(\"claude\") ?? false;\n\n it(\"returns null when the session has no pane\", async () => {\n setExecFileHandler((cmd, args) => {\n if (args[0] === \"list-panes\") return new Error(\"no session\");\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBeNull();\n });\n\n it(\"returns null when no descendant matches\", async () => {\n // pane PID 100; child 200 is \"node /unrelated\" — no match\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\" && args[0] === \"list-panes\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"node /unrelated\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBeNull();\n });\n\n it(\"returns the matching pane PID when the agent replaces the shell\", async () => {\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\" && args[0] === \"list-panes\") return \"100\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"100\") return \"/usr/local/bin/claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(100);\n });\n\n it(\"returns the matching descendant when found\", async () => {\n // pane 100 → child 200 (claude) — no grandchildren\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(200);\n });\n\n it(\"prefers the deepest match (wrapper case)\", async () => {\n // pane 100 → 200 (claude wrapper, matches) → 300 (claude, matches, deeper)\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\" && args[1] === \"200\") return \"300\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"/usr/local/bin/claude\";\n if (cmd === \"ps\" && args[1] === \"300\") return \"/usr/local/lib/claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(300);\n });\n\n it(\"skips non-matching subprocesses (MCP child case)\", async () => {\n // pane 100 → 200 (claude, matches) → 300 (mcp-server, no match)\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\" && args[1] === \"200\") return \"300\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"claude\";\n if (cmd === \"ps\" && args[1] === \"300\") return \"node mcp-server.js\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(200);\n });\n\n it(\"handles the gemini Node-script shape via a token-scan matcher\", async () => {\n const matchesGemini = (cmd: string) =>\n cmd.split(/\\s+/).some((t) => t.endsWith(\"/gemini\") || t === \"gemini\");\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"node /opt/homebrew/bin/gemini --foo\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesGemini)).toBe(200);\n });\n\n it(\"handles multiple children at the same level\", async () => {\n // pane 100 → [200 (nope), 201 (claude)]\n setExecFileHandler((cmd, args) => {\n if (cmd === \"tmux\") return \"100\\n\";\n if (cmd === \"pgrep\" && args[1] === \"100\") return \"200\\n201\\n\";\n if (cmd === \"pgrep\") return new Error(\"no children\");\n if (cmd === \"ps\" && args[1] === \"200\") return \"bash\";\n if (cmd === \"ps\" && args[1] === \"201\") return \"claude\";\n return \"\";\n });\n expect(await tmux.findAgentPid(\"foo\", matchesClaude)).toBe(201);\n });\n });\n});\n"],"names":["execFile","TmuxManager","vi","mock","fn","mockedExecFile","setExecFileHandler","handler","mockImplementation","_cmd","_args","cb","result","Error","stdout","stderr","describe","tmux","beforeEach","mockReset","it","expect","isAvailable","toBe","sessionExists","createSession","toHaveBeenCalledWith","any","Function","sendKeys","killSession","resolves","toBeUndefined","matchesClaude","cmd","split","endsWith","args","findAgentPid","toBeNull","matchesGemini","some","t"],"mappings":"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"}
@@ -1,30 +1,20 @@
1
- import { probeCodexCapacity } from "./codex.js";
2
- import { type ClaudeCapacityOptions } from "./claude.js";
1
+ import { probeCodexCapacity } from "./sources/codex.js";
2
+ import { type ClaudeCapacityOptions } from "./sources/claude.js";
3
+ import { type PiAnthropicCapacityOptions, type PiOpenAiCapacityOptions, type PiZaiCapacityOptions } from "./sources/pi.js";
3
4
  import type { CapacityReport } from "./types.js";
4
5
  export type { CapacityReport, CapacityWindow } from "./types.js";
5
- export type { ClaudeCapacityOptions } from "./claude.js";
6
+ export type { ClaudeCapacityOptions } from "./sources/claude.js";
7
+ export type { PiAnthropicCapacityOptions as AnthropicCapacityOptions } from "./sources/pi.js";
8
+ export type { PiOpenAiCapacityOptions as OpenAiCapacityOptions, PiZaiCapacityOptions as ZaiCapacityOptions, } from "./sources/pi.js";
6
9
  export type CapacityProbeOptions = {
7
10
  now?: () => Date;
8
11
  path?: string;
9
12
  access?: (target: string) => Promise<void>;
10
13
  probe?: typeof probeCodexCapacity;
11
14
  };
12
- export type ZaiCapacityOptions = {
13
- now?: () => Date;
14
- env?: NodeJS.ProcessEnv;
15
- readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
16
- fetch?: typeof globalThis.fetch;
17
- timeoutMs?: number;
18
- };
19
- export type OpenAiCapacityOptions = {
20
- now?: () => Date;
21
- env?: NodeJS.ProcessEnv;
22
- readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
23
- fetch?: typeof globalThis.fetch;
24
- timeoutMs?: number;
25
- };
26
15
  export declare function getCodexCapacityReport(options?: CapacityProbeOptions): Promise<CapacityReport>;
27
- export declare function getZaiCapacityReport(options?: ZaiCapacityOptions): Promise<CapacityReport>;
28
- export declare function getOpenAiCapacityReport(options?: OpenAiCapacityOptions): Promise<CapacityReport>;
16
+ export declare function getZaiCapacityReport(options?: PiZaiCapacityOptions): Promise<CapacityReport>;
17
+ export declare function getOpenAiCapacityReport(options?: PiOpenAiCapacityOptions): Promise<CapacityReport>;
29
18
  export declare function getClaudeCapacityReport(options?: ClaudeCapacityOptions): Promise<CapacityReport>;
19
+ export declare function getAnthropicCapacityReport(options?: PiAnthropicCapacityOptions): Promise<CapacityReport>;
30
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capacity/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACxE,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAG9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AA+BF,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CAWzB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CAOzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/capacity/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAuB,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAIL,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjE,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,YAAY,EAAE,0BAA0B,IAAI,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,YAAY,EACV,uBAAuB,IAAI,qBAAqB,EAChD,oBAAoB,IAAI,kBAAkB,GAC3C,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,KAAK,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACnC,CAAC;AA+BF,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CAWzB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,cAAc,CAAC,CAMzB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CAOzB;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,cAAc,CAAC,CAOzB"}
@@ -1,10 +1,9 @@
1
1
  import { constants } from "node:fs";
2
2
  import { access as fsAccess } from "node:fs/promises";
3
3
  import path from "node:path";
4
- import { codexUnavailableReport, probeCodexCapacity } from "./codex.js";
5
- import { probeClaudeCapacity } from "./claude.js";
6
- import { probeOpenAiCapacity } from "./openai.js";
7
- import { probeZaiCapacity } from "./zai.js";
4
+ import { codexUnavailableReport, probeCodexCapacity } from "./sources/codex.js";
5
+ import { probeClaudeCapacity } from "./sources/claude.js";
6
+ import { probeOpenAiCapacity, probePiAnthropicCapacity, probeZaiCapacity } from "./sources/pi.js";
8
7
  async function canAccess(target, mode) {
9
8
  try {
10
9
  await fsAccess(target, mode);
@@ -63,5 +62,13 @@ export async function getClaudeCapacityReport(options = {}) {
63
62
  now
64
63
  });
65
64
  }
65
+ export async function getAnthropicCapacityReport(options = {}) {
66
+ const { now, ...probeOptions } = options;
67
+ return probePiAnthropicCapacity({
68
+ ...probeOptions,
69
+ checkedAt: (now?.() ?? new Date()).toISOString(),
70
+ now
71
+ });
72
+ }
66
73
 
67
74
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/capacity/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { codexUnavailableReport, probeCodexCapacity } from \"./codex.js\";\nimport { probeClaudeCapacity, type ClaudeCapacityOptions } from \"./claude.js\";\nimport { probeOpenAiCapacity } from \"./openai.js\";\nimport { probeZaiCapacity } from \"./zai.js\";\nimport type { CapacityReport } from \"./types.js\";\n\nexport type { CapacityReport, CapacityWindow } from \"./types.js\";\nexport type { ClaudeCapacityOptions } from \"./claude.js\";\n\nexport type CapacityProbeOptions = {\n now?: () => Date;\n path?: string;\n access?: (target: string) => Promise<void>;\n probe?: typeof probeCodexCapacity;\n};\n\nexport type ZaiCapacityOptions = {\n now?: () => Date;\n env?: NodeJS.ProcessEnv;\n readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n};\n\nexport type OpenAiCapacityOptions = {\n now?: () => Date;\n env?: NodeJS.ProcessEnv;\n readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;\n fetch?: typeof globalThis.fetch;\n timeoutMs?: number;\n};\n\nasync function canAccess(target: string, mode: number): Promise<boolean> {\n try {\n await fsAccess(target, mode);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isCodexInstalled(\n pathValue: string,\n checkAccess?: (target: string) => Promise<void>,\n): Promise<boolean> {\n const directories = pathValue.split(path.delimiter).filter(Boolean);\n for (const directory of directories) {\n const executable = path.join(directory, \"codex\");\n if (checkAccess) {\n try {\n await checkAccess(executable);\n return true;\n } catch {\n continue;\n }\n }\n if (await canAccess(executable, constants.X_OK)) return true;\n }\n return false;\n}\n\nexport async function getCodexCapacityReport(\n options: CapacityProbeOptions = {},\n): Promise<CapacityReport> {\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const installed = await isCodexInstalled(options.path ?? process.env.PATH ?? \"\", options.access);\n try {\n return await (options.probe ?? probeCodexCapacity)({\n installed,\n checkedAt: generatedAt,\n });\n } catch {\n return codexUnavailableReport(generatedAt);\n }\n}\n\nexport async function getZaiCapacityReport(\n options: ZaiCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeZaiCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n });\n}\n\nexport async function getOpenAiCapacityReport(\n options: OpenAiCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeOpenAiCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n });\n}\n\nexport async function getClaudeCapacityReport(\n options: ClaudeCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeClaudeCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n now,\n });\n}\n"],"names":["constants","access","fsAccess","path","codexUnavailableReport","probeCodexCapacity","probeClaudeCapacity","probeOpenAiCapacity","probeZaiCapacity","canAccess","target","mode","isCodexInstalled","pathValue","checkAccess","directories","split","delimiter","filter","Boolean","directory","executable","join","X_OK","getCodexCapacityReport","options","generatedAt","now","Date","toISOString","installed","process","env","PATH","probe","checkedAt","getZaiCapacityReport","probeOptions","getOpenAiCapacityReport","getClaudeCapacityReport"],"mappings":"AAAA,SAASA,SAAS,QAAQ,UAAU;AACpC,SAASC,UAAUC,QAAQ,QAAQ,mBAAmB;AACtD,OAAOC,UAAU,YAAY;AAC7B,SAASC,sBAAsB,EAAEC,kBAAkB,QAAQ,aAAa;AACxE,SAASC,mBAAmB,QAAoC,cAAc;AAC9E,SAASC,mBAAmB,QAAQ,cAAc;AAClD,SAASC,gBAAgB,QAAQ,WAAW;AA6B5C,eAAeC,UAAUC,MAAc,EAAEC,IAAY;IACnD,IAAI;QACF,MAAMT,SAASQ,QAAQC;QACvB,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,eAAeC,iBACbC,SAAiB,EACjBC,WAA+C;IAE/C,MAAMC,cAAcF,UAAUG,KAAK,CAACb,KAAKc,SAAS,EAAEC,MAAM,CAACC;IAC3D,KAAK,MAAMC,aAAaL,YAAa;QACnC,MAAMM,aAAalB,KAAKmB,IAAI,CAACF,WAAW;QACxC,IAAIN,aAAa;YACf,IAAI;gBACF,MAAMA,YAAYO;gBAClB,OAAO;YACT,EAAE,OAAM;gBACN;YACF;QACF;QACA,IAAI,MAAMZ,UAAUY,YAAYrB,UAAUuB,IAAI,GAAG,OAAO;IAC1D;IACA,OAAO;AACT;AAEA,OAAO,eAAeC,uBACpBC,UAAgC,CAAC,CAAC;IAElC,MAAMC,cAAc,AAACD,CAAAA,QAAQE,GAAG,QAAQ,IAAIC,MAAK,EAAGC,WAAW;IAC/D,MAAMC,YAAY,MAAMlB,iBAAiBa,QAAQtB,IAAI,IAAI4B,QAAQC,GAAG,CAACC,IAAI,IAAI,IAAIR,QAAQxB,MAAM;IAC/F,IAAI;QACF,OAAO,MAAM,AAACwB,CAAAA,QAAQS,KAAK,IAAI7B,kBAAiB,EAAG;YACjDyB;YACAK,WAAWT;QACb;IACF,EAAE,OAAM;QACN,OAAOtB,uBAAuBsB;IAChC;AACF;AAEA,OAAO,eAAeU,qBACpBX,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOjB,iBAAiB;QACtB,GAAG6B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;IAChD;AACF;AAEA,OAAO,eAAeS,wBACpBb,UAAiC,CAAC,CAAC;IAEnC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOlB,oBAAoB;QACzB,GAAG8B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;IAChD;AACF;AAEA,OAAO,eAAeU,wBACpBd,UAAiC,CAAC,CAAC;IAEnC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOnB,oBAAoB;QACzB,GAAG+B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;QAC9CF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/capacity/index.ts"],"sourcesContent":["import { constants } from \"node:fs\";\nimport { access as fsAccess } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { codexUnavailableReport, probeCodexCapacity } from \"./sources/codex.js\";\nimport { probeClaudeCapacity, type ClaudeCapacityOptions } from \"./sources/claude.js\";\nimport {\n probeOpenAiCapacity,\n probePiAnthropicCapacity,\n probeZaiCapacity,\n type PiAnthropicCapacityOptions,\n type PiOpenAiCapacityOptions,\n type PiZaiCapacityOptions,\n} from \"./sources/pi.js\";\nimport type { CapacityReport } from \"./types.js\";\n\nexport type { CapacityReport, CapacityWindow } from \"./types.js\";\nexport type { ClaudeCapacityOptions } from \"./sources/claude.js\";\nexport type { PiAnthropicCapacityOptions as AnthropicCapacityOptions } from \"./sources/pi.js\";\nexport type {\n PiOpenAiCapacityOptions as OpenAiCapacityOptions,\n PiZaiCapacityOptions as ZaiCapacityOptions,\n} from \"./sources/pi.js\";\n\nexport type CapacityProbeOptions = {\n now?: () => Date;\n path?: string;\n access?: (target: string) => Promise<void>;\n probe?: typeof probeCodexCapacity;\n};\n\nasync function canAccess(target: string, mode: number): Promise<boolean> {\n try {\n await fsAccess(target, mode);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isCodexInstalled(\n pathValue: string,\n checkAccess?: (target: string) => Promise<void>,\n): Promise<boolean> {\n const directories = pathValue.split(path.delimiter).filter(Boolean);\n for (const directory of directories) {\n const executable = path.join(directory, \"codex\");\n if (checkAccess) {\n try {\n await checkAccess(executable);\n return true;\n } catch {\n continue;\n }\n }\n if (await canAccess(executable, constants.X_OK)) return true;\n }\n return false;\n}\n\nexport async function getCodexCapacityReport(\n options: CapacityProbeOptions = {},\n): Promise<CapacityReport> {\n const generatedAt = (options.now?.() ?? new Date()).toISOString();\n const installed = await isCodexInstalled(options.path ?? process.env.PATH ?? \"\", options.access);\n try {\n return await (options.probe ?? probeCodexCapacity)({\n installed,\n checkedAt: generatedAt,\n });\n } catch {\n return codexUnavailableReport(generatedAt);\n }\n}\n\nexport async function getZaiCapacityReport(\n options: PiZaiCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeZaiCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n });\n}\n\nexport async function getOpenAiCapacityReport(\n options: PiOpenAiCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeOpenAiCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n });\n}\n\nexport async function getClaudeCapacityReport(\n options: ClaudeCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probeClaudeCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n now,\n });\n}\n\nexport async function getAnthropicCapacityReport(\n options: PiAnthropicCapacityOptions = {},\n): Promise<CapacityReport> {\n const { now, ...probeOptions } = options;\n return probePiAnthropicCapacity({\n ...probeOptions,\n checkedAt: (now?.() ?? new Date()).toISOString(),\n now,\n });\n}\n"],"names":["constants","access","fsAccess","path","codexUnavailableReport","probeCodexCapacity","probeClaudeCapacity","probeOpenAiCapacity","probePiAnthropicCapacity","probeZaiCapacity","canAccess","target","mode","isCodexInstalled","pathValue","checkAccess","directories","split","delimiter","filter","Boolean","directory","executable","join","X_OK","getCodexCapacityReport","options","generatedAt","now","Date","toISOString","installed","process","env","PATH","probe","checkedAt","getZaiCapacityReport","probeOptions","getOpenAiCapacityReport","getClaudeCapacityReport","getAnthropicCapacityReport"],"mappings":"AAAA,SAASA,SAAS,QAAQ,UAAU;AACpC,SAASC,UAAUC,QAAQ,QAAQ,mBAAmB;AACtD,OAAOC,UAAU,YAAY;AAC7B,SAASC,sBAAsB,EAAEC,kBAAkB,QAAQ,qBAAqB;AAChF,SAASC,mBAAmB,QAAoC,sBAAsB;AACtF,SACEC,mBAAmB,EACnBC,wBAAwB,EACxBC,gBAAgB,QAIX,kBAAkB;AAkBzB,eAAeC,UAAUC,MAAc,EAAEC,IAAY;IACnD,IAAI;QACF,MAAMV,SAASS,QAAQC;QACvB,OAAO;IACT,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAEA,eAAeC,iBACbC,SAAiB,EACjBC,WAA+C;IAE/C,MAAMC,cAAcF,UAAUG,KAAK,CAACd,KAAKe,SAAS,EAAEC,MAAM,CAACC;IAC3D,KAAK,MAAMC,aAAaL,YAAa;QACnC,MAAMM,aAAanB,KAAKoB,IAAI,CAACF,WAAW;QACxC,IAAIN,aAAa;YACf,IAAI;gBACF,MAAMA,YAAYO;gBAClB,OAAO;YACT,EAAE,OAAM;gBACN;YACF;QACF;QACA,IAAI,MAAMZ,UAAUY,YAAYtB,UAAUwB,IAAI,GAAG,OAAO;IAC1D;IACA,OAAO;AACT;AAEA,OAAO,eAAeC,uBACpBC,UAAgC,CAAC,CAAC;IAElC,MAAMC,cAAc,AAACD,CAAAA,QAAQE,GAAG,QAAQ,IAAIC,MAAK,EAAGC,WAAW;IAC/D,MAAMC,YAAY,MAAMlB,iBAAiBa,QAAQvB,IAAI,IAAI6B,QAAQC,GAAG,CAACC,IAAI,IAAI,IAAIR,QAAQzB,MAAM;IAC/F,IAAI;QACF,OAAO,MAAM,AAACyB,CAAAA,QAAQS,KAAK,IAAI9B,kBAAiB,EAAG;YACjD0B;YACAK,WAAWT;QACb;IACF,EAAE,OAAM;QACN,OAAOvB,uBAAuBuB;IAChC;AACF;AAEA,OAAO,eAAeU,qBACpBX,UAAgC,CAAC,CAAC;IAElC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOjB,iBAAiB;QACtB,GAAG6B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;IAChD;AACF;AAEA,OAAO,eAAeS,wBACpBb,UAAmC,CAAC,CAAC;IAErC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOnB,oBAAoB;QACzB,GAAG+B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;IAChD;AACF;AAEA,OAAO,eAAeU,wBACpBd,UAAiC,CAAC,CAAC;IAEnC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOpB,oBAAoB;QACzB,GAAGgC,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;QAC9CF;IACF;AACF;AAEA,OAAO,eAAea,2BACpBf,UAAsC,CAAC,CAAC;IAExC,MAAM,EAAEE,GAAG,EAAE,GAAGU,cAAc,GAAGZ;IACjC,OAAOlB,yBAAyB;QAC9B,GAAG8B,YAAY;QACfF,WAAW,AAACR,CAAAA,WAAW,IAAIC,MAAK,EAAGC,WAAW;QAC9CF;IACF;AACF"}
@@ -0,0 +1,9 @@
1
+ import type { ProviderCapacitySnapshot } from "../types.js";
2
+ export type AnthropicCapacityRequestOptions = {
3
+ fetch?: typeof globalThis.fetch;
4
+ timeoutMs?: number;
5
+ now?: () => Date;
6
+ };
7
+ export declare function parseAnthropicCapacity(raw: unknown): ProviderCapacitySnapshot;
8
+ export declare function fetchAnthropicCapacity(token: string, options?: AnthropicCapacityRequestOptions): Promise<ProviderCapacitySnapshot>;
9
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/capacity/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgC,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAM1F,MAAM,MAAM,+BAA+B,GAAG;IAC5C,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AA2HF,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,wBAAwB,CAsB7E;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,wBAAwB,CAAC,CAqCnC"}