@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
@@ -3,9 +3,9 @@ import {
3
3
  CODEX_APP_SERVER_ARGS,
4
4
  parseUsage,
5
5
  probeCodexCapacity,
6
- resolveCodexAuthPath,
7
- toRateWindow,
8
- } from "../../capacity/codex.js";
6
+ } from "../../capacity/sources/codex.js";
7
+ import { resolveCodexAuthPath } from "../../harnesses/codex/credentials.js";
8
+ import { toRateWindow } from "../../capacity/providers/openai-subscription.js";
9
9
 
10
10
  const checkedAt = "2026-08-20T10:00:00.000Z";
11
11
  const context = { installed: true, checkedAt };
@@ -52,9 +52,7 @@ describe("Codex auth resolution", () => {
52
52
  });
53
53
 
54
54
  it("falls back to ~/.codex/auth.json", () => {
55
- expect(resolveCodexAuthPath({ HOME: "/users/test" })).toBe(
56
- "/users/test/.codex/auth.json",
57
- );
55
+ expect(resolveCodexAuthPath({ HOME: "/users/test" })).toBe("/users/test/.codex/auth.json");
58
56
  });
59
57
  });
60
58
 
@@ -108,9 +106,7 @@ describe("tiered Codex probing", () => {
108
106
  status: 200,
109
107
  }),
110
108
  )
111
- .mockResolvedValueOnce(
112
- new Response(JSON.stringify(apiUsage()), { status: 200 }),
113
- );
109
+ .mockResolvedValueOnce(new Response(JSON.stringify(apiUsage()), { status: 200 }));
114
110
  const rpc = vi.fn();
115
111
  const result = await probeCodexCapacity({
116
112
  ...context,
@@ -129,9 +125,7 @@ describe("tiered Codex probing", () => {
129
125
  expect(fetch.mock.calls[0][0]).toBe(
130
126
  "https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami",
131
127
  );
132
- expect(fetch.mock.calls[1][0]).toBe(
133
- "https://chatgpt.com/backend-api/wham/usage",
134
- );
128
+ expect(fetch.mock.calls[1][0]).toBe("https://chatgpt.com/backend-api/wham/usage");
135
129
  expect(fetch.mock.calls[1][1].headers).toMatchObject({
136
130
  Authorization: "Bearer pat-secret",
137
131
  "ChatGPT-Account-Id": "acct-1",
@@ -154,9 +148,7 @@ describe("tiered Codex probing", () => {
154
148
  it("selects a fresh OAuth token without calling whoami", async () => {
155
149
  const fetch = vi
156
150
  .fn()
157
- .mockResolvedValue(
158
- new Response(JSON.stringify(apiUsage()), { status: 200 }),
159
- );
151
+ .mockResolvedValue(new Response(JSON.stringify(apiUsage()), { status: 200 }));
160
152
  const result = await probeCodexCapacity({
161
153
  ...context,
162
154
  readFile: async () =>
@@ -210,9 +202,7 @@ describe("tiered Codex probing", () => {
210
202
  ])("falls back to the CLI for %s", async (name, readFile) => {
211
203
  const fetch = vi
212
204
  .fn()
213
- .mockResolvedValue(
214
- new Response("", { status: name === "OAuth 401" ? 401 : 200 }),
215
- );
205
+ .mockResolvedValue(new Response("", { status: name === "OAuth 401" ? 401 : 200 }));
216
206
  const rpc = vi.fn(async () => ({
217
207
  rateLimits: {
218
208
  rateLimits: {
@@ -239,8 +229,7 @@ describe("tiered Codex probing", () => {
239
229
  }));
240
230
  const result = await probeCodexCapacity({
241
231
  ...context,
242
- readFile: async () =>
243
- JSON.stringify({ personal_access_token: "pat-secret" }),
232
+ readFile: async () => JSON.stringify({ personal_access_token: "pat-secret" }),
244
233
  fetch: vi.fn().mockRejectedValue(new Error("network failure pat-secret")),
245
234
  rpc,
246
235
  });
@@ -252,9 +241,7 @@ describe("tiered Codex probing", () => {
252
241
  const fetch = vi
253
242
  .fn()
254
243
  .mockRejectedValueOnce(new Error("PAT failed"))
255
- .mockResolvedValueOnce(
256
- new Response(JSON.stringify(apiUsage()), { status: 200 }),
257
- );
244
+ .mockResolvedValueOnce(new Response(JSON.stringify(apiUsage()), { status: 200 }));
258
245
  const rpc = vi.fn();
259
246
  const result = await probeCodexCapacity({
260
247
  ...context,
@@ -294,13 +281,7 @@ describe("tiered Codex probing", () => {
294
281
  "account/read",
295
282
  ]);
296
283
  expect(JSON.stringify(messages)).not.toMatch(/prompt|turn\/start/);
297
- expect(CODEX_APP_SERVER_ARGS).toEqual([
298
- "-s",
299
- "read-only",
300
- "-a",
301
- "untrusted",
302
- "app-server",
303
- ]);
284
+ expect(CODEX_APP_SERVER_ARGS).toEqual(["-s", "read-only", "-a", "untrusted", "app-server"]);
304
285
  });
305
286
 
306
287
  it("uses account/read to distinguish logged-out CLI state", async () => {
@@ -316,11 +297,7 @@ describe("tiered Codex probing", () => {
316
297
  });
317
298
 
318
299
  it("never exposes tokens or raw auth content through failures", async () => {
319
- const secrets = [
320
- "pat-secret-value",
321
- "oauth-secret-value",
322
- "refresh-secret-value",
323
- ];
300
+ const secrets = ["pat-secret-value", "oauth-secret-value", "refresh-secret-value"];
324
301
  const result = await probeCodexCapacity({
325
302
  ...context,
326
303
  readFile: async () =>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "openai-codex": {
3
3
  "type": "oauth",
4
- "access": "fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
4
+ "access": "sample access value for tests",
5
5
  "refresh": "fixture-refresh-token",
6
6
  "expires": 1793000000000,
7
7
  "accountId": "fixture-chatgpt-account-id"
@@ -2,14 +2,17 @@ import { readFile } from "node:fs/promises";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { describe, expect, it, vi } from "vitest";
5
+ import { probeOpenAiCapacity } from "../../capacity/sources/pi.js";
5
6
  import {
6
- buildOpenAiReport,
7
+ buildOpenAiPlatformCapacity,
7
8
  parseOpenAiUsage,
8
- probeOpenAiCapacity,
9
- resolveOpenAiCredential,
10
- } from "../../capacity/openai.js";
9
+ } from "../../capacity/providers/openai-platform.js";
10
+ import { resolvePiOpenAiCredential as resolveOpenAiCredential } from "../../harnesses/pi/credentials.js";
11
11
 
12
12
  const checkedAt = "2026-09-26T10:00:00.000Z";
13
+ const fixtureOauthAccess = "sample access value for tests";
14
+ const fakeJwt = (payload: string) =>
15
+ ["test", Buffer.from(payload).toString("base64url"), "test"].join(".");
13
16
  const fixture = (name: string) =>
14
17
  readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
15
18
  const fixtureString = (name: string) =>
@@ -59,7 +62,7 @@ describe("OpenAI tiered credential resolution", () => {
59
62
  openai: { type: "api_key", key: "pi-openai-test-key" },
60
63
  "openai-codex": {
61
64
  type: "oauth",
62
- access: "fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
65
+ access: fixtureOauthAccess,
63
66
  refresh: "fixture-refresh-token",
64
67
  expires: 1793000000000,
65
68
  accountId: "fixture-chatgpt-account-id",
@@ -83,7 +86,7 @@ describe("OpenAI tiered credential resolution", () => {
83
86
  }),
84
87
  ).resolves.toEqual({
85
88
  kind: "oauth",
86
- access: "fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
89
+ access: fixtureOauthAccess,
87
90
  accountId: "fixture-chatgpt-account-id",
88
91
  expiresMs: 1793000000000,
89
92
  });
@@ -148,7 +151,7 @@ describe("OpenAI OAuth capacity probe", () => {
148
151
  expect.objectContaining({
149
152
  method: "GET",
150
153
  headers: {
151
- Authorization: "Bearer fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
154
+ Authorization: `Bearer ${fixtureOauthAccess}`,
152
155
  "ChatGPT-Account-Id": "fixture-chatgpt-account-id",
153
156
  },
154
157
  }),
@@ -217,7 +220,7 @@ describe("OpenAI OAuth capacity probe", () => {
217
220
  const expiredJwtAuth = JSON.stringify({
218
221
  "openai-codex": {
219
222
  type: "oauth",
220
- access: "h.eyJleHAiOjE3ODkwMDAwMDB9.s",
223
+ access: fakeJwt(JSON.stringify({ exp: 1789000000 })),
221
224
  accountId: "fixture-chatgpt-account-id",
222
225
  },
223
226
  });
@@ -235,7 +238,7 @@ describe("OpenAI OAuth capacity probe", () => {
235
238
  const futureJwtAuth = JSON.stringify({
236
239
  "openai-codex": {
237
240
  type: "oauth",
238
- access: "h.eyJleHAiOjE3OTMwMDAwMDB9.s",
241
+ access: fakeJwt(JSON.stringify({ exp: 1793000000 })),
239
242
  accountId: "fixture-chatgpt-account-id",
240
243
  },
241
244
  });
@@ -255,7 +258,7 @@ describe("OpenAI OAuth capacity probe", () => {
255
258
  const auth = JSON.stringify({
256
259
  "openai-codex": {
257
260
  type: "oauth",
258
- access: "fixture-header.bm90LWpzb24.fixture-signature",
261
+ access: fakeJwt("not-json"),
259
262
  accountId: "fixture-chatgpt-account-id",
260
263
  },
261
264
  });
@@ -391,11 +394,8 @@ describe("OpenAI usage mapping", () => {
391
394
  ...parseOpenAiUsage(JSON.parse(await fixture("openai-usage-completions.json"))),
392
395
  ...parseOpenAiUsage(JSON.parse(await fixture("openai-usage-responses.json"))),
393
396
  ];
394
- const report = buildOpenAiReport(buckets, checkedAt);
397
+ const report = buildOpenAiPlatformCapacity(buckets, checkedAt);
395
398
  expect(report).toMatchObject({
396
- harness: "pi",
397
- provider: "openai",
398
- generatedAt: checkedAt,
399
399
  authenticated: true,
400
400
  available: "yes",
401
401
  creditsRemaining: null,
@@ -427,7 +427,7 @@ describe("OpenAI usage mapping", () => {
427
427
  });
428
428
 
429
429
  it("reports zero usage for days without buckets", () => {
430
- const report = buildOpenAiReport([], checkedAt);
430
+ const report = buildOpenAiPlatformCapacity([], checkedAt);
431
431
  expect(report.windows.map((window) => window.current)).toEqual([0, 0]);
432
432
  expect(report.windows[0].resetsAt).toBe("2026-09-27T00:00:00.000Z");
433
433
  });
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { describe, expect, it } from "vitest";
4
- import { parseWhamUsage, toRateWindow } from "../../capacity/wham.js";
4
+ import { parseWhamUsage, toRateWindow } from "../../capacity/providers/openai-subscription.js";
5
5
 
6
6
  const fixture = (name: string) =>
7
7
  readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
@@ -1,18 +1,13 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { describe, expect, it, vi } from "vitest";
4
- import {
5
- parseZaiQuota,
6
- probeZaiCapacity,
7
- resolveZaiApiKey,
8
- } from "../../capacity/zai.js";
4
+ import { parseZaiCapacity } from "../../capacity/providers/zai.js";
5
+ import { probeZaiCapacity } from "../../capacity/sources/pi.js";
6
+ import { resolvePiZaiApiKey as resolveZaiApiKey } from "../../harnesses/pi/credentials.js";
9
7
 
10
8
  const checkedAt = "2026-08-20T10:00:00.000Z";
11
9
  const fixture = (name: string) =>
12
- readFile(
13
- fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)),
14
- "utf8",
15
- );
10
+ readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
16
11
 
17
12
  describe("z.ai credential resolution", () => {
18
13
  it("prefers Z_AI_API_KEY without reading Pi auth", async () => {
@@ -31,44 +26,28 @@ describe("z.ai credential resolution", () => {
31
26
  await expect(
32
27
  resolveZaiApiKey({ env: { HOME: "/users/test" }, readFile: readAuth }),
33
28
  ).resolves.toBe("pi-zai-test-key");
34
- expect(readAuth).toHaveBeenCalledWith(
35
- "/users/test/.pi/agent/auth.json",
36
- "utf8",
37
- );
29
+ expect(readAuth).toHaveBeenCalledWith("/users/test/.pi/agent/auth.json", "utf8");
38
30
  });
39
31
 
40
32
  it.each([
41
33
  [
42
34
  "missing",
43
- async () =>
44
- Promise.reject(Object.assign(new Error("missing"), { code: "ENOENT" })),
35
+ async () => Promise.reject(Object.assign(new Error("missing"), { code: "ENOENT" })),
45
36
  ],
46
37
  ["invalid JSON", async () => "{"],
47
- [
48
- "wrong credential type",
49
- async () => JSON.stringify({ zai: { type: "oauth", key: "x" } }),
50
- ],
38
+ ["wrong credential type", async () => JSON.stringify({ zai: { type: "oauth", key: "x" } })],
51
39
  ["missing key", async () => JSON.stringify({ zai: { type: "api_key" } })],
52
- ])(
53
- "fails clearly for %s credentials without exposing file content",
54
- async (_name, readAuth) => {
55
- await expect(
56
- resolveZaiApiKey({ env: { HOME: "/users/test" }, readFile: readAuth }),
57
- ).rejects.toThrow(/z\.ai API key|z\.ai Pi auth file/);
58
- },
59
- );
40
+ ])("fails clearly for %s credentials without exposing file content", async (_name, readAuth) => {
41
+ await expect(
42
+ resolveZaiApiKey({ env: { HOME: "/users/test" }, readFile: readAuth }),
43
+ ).rejects.toThrow(/z\.ai API key|z\.ai Pi auth file/);
44
+ });
60
45
  });
61
46
 
62
47
  describe("z.ai quota mapping", () => {
63
48
  it("maps token, credit, and monthly MCP windows with recomputed usage", async () => {
64
- const report = parseZaiQuota(
65
- JSON.parse(await fixture("zai-quota.json")),
66
- checkedAt,
67
- );
49
+ const report = parseZaiCapacity(JSON.parse(await fixture("zai-quota.json")));
68
50
  expect(report).toMatchObject({
69
- harness: "pi",
70
- provider: "zai",
71
- generatedAt: checkedAt,
72
51
  authenticated: true,
73
52
  available: "yes",
74
53
  creditsRemaining: null,
@@ -111,40 +90,26 @@ describe("z.ai quota mapping", () => {
111
90
  });
112
91
 
113
92
  it("uses and clamps the server percentage when quota amounts are unavailable", () => {
114
- const report = parseZaiQuota(
115
- {
116
- success: true,
117
- code: 200,
118
- data: {
119
- limits: [
120
- { type: "TOKENS_LIMIT", unit: 1, number: 1, percentage: 120 },
121
- { type: "CREDIT_LIMIT", unit: 5, number: 30, percentage: -5 },
122
- ],
123
- },
93
+ const report = parseZaiCapacity({
94
+ success: true,
95
+ code: 200,
96
+ data: {
97
+ limits: [
98
+ { type: "TOKENS_LIMIT", unit: 1, number: 1, percentage: 120 },
99
+ { type: "CREDIT_LIMIT", unit: 5, number: 30, percentage: -5 },
100
+ ],
124
101
  },
125
- checkedAt,
126
- );
127
- expect(report.windows.map((window) => window.usedPercent)).toEqual([
128
- 100, 0,
129
- ]);
102
+ });
103
+ expect(report.windows.map((window) => window.usedPercent)).toEqual([100, 0]);
130
104
  });
131
105
 
132
106
  it.each([
133
- [
134
- "invalid fixture",
135
- async () => JSON.parse(await fixture("zai-quota-invalid.json")),
136
- ],
137
- [
138
- "unsuccessful envelope",
139
- async () => ({ success: false, code: 401, data: { limits: [] } }),
140
- ],
141
- [
142
- "invalid entry",
143
- async () => ({ success: true, code: 200, data: { limits: [{}] } }),
144
- ],
107
+ ["invalid fixture", async () => JSON.parse(await fixture("zai-quota-invalid.json"))],
108
+ ["unsuccessful envelope", async () => ({ success: false, code: 401, data: { limits: [] } })],
109
+ ["invalid entry", async () => ({ success: true, code: 200, data: { limits: [{}] } })],
145
110
  ])("rejects %s", async (_name, input) => {
146
111
  const value = await input();
147
- expect(() => parseZaiQuota(value, checkedAt)).toThrow(/z\.ai quota/);
112
+ expect(() => parseZaiCapacity(value)).toThrow(/z\.ai quota/);
148
113
  });
149
114
  });
150
115
 
@@ -3,10 +3,10 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { afterEach, describe, expect, it, vi } from "vitest";
5
5
  import {
6
- ClaudePrintAgentService,
7
6
  DurableAgentRepository,
8
7
  type ProcessInspector,
9
- } from "../../../../index.js";
8
+ } from "../../../../durable/DurableAgentRepository.js";
9
+ import { ClaudePrintAgentService } from "../../../../harnesses/claude/durable/ClaudePrintAgentService.js";
10
10
 
11
11
  const roots: string[] = [];
12
12
 
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import { PassThrough, Writable } from "node:stream";
3
3
  import { describe, expect, it, vi } from "vitest";
4
- import type { DurableAgent } from "../../../../index.js";
4
+ import type { DurableAgent } from "../../../../durable/DurableAgent.js";
5
5
  import { ClaudePrintRunner } from "../../../../harnesses/claude/durable/ClaudePrintRunner.js";
6
6
 
7
7
  function agent(): DurableAgent {
@@ -1,9 +1,8 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
+ import { CodexCliProbe } from "../../../../harnesses/codex/durable/CodexCliProbe.js";
2
3
 
3
4
  describe("CodexCliProbe", () => {
4
5
  it("validates version, exec JSON/stdin, and resume capabilities without a model call", async () => {
5
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
6
- expect(api).toHaveProperty("CodexCliProbe");
7
6
  const exec = vi
8
7
  .fn()
9
8
  .mockResolvedValueOnce({ stdout: "codex-cli 0.147.0", stderr: "" })
@@ -15,12 +14,12 @@ describe("CodexCliProbe", () => {
15
14
  stdout: "Usage: codex exec resume [SESSION_ID] [PROMPT]\n--json\n- stdin",
16
15
  stderr: "",
17
16
  });
18
- const Probe = api.CodexCliProbe as new (options: unknown) => any;
19
-
20
- await expect(new Probe({ executable: "fake-codex", exec }).validate()).resolves.toEqual({
21
- executable: "fake-codex",
22
- version: "codex-cli 0.147.0",
23
- });
17
+ await expect(new CodexCliProbe({ executable: "fake-codex", exec }).validate()).resolves.toEqual(
18
+ {
19
+ executable: "fake-codex",
20
+ version: "codex-cli 0.147.0",
21
+ },
22
+ );
24
23
  expect(exec.mock.calls).toEqual([
25
24
  ["fake-codex", ["--version"]],
26
25
  ["fake-codex", ["exec", "--help"]],
@@ -29,9 +28,7 @@ describe("CodexCliProbe", () => {
29
28
  });
30
29
 
31
30
  it("rejects unsupported and unavailable CLIs with bounded sanitized errors", async () => {
32
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
33
- const Probe = api.CodexCliProbe as new (options: unknown) => any;
34
- const unsupported = new Probe({
31
+ const unsupported = new CodexCliProbe({
35
32
  exec: vi
36
33
  .fn()
37
34
  .mockResolvedValueOnce({ stdout: "version", stderr: "" })
@@ -39,7 +36,7 @@ describe("CodexCliProbe", () => {
39
36
  .mockResolvedValueOnce({ stdout: "resume", stderr: "" }),
40
37
  });
41
38
  await expect(unsupported.validate()).rejects.toMatchObject({ code: "CODEX_CLI_UNSUPPORTED" });
42
- const missingCommands = new Probe({
39
+ const missingCommands = new CodexCliProbe({
43
40
  exec: vi
44
41
  .fn()
45
42
  .mockResolvedValueOnce({ stdout: "version", stderr: "" })
@@ -50,7 +47,7 @@ describe("CodexCliProbe", () => {
50
47
  code: "CODEX_CLI_UNSUPPORTED",
51
48
  });
52
49
 
53
- const unavailable = new Probe({
50
+ const unavailable = new CodexCliProbe({
54
51
  exec: vi.fn().mockRejectedValue(new Error(`bad\0${"x".repeat(1000)}`)),
55
52
  });
56
53
  const error = await unavailable.validate().catch((value: Error & { code: string }) => value);
@@ -60,25 +57,23 @@ describe("CodexCliProbe", () => {
60
57
  });
61
58
 
62
59
  it("reports an empty version response as unknown", async () => {
63
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
64
- const Probe = api.CodexCliProbe as new (options: unknown) => any;
65
60
  const exec = vi
66
61
  .fn()
67
62
  .mockResolvedValueOnce({ stdout: " \n", stderr: "" })
68
63
  .mockResolvedValueOnce({ stdout: "exec --json -", stderr: "" })
69
64
  .mockResolvedValueOnce({ stdout: "resume --json -", stderr: "" });
70
- await expect(new Probe({ exec }).validate()).resolves.toMatchObject({ version: "unknown" });
65
+ await expect(new CodexCliProbe({ exec }).validate()).resolves.toMatchObject({
66
+ version: "unknown",
67
+ });
71
68
  });
72
69
 
73
70
  it("requires a standalone stdin dash rather than accepting flag hyphens", async () => {
74
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
75
- const Probe = api.CodexCliProbe as new (options: unknown) => any;
76
71
  const exec = vi
77
72
  .fn()
78
73
  .mockResolvedValueOnce({ stdout: "version", stderr: "" })
79
74
  .mockResolvedValueOnce({ stdout: "exec --json", stderr: "" })
80
75
  .mockResolvedValueOnce({ stdout: "resume --json", stderr: "" });
81
- await expect(new Probe({ exec }).validate()).rejects.toMatchObject({
76
+ await expect(new CodexCliProbe({ exec }).validate()).rejects.toMatchObject({
82
77
  code: "CODEX_CLI_UNSUPPORTED",
83
78
  });
84
79
  });
@@ -2,12 +2,12 @@ import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { afterEach, describe, expect, it, vi } from "vitest";
5
+ import { CodexPrintError } from "../../../../durable/DurableAgent.js";
5
6
  import {
6
- CodexPrintError,
7
- CodexPrintAgentService,
8
7
  DurableAgentRepository,
9
8
  type ProcessInspector,
10
- } from "../../../../index.js";
9
+ } from "../../../../durable/DurableAgentRepository.js";
10
+ import { CodexPrintAgentService } from "../../../../harnesses/codex/durable/CodexPrintAgentService.js";
11
11
 
12
12
  const SESSION = "22222222-2222-4222-8222-222222222222";
13
13
  const roots: string[] = [];
@@ -1,4 +1,6 @@
1
1
  import { describe, expect, it, vi } from "vitest";
2
+ import { CodexPrintError } from "../../../../durable/DurableAgent.js";
3
+ import { CodexPrintAgentService } from "../../../../harnesses/codex/durable/CodexPrintAgentService.js";
2
4
 
3
5
  const SESSION = "22222222-2222-4222-8222-222222222222";
4
6
  const base = {
@@ -11,15 +13,15 @@ const base = {
11
13
 
12
14
  describe("CodexPrintAgentService", () => {
13
15
  it("validates before provider-aware create and never runs Codex", async () => {
14
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
15
- expect(api).toHaveProperty("CodexPrintAgentService");
16
16
  const probe = {
17
17
  validate: vi.fn().mockResolvedValue({ executable: "codex", version: "0.147.0" }),
18
18
  };
19
19
  const repository = { create: vi.fn().mockResolvedValue(base) };
20
20
  const runner = { run: vi.fn() };
21
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
22
- await new Service({ repository, probe, runner }).create({ name: "reviewer", cwd: "/project" });
21
+ await new CodexPrintAgentService({ repository, probe, runner }).create({
22
+ name: "reviewer",
23
+ cwd: "/project",
24
+ });
23
25
  expect(repository.create).toHaveBeenCalledWith({
24
26
  name: "reviewer",
25
27
  cwd: "/project",
@@ -29,7 +31,6 @@ describe("CodexPrintAgentService", () => {
29
31
  });
30
32
 
31
33
  it("binds during first send and explicitly resumes later sends", async () => {
32
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
33
34
  const repository = {
34
35
  resolve: vi.fn().mockResolvedValue(base),
35
36
  acquireRun: vi
@@ -50,8 +51,7 @@ describe("CodexPrintAgentService", () => {
50
51
  return { sessionId: SESSION, result: "answer", messages: ["answer"], exitCode: 0 };
51
52
  }),
52
53
  };
53
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
54
- const service = new Service({
54
+ const service = new CodexPrintAgentService({
55
55
  repository,
56
56
  probe: { validate: vi.fn() },
57
57
  runner,
@@ -74,8 +74,6 @@ describe("CodexPrintAgentService", () => {
74
74
  });
75
75
 
76
76
  it("records mismatch separately from unknown failures", async () => {
77
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
78
- const ErrorType = api.CodexPrintError as new (message: string, code: string) => Error;
79
77
  const completeRun = vi.fn();
80
78
  const repository = {
81
79
  resolve: vi.fn().mockResolvedValue(base),
@@ -84,12 +82,11 @@ describe("CodexPrintAgentService", () => {
84
82
  bindProviderSession: vi.fn(),
85
83
  completeRun,
86
84
  };
87
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
88
- const service = new Service({
85
+ const service = new CodexPrintAgentService({
89
86
  repository,
90
87
  probe: { validate: vi.fn() },
91
88
  runner: {
92
- run: vi.fn().mockRejectedValue(new ErrorType("mismatch", "CODEX_SESSION_MISMATCH")),
89
+ run: vi.fn().mockRejectedValue(new CodexPrintError("mismatch", "CODEX_SESSION_MISMATCH")),
93
90
  },
94
91
  });
95
92
  await expect(service.send("reviewer", "x")).rejects.toMatchObject({
@@ -103,8 +100,6 @@ describe("CodexPrintAgentService", () => {
103
100
  });
104
101
 
105
102
  it("rejects a non-Codex target without acquiring or mutating it", async () => {
106
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
107
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
108
103
  const repository = {
109
104
  resolve: vi.fn().mockResolvedValue({ ...base, provider: "claude" }),
110
105
  acquireRun: vi.fn(),
@@ -114,18 +109,17 @@ describe("CodexPrintAgentService", () => {
114
109
  };
115
110
 
116
111
  await expect(
117
- new Service({ repository, probe: { validate: vi.fn() }, runner: { run: vi.fn() } }).send(
118
- "reviewer",
119
- "x",
120
- ),
112
+ new CodexPrintAgentService({
113
+ repository,
114
+ probe: { validate: vi.fn() },
115
+ runner: { run: vi.fn() },
116
+ }).send("reviewer", "x"),
121
117
  ).rejects.toMatchObject({ code: "CODEX_UNSUPPORTED" });
122
118
  expect(repository.acquireRun).not.toHaveBeenCalled();
123
119
  expect(repository.completeRun).not.toHaveBeenCalled();
124
120
  });
125
121
 
126
122
  it("does not turn a successful completion write failure into a second completion", async () => {
127
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
128
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
129
123
  const completionFailure = new Error("completion failed");
130
124
  const repository = {
131
125
  resolve: vi.fn().mockResolvedValue(base),
@@ -144,14 +138,15 @@ describe("CodexPrintAgentService", () => {
144
138
  };
145
139
 
146
140
  await expect(
147
- new Service({ repository, probe: { validate: vi.fn() }, runner }).send("reviewer", "x"),
141
+ new CodexPrintAgentService({ repository, probe: { validate: vi.fn() }, runner }).send(
142
+ "reviewer",
143
+ "x",
144
+ ),
148
145
  ).rejects.toBe(completionFailure);
149
146
  expect(repository.completeRun).toHaveBeenCalledOnce();
150
147
  });
151
148
 
152
149
  it("records a repository binding conflict as a session mismatch", async () => {
153
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
154
- const BindingError = api.CodexPrintError as new (message: string, code: string) => Error;
155
150
  const completeRun = vi.fn();
156
151
  const repository = {
157
152
  resolve: vi.fn().mockResolvedValue(base),
@@ -159,7 +154,7 @@ describe("CodexPrintAgentService", () => {
159
154
  recordProviderProcess: vi.fn(),
160
155
  bindProviderSession: vi
161
156
  .fn()
162
- .mockRejectedValue(new BindingError("binding mismatch", "CODEX_SESSION_MISMATCH")),
157
+ .mockRejectedValue(new CodexPrintError("binding mismatch", "CODEX_SESSION_MISMATCH")),
163
158
  completeRun,
164
159
  };
165
160
  const runner = {
@@ -168,10 +163,11 @@ describe("CodexPrintAgentService", () => {
168
163
  return { sessionId: SESSION, result: "x", messages: ["x"], exitCode: 0 };
169
164
  }),
170
165
  };
171
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
172
-
173
166
  await expect(
174
- new Service({ repository, probe: { validate: vi.fn() }, runner }).send("reviewer", "x"),
167
+ new CodexPrintAgentService({ repository, probe: { validate: vi.fn() }, runner }).send(
168
+ "reviewer",
169
+ "x",
170
+ ),
175
171
  ).rejects.toMatchObject({ code: "CODEX_SESSION_MISMATCH" });
176
172
  expect(completeRun).toHaveBeenCalledWith(
177
173
  "id",
@@ -181,8 +177,6 @@ describe("CodexPrintAgentService", () => {
181
177
  });
182
178
 
183
179
  it("rejects missing and ambiguous records before acquiring a run", async () => {
184
- const api = (await import("../../../../index.js")) as Record<string, unknown>;
185
- const Service = api.CodexPrintAgentService as new (options: unknown) => any;
186
180
  const repository = {
187
181
  create: vi.fn(),
188
182
  resolve: vi.fn().mockResolvedValueOnce(null).mockResolvedValueOnce([base, base]),
@@ -191,7 +185,7 @@ describe("CodexPrintAgentService", () => {
191
185
  bindProviderSession: vi.fn(),
192
186
  completeRun: vi.fn(),
193
187
  };
194
- const service = new Service({
188
+ const service = new CodexPrintAgentService({
195
189
  repository,
196
190
  probe: { validate: vi.fn() },
197
191
  runner: { run: vi.fn() },