@ai-devkit/agent-manager 0.37.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/dist/AgentManager.d.ts +0 -4
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +2 -2
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/capacity/anthropic.test.js +115 -0
  6. package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
  7. package/dist/__tests__/capacity/boundaries.test.js +45 -0
  8. package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
  9. package/dist/__tests__/capacity/claude.test.js +3 -3
  10. package/dist/__tests__/capacity/claude.test.js.map +1 -1
  11. package/dist/__tests__/capacity/codex.test.js +3 -1
  12. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  13. package/dist/__tests__/capacity/openai.test.js +21 -12
  14. package/dist/__tests__/capacity/openai.test.js.map +1 -1
  15. package/dist/__tests__/capacity/wham.test.js +1 -1
  16. package/dist/__tests__/capacity/wham.test.js.map +1 -1
  17. package/dist/__tests__/capacity/zai.test.js +7 -8
  18. package/dist/__tests__/capacity/zai.test.js.map +1 -1
  19. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +2 -1
  20. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -1
  21. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -1
  22. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +7 -15
  23. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -1
  24. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +3 -1
  25. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -1
  26. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +11 -26
  27. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -1
  28. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +3 -7
  29. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -1
  30. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js +597 -0
  31. package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -0
  32. package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js +91 -0
  33. package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js.map +1 -0
  34. package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js +192 -0
  35. package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js.map +1 -0
  36. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js +407 -0
  37. package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -0
  38. package/dist/__tests__/harnesses/devin/fixtures.js +95 -0
  39. package/dist/__tests__/harnesses/devin/fixtures.js.map +1 -0
  40. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +5 -11
  41. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
  42. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
  43. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
  44. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
  45. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
  46. package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +95 -11
  47. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
  48. package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
  49. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
  50. package/dist/__tests__/print/DurableAgent.test.js +4 -6
  51. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  52. package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
  53. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  54. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  55. package/dist/__tests__/terminal/GhosttyBackend.test.js +334 -0
  56. package/dist/__tests__/terminal/GhosttyBackend.test.js.map +1 -0
  57. package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
  58. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  59. package/dist/adapters/AgentAdapter.d.ts +1 -1
  60. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  61. package/dist/adapters/AgentAdapter.js +2 -1
  62. package/dist/adapters/AgentAdapter.js.map +1 -1
  63. package/dist/capacity/index.d.ts +9 -19
  64. package/dist/capacity/index.d.ts.map +1 -1
  65. package/dist/capacity/index.js +11 -4
  66. package/dist/capacity/index.js.map +1 -1
  67. package/dist/capacity/providers/anthropic.d.ts +9 -0
  68. package/dist/capacity/providers/anthropic.d.ts.map +1 -0
  69. package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
  70. package/dist/capacity/providers/anthropic.js.map +1 -0
  71. package/dist/capacity/providers/openai-platform.d.ts +14 -0
  72. package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
  73. package/dist/capacity/providers/openai-platform.js +120 -0
  74. package/dist/capacity/providers/openai-platform.js.map +1 -0
  75. package/dist/capacity/providers/openai-subscription.d.ts +20 -0
  76. package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
  77. package/dist/capacity/providers/openai-subscription.js +129 -0
  78. package/dist/capacity/providers/openai-subscription.js.map +1 -0
  79. package/dist/capacity/providers/zai.d.ts +8 -0
  80. package/dist/capacity/providers/zai.d.ts.map +1 -0
  81. package/dist/capacity/{zai.js → providers/zai.js} +17 -62
  82. package/dist/capacity/providers/zai.js.map +1 -0
  83. package/dist/capacity/sources/claude.d.ts +9 -0
  84. package/dist/capacity/sources/claude.d.ts.map +1 -0
  85. package/dist/capacity/sources/claude.js +17 -0
  86. package/dist/capacity/sources/claude.js.map +1 -0
  87. package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
  88. package/dist/capacity/sources/codex.d.ts.map +1 -0
  89. package/dist/capacity/{codex.js → sources/codex.js} +31 -84
  90. package/dist/capacity/sources/codex.js.map +1 -0
  91. package/dist/capacity/sources/pi.d.ts +30 -0
  92. package/dist/capacity/sources/pi.d.ts.map +1 -0
  93. package/dist/capacity/sources/pi.js +81 -0
  94. package/dist/capacity/sources/pi.js.map +1 -0
  95. package/dist/capacity/types.d.ts +2 -0
  96. package/dist/capacity/types.d.ts.map +1 -1
  97. package/dist/capacity/types.js +1 -1
  98. package/dist/capacity/types.js.map +1 -1
  99. package/dist/harnesses/claude/credentials.d.ts +10 -0
  100. package/dist/harnesses/claude/credentials.d.ts.map +1 -0
  101. package/dist/harnesses/claude/credentials.js +112 -0
  102. package/dist/harnesses/claude/credentials.js.map +1 -0
  103. package/dist/harnesses/claude/readiness.d.ts +3 -0
  104. package/dist/harnesses/claude/readiness.d.ts.map +1 -0
  105. package/dist/harnesses/claude/readiness.js +63 -0
  106. package/dist/harnesses/claude/readiness.js.map +1 -0
  107. package/dist/harnesses/codex/credentials.d.ts +15 -0
  108. package/dist/harnesses/codex/credentials.d.ts.map +1 -0
  109. package/dist/harnesses/codex/credentials.js +58 -0
  110. package/dist/harnesses/codex/credentials.js.map +1 -0
  111. package/dist/harnesses/codex/readiness.d.ts +3 -0
  112. package/dist/harnesses/codex/readiness.d.ts.map +1 -0
  113. package/dist/harnesses/codex/readiness.js +60 -0
  114. package/dist/harnesses/codex/readiness.js.map +1 -0
  115. package/dist/harnesses/copilot/readiness.d.ts +3 -0
  116. package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
  117. package/dist/harnesses/copilot/readiness.js +39 -0
  118. package/dist/harnesses/copilot/readiness.js.map +1 -0
  119. package/dist/harnesses/devin/DevinAdapter.d.ts +39 -0
  120. package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -0
  121. package/dist/harnesses/devin/DevinAdapter.js +177 -0
  122. package/dist/harnesses/devin/DevinAdapter.js.map +1 -0
  123. package/dist/harnesses/devin/DevinAgentMapper.d.ts +11 -0
  124. package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -0
  125. package/dist/harnesses/devin/DevinAgentMapper.js +35 -0
  126. package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -0
  127. package/dist/harnesses/devin/DevinSessionLocator.d.ts +46 -0
  128. package/dist/harnesses/devin/DevinSessionLocator.d.ts.map +1 -0
  129. package/dist/harnesses/devin/DevinSessionLocator.js +176 -0
  130. package/dist/harnesses/devin/DevinSessionLocator.js.map +1 -0
  131. package/dist/harnesses/devin/DevinSessionParser.d.ts +29 -0
  132. package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -0
  133. package/dist/harnesses/devin/DevinSessionParser.js +166 -0
  134. package/dist/harnesses/devin/DevinSessionParser.js.map +1 -0
  135. package/dist/harnesses/devin/readiness.d.ts +3 -0
  136. package/dist/harnesses/devin/readiness.d.ts.map +1 -0
  137. package/dist/harnesses/devin/readiness.js +39 -0
  138. package/dist/harnesses/devin/readiness.js.map +1 -0
  139. package/dist/harnesses/index.d.ts.map +1 -1
  140. package/dist/harnesses/index.js +3 -1
  141. package/dist/harnesses/index.js.map +1 -1
  142. package/dist/harnesses/opencode/readiness.d.ts +3 -0
  143. package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
  144. package/dist/harnesses/opencode/readiness.js +50 -0
  145. package/dist/harnesses/opencode/readiness.js.map +1 -0
  146. package/dist/harnesses/pi/credentials.d.ts +22 -0
  147. package/dist/harnesses/pi/credentials.d.ts.map +1 -0
  148. package/dist/harnesses/pi/credentials.js +98 -0
  149. package/dist/harnesses/pi/credentials.js.map +1 -0
  150. package/dist/harnesses/pi/readiness.d.ts +3 -0
  151. package/dist/harnesses/pi/readiness.d.ts.map +1 -0
  152. package/dist/harnesses/pi/readiness.js +96 -0
  153. package/dist/harnesses/pi/readiness.js.map +1 -0
  154. package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
  155. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
  156. package/dist/harnesses/readiness/AgentReadiness.js +70 -0
  157. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
  158. package/dist/harnesses/readiness/checks.d.ts +31 -0
  159. package/dist/harnesses/readiness/checks.d.ts.map +1 -0
  160. package/dist/harnesses/readiness/checks.js +270 -0
  161. package/dist/harnesses/readiness/checks.js.map +1 -0
  162. package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
  163. package/dist/harnesses/readiness/types.d.ts.map +1 -0
  164. package/dist/harnesses/readiness/types.js +4 -0
  165. package/dist/harnesses/readiness/types.js.map +1 -0
  166. package/dist/harnesses/runtimeProfiles.d.ts +11 -0
  167. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
  168. package/dist/harnesses/runtimeProfiles.js +100 -0
  169. package/dist/harnesses/runtimeProfiles.js.map +1 -0
  170. package/dist/index.d.ts +16 -42
  171. package/dist/index.d.ts.map +1 -1
  172. package/dist/index.js +9 -23
  173. package/dist/index.js.map +1 -1
  174. package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
  175. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
  176. package/dist/runtime/ManagedAgentRuntime.js +6 -20
  177. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  178. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
  179. package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
  180. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  181. package/dist/runtime/tmux/PidPolling.d.ts +1 -1
  182. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
  183. package/dist/runtime/tmux/PidPolling.js.map +1 -1
  184. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
  185. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
  186. package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
  187. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
  188. package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
  189. package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
  190. package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
  191. package/dist/runtime/tmux/TmuxManager.js.map +1 -0
  192. package/dist/runtime/types.d.ts +1 -1
  193. package/dist/runtime/types.d.ts.map +1 -1
  194. package/dist/runtime/types.js.map +1 -1
  195. package/dist/terminal/TerminalFocusManager.d.ts +4 -32
  196. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  197. package/dist/terminal/TerminalFocusManager.js +17 -267
  198. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  199. package/dist/terminal/TtyWriter.d.ts +1 -44
  200. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  201. package/dist/terminal/TtyWriter.js +12 -347
  202. package/dist/terminal/TtyWriter.js.map +1 -1
  203. package/dist/terminal/backends/ghostty.d.ts +3 -0
  204. package/dist/terminal/backends/ghostty.d.ts.map +1 -0
  205. package/dist/terminal/backends/ghostty.js +161 -0
  206. package/dist/terminal/backends/ghostty.js.map +1 -0
  207. package/dist/terminal/backends/index.d.ts +5 -0
  208. package/dist/terminal/backends/index.d.ts.map +1 -0
  209. package/dist/terminal/backends/index.js +21 -0
  210. package/dist/terminal/backends/index.js.map +1 -0
  211. package/dist/terminal/backends/iterm2.d.ts +3 -0
  212. package/dist/terminal/backends/iterm2.d.ts.map +1 -0
  213. package/dist/terminal/backends/iterm2.js +135 -0
  214. package/dist/terminal/backends/iterm2.js.map +1 -0
  215. package/dist/terminal/backends/shared.d.ts +9 -0
  216. package/dist/terminal/backends/shared.d.ts.map +1 -0
  217. package/dist/terminal/backends/shared.js +38 -0
  218. package/dist/terminal/backends/shared.js.map +1 -0
  219. package/dist/terminal/backends/terminal-app.d.ts +3 -0
  220. package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
  221. package/dist/terminal/backends/terminal-app.js +129 -0
  222. package/dist/terminal/backends/terminal-app.js.map +1 -0
  223. package/dist/terminal/backends/tmux.d.ts +3 -0
  224. package/dist/terminal/backends/tmux.d.ts.map +1 -0
  225. package/dist/terminal/backends/tmux.js +76 -0
  226. package/dist/terminal/backends/tmux.js.map +1 -0
  227. package/dist/terminal/backends/wezterm.d.ts +3 -0
  228. package/dist/terminal/backends/wezterm.d.ts.map +1 -0
  229. package/dist/terminal/backends/wezterm.js +71 -0
  230. package/dist/terminal/backends/wezterm.js.map +1 -0
  231. package/dist/terminal/types.d.ts +22 -0
  232. package/dist/terminal/types.d.ts.map +1 -0
  233. package/dist/terminal/types.js +11 -0
  234. package/dist/terminal/types.js.map +1 -0
  235. package/dist/utils/process.d.ts +2 -0
  236. package/dist/utils/process.d.ts.map +1 -1
  237. package/dist/utils/process.js +3 -0
  238. package/dist/utils/process.js.map +1 -1
  239. package/package.json +1 -1
  240. package/src/AgentManager.ts +1 -1
  241. package/src/__tests__/capacity/anthropic.test.ts +105 -0
  242. package/src/__tests__/capacity/boundaries.test.ts +36 -0
  243. package/src/__tests__/capacity/claude.test.ts +3 -8
  244. package/src/__tests__/capacity/codex.test.ts +12 -35
  245. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
  246. package/src/__tests__/capacity/openai.test.ts +15 -15
  247. package/src/__tests__/capacity/wham.test.ts +1 -1
  248. package/src/__tests__/capacity/zai.test.ts +27 -62
  249. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
  250. package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
  251. package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
  252. package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
  253. package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
  254. package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
  255. package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +292 -0
  256. package/src/__tests__/harnesses/devin/DevinAgentMapper.test.ts +88 -0
  257. package/src/__tests__/harnesses/devin/DevinSessionLocator.test.ts +139 -0
  258. package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +218 -0
  259. package/src/__tests__/harnesses/devin/fixtures.ts +144 -0
  260. package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
  261. package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
  262. package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
  263. package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +77 -9
  264. package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
  265. package/src/__tests__/print/DurableAgent.test.ts +4 -13
  266. package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
  267. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
  268. package/src/__tests__/terminal/GhosttyBackend.test.ts +271 -0
  269. package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
  270. package/src/adapters/AgentAdapter.ts +1 -0
  271. package/src/capacity/index.ts +29 -23
  272. package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
  273. package/src/capacity/providers/openai-platform.ts +150 -0
  274. package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
  275. package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
  276. package/src/capacity/sources/claude.ts +30 -0
  277. package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
  278. package/src/capacity/sources/pi.ts +131 -0
  279. package/src/capacity/types.ts +3 -0
  280. package/src/harnesses/claude/credentials.ts +122 -0
  281. package/src/harnesses/claude/readiness.ts +69 -0
  282. package/src/harnesses/codex/credentials.ts +81 -0
  283. package/src/harnesses/codex/readiness.ts +72 -0
  284. package/src/harnesses/copilot/readiness.ts +33 -0
  285. package/src/harnesses/devin/DevinAdapter.ts +224 -0
  286. package/src/harnesses/devin/DevinAgentMapper.ts +43 -0
  287. package/src/harnesses/devin/DevinSessionLocator.ts +230 -0
  288. package/src/harnesses/devin/DevinSessionParser.ts +236 -0
  289. package/src/harnesses/devin/readiness.ts +36 -0
  290. package/src/harnesses/index.ts +2 -0
  291. package/src/harnesses/opencode/readiness.ts +48 -0
  292. package/src/harnesses/pi/credentials.ts +129 -0
  293. package/src/harnesses/pi/readiness.ts +104 -0
  294. package/src/harnesses/readiness/AgentReadiness.ts +89 -0
  295. package/src/harnesses/readiness/checks.ts +336 -0
  296. package/src/harnesses/readiness/types.ts +90 -0
  297. package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +35 -38
  298. package/src/index.ts +15 -128
  299. package/src/runtime/ManagedAgentRuntime.ts +7 -22
  300. package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
  301. package/src/runtime/tmux/PidPolling.ts +1 -1
  302. package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
  303. package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
  304. package/src/runtime/types.ts +1 -1
  305. package/src/terminal/TerminalFocusManager.ts +19 -292
  306. package/src/terminal/TtyWriter.ts +15 -335
  307. package/src/terminal/backends/ghostty.ts +180 -0
  308. package/src/terminal/backends/index.ts +23 -0
  309. package/src/terminal/backends/iterm2.ts +126 -0
  310. package/src/terminal/backends/shared.ts +47 -0
  311. package/src/terminal/backends/terminal-app.ts +122 -0
  312. package/src/terminal/backends/tmux.ts +62 -0
  313. package/src/terminal/backends/wezterm.ts +65 -0
  314. package/src/terminal/types.ts +23 -0
  315. package/src/utils/process.ts +5 -0
  316. package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
  317. package/dist/__tests__/utils/agents.test.js +0 -93
  318. package/dist/__tests__/utils/agents.test.js.map +0 -1
  319. package/dist/capacity/claude.d.ts +0 -17
  320. package/dist/capacity/claude.d.ts.map +0 -1
  321. package/dist/capacity/claude.js.map +0 -1
  322. package/dist/capacity/codex.d.ts.map +0 -1
  323. package/dist/capacity/codex.js.map +0 -1
  324. package/dist/capacity/openai.d.ts +0 -47
  325. package/dist/capacity/openai.d.ts.map +0 -1
  326. package/dist/capacity/openai.js +0 -307
  327. package/dist/capacity/openai.js.map +0 -1
  328. package/dist/capacity/wham.d.ts +0 -16
  329. package/dist/capacity/wham.d.ts.map +0 -1
  330. package/dist/capacity/wham.js +0 -66
  331. package/dist/capacity/wham.js.map +0 -1
  332. package/dist/capacity/zai.d.ts +0 -14
  333. package/dist/capacity/zai.d.ts.map +0 -1
  334. package/dist/capacity/zai.js.map +0 -1
  335. package/dist/readiness/AgentReadiness.d.ts.map +0 -1
  336. package/dist/readiness/AgentReadiness.js +0 -614
  337. package/dist/readiness/AgentReadiness.js.map +0 -1
  338. package/dist/terminal/TmuxManager.d.ts +0 -28
  339. package/dist/terminal/TmuxManager.d.ts.map +0 -1
  340. package/dist/terminal/TmuxManager.js.map +0 -1
  341. package/dist/terminal/index.d.ts +0 -5
  342. package/dist/terminal/index.d.ts.map +0 -1
  343. package/dist/terminal/index.js +0 -5
  344. package/dist/terminal/index.js.map +0 -1
  345. package/dist/utils/agents.d.ts +0 -16
  346. package/dist/utils/agents.d.ts.map +0 -1
  347. package/dist/utils/agents.js +0 -117
  348. package/dist/utils/agents.js.map +0 -1
  349. package/dist/utils/index.d.ts +0 -8
  350. package/dist/utils/index.d.ts.map +0 -1
  351. package/dist/utils/index.js +0 -6
  352. package/dist/utils/index.js.map +0 -1
  353. package/src/__tests__/utils/agents.test.ts +0 -105
  354. package/src/capacity/openai.ts +0 -355
  355. package/src/readiness/AgentReadiness.ts +0 -730
  356. package/src/terminal/index.ts +0 -4
  357. package/src/utils/index.ts +0 -14
@@ -1,14 +1,25 @@
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, type ClaudeCapacityOptions } 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, type ClaudeCapacityOptions } from "./sources/claude.js";
6
+ import {
7
+ probeOpenAiCapacity,
8
+ probePiAnthropicCapacity,
9
+ probeZaiCapacity,
10
+ type PiAnthropicCapacityOptions,
11
+ type PiOpenAiCapacityOptions,
12
+ type PiZaiCapacityOptions,
13
+ } from "./sources/pi.js";
8
14
  import type { CapacityReport } from "./types.js";
9
15
 
10
16
  export type { CapacityReport, CapacityWindow } from "./types.js";
11
- export type { ClaudeCapacityOptions } from "./claude.js";
17
+ export type { ClaudeCapacityOptions } from "./sources/claude.js";
18
+ export type { PiAnthropicCapacityOptions as AnthropicCapacityOptions } from "./sources/pi.js";
19
+ export type {
20
+ PiOpenAiCapacityOptions as OpenAiCapacityOptions,
21
+ PiZaiCapacityOptions as ZaiCapacityOptions,
22
+ } from "./sources/pi.js";
12
23
 
13
24
  export type CapacityProbeOptions = {
14
25
  now?: () => Date;
@@ -17,22 +28,6 @@ export type CapacityProbeOptions = {
17
28
  probe?: typeof probeCodexCapacity;
18
29
  };
19
30
 
20
- export type ZaiCapacityOptions = {
21
- now?: () => Date;
22
- env?: NodeJS.ProcessEnv;
23
- readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
24
- fetch?: typeof globalThis.fetch;
25
- timeoutMs?: number;
26
- };
27
-
28
- export type OpenAiCapacityOptions = {
29
- now?: () => Date;
30
- env?: NodeJS.ProcessEnv;
31
- readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
32
- fetch?: typeof globalThis.fetch;
33
- timeoutMs?: number;
34
- };
35
-
36
31
  async function canAccess(target: string, mode: number): Promise<boolean> {
37
32
  try {
38
33
  await fsAccess(target, mode);
@@ -78,7 +73,7 @@ export async function getCodexCapacityReport(
78
73
  }
79
74
 
80
75
  export async function getZaiCapacityReport(
81
- options: ZaiCapacityOptions = {},
76
+ options: PiZaiCapacityOptions = {},
82
77
  ): Promise<CapacityReport> {
83
78
  const { now, ...probeOptions } = options;
84
79
  return probeZaiCapacity({
@@ -88,7 +83,7 @@ export async function getZaiCapacityReport(
88
83
  }
89
84
 
90
85
  export async function getOpenAiCapacityReport(
91
- options: OpenAiCapacityOptions = {},
86
+ options: PiOpenAiCapacityOptions = {},
92
87
  ): Promise<CapacityReport> {
93
88
  const { now, ...probeOptions } = options;
94
89
  return probeOpenAiCapacity({
@@ -107,3 +102,14 @@ export async function getClaudeCapacityReport(
107
102
  now,
108
103
  });
109
104
  }
105
+
106
+ export async function getAnthropicCapacityReport(
107
+ options: PiAnthropicCapacityOptions = {},
108
+ ): Promise<CapacityReport> {
109
+ const { now, ...probeOptions } = options;
110
+ return probePiAnthropicCapacity({
111
+ ...probeOptions,
112
+ checkedAt: (now?.() ?? new Date()).toISOString(),
113
+ now,
114
+ });
115
+ }
@@ -1,34 +1,15 @@
1
- import { execFile } from "node:child_process";
2
- import { readFile } from "node:fs/promises";
3
- import { homedir } from "node:os";
4
- import { isAbsolute, join, resolve } from "node:path";
5
- import { promisify } from "node:util";
6
- import type { Availability, CapacityReport, CapacityWindow } from "./types.js";
1
+ import type { Availability, CapacityWindow, ProviderCapacitySnapshot } from "../types.js";
7
2
 
8
- const execFileAsync = promisify(execFile);
3
+ const SESSION_DURATION_MINUTES = 5 * 60;
4
+ const WEEK_DURATION_MINUTES = 7 * 24 * 60;
5
+ const ANTHROPIC_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
9
6
 
10
- export type ClaudeCapacityOptions = {
11
- env?: NodeJS.ProcessEnv;
12
- readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
7
+ export type AnthropicCapacityRequestOptions = {
13
8
  fetch?: typeof globalThis.fetch;
14
9
  timeoutMs?: number;
15
10
  now?: () => Date;
16
- cwd?: string;
17
- platform?: NodeJS.Platform;
18
- keychainRead?: (service: string) => Promise<string | null>;
19
- };
20
-
21
- export type ClaudeProbeOptions = ClaudeCapacityOptions & {
22
- checkedAt: string;
23
11
  };
24
12
 
25
- const CLAUDE_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
26
- const CLAUDE_KEYCHAIN_SERVICE = "Claude Code-credentials";
27
- const SESSION_DURATION_MINUTES = 5 * 60;
28
- const WEEK_DURATION_MINUTES = 7 * 24 * 60;
29
-
30
- type Credential = { token: string | null; expired: boolean };
31
-
32
13
  function record(value: unknown): Record<string, unknown> | null {
33
14
  return value !== null && typeof value === "object" && !Array.isArray(value)
34
15
  ? (value as Record<string, unknown>)
@@ -45,91 +26,6 @@ function nonEmptyText(value: unknown): string | null {
45
26
  return typeof value === "string" && value.trim() ? value.trim() : null;
46
27
  }
47
28
 
48
- function credentialsPath(options: ClaudeProbeOptions): string {
49
- const env = options.env ?? process.env;
50
- const configured = nonEmptyText(env.CLAUDE_CONFIG_DIR);
51
- if (configured) {
52
- const profileRoot = isAbsolute(configured)
53
- ? configured
54
- : resolve(options.cwd ?? process.cwd(), configured);
55
- return join(profileRoot, ".credentials.json");
56
- }
57
- return join(env.HOME || homedir(), ".claude", ".credentials.json");
58
- }
59
-
60
- function credentialFromPayload(payload: string | null, now: Date): Credential {
61
- if (!payload) return { token: null, expired: false };
62
- try {
63
- return credentialFromRoot(record(JSON.parse(payload)), now);
64
- } catch {
65
- return { token: null, expired: false };
66
- }
67
- }
68
-
69
- async function readProfileCredential(options: ClaudeProbeOptions, now: Date): Promise<Credential> {
70
- try {
71
- const payload = await (options.readFile ?? readFile)(credentialsPath(options), "utf8");
72
- return credentialFromPayload(payload, now);
73
- } catch {
74
- return { token: null, expired: false };
75
- }
76
- }
77
-
78
- async function readKeychainCredential(options: ClaudeProbeOptions, now: Date): Promise<Credential> {
79
- const env = options.env ?? process.env;
80
- const usesDefaultProfile = !nonEmptyText(env.CLAUDE_CONFIG_DIR);
81
- if (!usesDefaultProfile || (options.platform ?? process.platform) !== "darwin") {
82
- return { token: null, expired: false };
83
- }
84
- try {
85
- const payload = await (options.keychainRead ?? readClaudeKeychain)(CLAUDE_KEYCHAIN_SERVICE);
86
- return credentialFromPayload(payload, now);
87
- } catch {
88
- return { token: null, expired: false };
89
- }
90
- }
91
-
92
- async function resolveToken(options: ClaudeProbeOptions): Promise<string> {
93
- const env = options.env ?? process.env;
94
- const environmentToken = nonEmptyText(env.CLAUDE_CODE_OAUTH_TOKEN);
95
- if (environmentToken) return environmentToken;
96
-
97
- const now = options.now?.() ?? new Date();
98
- const profileCredential = await readProfileCredential(options, now);
99
- if (profileCredential.token) return profileCredential.token;
100
-
101
- const keychainCredential = await readKeychainCredential(options, now);
102
- if (keychainCredential.token) return keychainCredential.token;
103
- if (profileCredential.expired || keychainCredential.expired) {
104
- throw new Error("Claude OAuth credentials expired");
105
- }
106
- throw new Error("Claude OAuth credentials not found or malformed");
107
- }
108
-
109
- function credentialFromRoot(root: Record<string, unknown> | null, now: Date): Credential {
110
- const oauth = record(root?.claudeAiOauth);
111
- const token = nonEmptyText(oauth?.accessToken);
112
- if (!token) return { token: null, expired: false };
113
- const expired =
114
- typeof oauth?.expiresAt === "number" &&
115
- Number.isFinite(oauth.expiresAt) &&
116
- oauth.expiresAt <= now.getTime();
117
- return { token: expired ? null : token, expired };
118
- }
119
-
120
- async function readClaudeKeychain(service: string): Promise<string | null> {
121
- try {
122
- const { stdout } = await execFileAsync(
123
- "/usr/bin/security",
124
- ["find-generic-password", "-s", service, "-w"],
125
- { encoding: "utf8", timeout: 1500, maxBuffer: 1024 * 1024 },
126
- );
127
- return nonEmptyText(stdout);
128
- } catch {
129
- return null;
130
- }
131
- }
132
-
133
29
  function resetTime(value: unknown): string | null {
134
30
  if (typeof value !== "string") return null;
135
31
  const milliseconds = Date.parse(value);
@@ -173,9 +69,7 @@ function scopedWindows(value: unknown): CapacityWindow[] {
173
69
  continue;
174
70
  }
175
71
  const modelSlug = slug(identity);
176
- if (!modelSlug || modelSlug === "all-models" || modelSlug.endsWith("-all-models")) {
177
- continue;
178
- }
72
+ if (!modelSlug || modelSlug === "all-models" || modelSlug.endsWith("-all-models")) continue;
179
73
  const id = `claude:weekly:${modelSlug}`;
180
74
  if (seen.has(id)) continue;
181
75
  seen.add(id);
@@ -237,7 +131,7 @@ function retryAfterTime(response: Response, now: Date): string | null {
237
131
  return Number.isNaN(milliseconds) ? null : new Date(milliseconds).toISOString();
238
132
  }
239
133
 
240
- export function parseClaudeUsage(raw: unknown, checkedAt: string): CapacityReport {
134
+ export function parseAnthropicCapacity(raw: unknown): ProviderCapacitySnapshot {
241
135
  const input = record(raw);
242
136
  if (!input) throw new Error("Claude usage response is malformed");
243
137
  const windows = [
@@ -254,9 +148,6 @@ export function parseClaudeUsage(raw: unknown, checkedAt: string): CapacityRepor
254
148
  extraUsageWindow(input.extra_usage),
255
149
  ].filter((window): window is CapacityWindow => window !== null);
256
150
  return {
257
- harness: "claude",
258
- provider: "anthropic",
259
- generatedAt: checkedAt,
260
151
  authenticated: true,
261
152
  available: availability(windows),
262
153
  windows,
@@ -264,13 +155,13 @@ export function parseClaudeUsage(raw: unknown, checkedAt: string): CapacityRepor
264
155
  };
265
156
  }
266
157
 
267
- export async function probeClaudeCapacity(options: ClaudeProbeOptions): Promise<CapacityReport> {
268
- const token = await resolveToken(options);
269
- const controller = new AbortController();
270
- const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 5000);
158
+ export async function fetchAnthropicCapacity(
159
+ token: string,
160
+ options: AnthropicCapacityRequestOptions = {},
161
+ ): Promise<ProviderCapacitySnapshot> {
271
162
  let response: Response;
272
163
  try {
273
- response = await (options.fetch ?? globalThis.fetch)(CLAUDE_USAGE_URL, {
164
+ response = await (options.fetch ?? globalThis.fetch)(ANTHROPIC_USAGE_URL, {
274
165
  method: "GET",
275
166
  headers: {
276
167
  Accept: "application/json",
@@ -279,19 +170,13 @@ export async function probeClaudeCapacity(options: ClaudeProbeOptions): Promise<
279
170
  "User-Agent": "claude-code/2.1.0",
280
171
  "anthropic-beta": "oauth-2025-04-20",
281
172
  },
282
- signal: controller.signal,
173
+ signal: AbortSignal.timeout(options.timeoutMs ?? 5000),
283
174
  });
284
175
  } catch {
285
176
  throw new Error("Claude OAuth usage request failed");
286
- } finally {
287
- clearTimeout(timer);
288
- }
289
- if (response.status === 401) {
290
- throw new Error("Claude OAuth request unauthorized (HTTP 401)");
291
- }
292
- if (response.status === 403) {
293
- throw new Error("Claude OAuth request forbidden (HTTP 403)");
294
177
  }
178
+ if (response.status === 401) throw new Error("Claude OAuth request unauthorized (HTTP 401)");
179
+ if (response.status === 403) throw new Error("Claude OAuth request forbidden (HTTP 403)");
295
180
  if (response.status === 429) {
296
181
  const retryAt = retryAfterTime(response, options.now?.() ?? new Date());
297
182
  throw new Error(
@@ -309,5 +194,5 @@ export async function probeClaudeCapacity(options: ClaudeProbeOptions): Promise<
309
194
  } catch {
310
195
  throw new Error("Claude usage response is malformed");
311
196
  }
312
- return parseClaudeUsage(raw, options.checkedAt);
197
+ return parseAnthropicCapacity(raw);
313
198
  }
@@ -0,0 +1,150 @@
1
+ import type { CapacityWindow, ProviderCapacitySnapshot } from "../types.js";
2
+
3
+ const OPENAI_USAGE_BASE_URL = "https://api.openai.com/v1/organization/usage";
4
+ const OPENAI_MODELS_URL = "https://api.openai.com/v1/models";
5
+ const OPENAI_USAGE_ENDPOINTS = ["completions", "responses"] as const;
6
+ const USAGE_WINDOW_DAYS = 7;
7
+ const DAY_MS = 24 * 60 * 60 * 1000;
8
+
9
+ export type OpenAiUsageBucket = { startMs: number; tokens: number };
10
+ export type OpenAiPlatformCapacityOptions = {
11
+ checkedAt: string;
12
+ fetch?: typeof globalThis.fetch;
13
+ timeoutMs?: number;
14
+ };
15
+
16
+ type UnknownRecord = Record<string, unknown>;
17
+
18
+ function record(value: unknown): UnknownRecord | null {
19
+ return value !== null && typeof value === "object" && !Array.isArray(value)
20
+ ? (value as UnknownRecord)
21
+ : null;
22
+ }
23
+
24
+ function finiteNumber(value: unknown): number | null {
25
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
26
+ }
27
+
28
+ function bucketTokens(value: unknown): number {
29
+ const results = Array.isArray(value) ? value : [];
30
+ return results.reduce(
31
+ (total, entry) =>
32
+ total +
33
+ (finiteNumber(record(entry)?.input_tokens) ?? 0) +
34
+ (finiteNumber(record(entry)?.output_tokens) ?? 0),
35
+ 0,
36
+ );
37
+ }
38
+
39
+ export function parseOpenAiUsage(raw: unknown): OpenAiUsageBucket[] {
40
+ const data = record(raw)?.data;
41
+ if (!Array.isArray(data)) throw new Error("Invalid OpenAI usage response");
42
+ const buckets: OpenAiUsageBucket[] = [];
43
+ for (const entry of data) {
44
+ const seconds = finiteNumber(record(entry)?.aggregation_timestamp);
45
+ if (seconds === null) continue;
46
+ buckets.push({ startMs: seconds * 1000, tokens: bucketTokens(record(entry)?.results) });
47
+ }
48
+ return buckets;
49
+ }
50
+
51
+ function emptySnapshot(authenticated: boolean): ProviderCapacitySnapshot {
52
+ return {
53
+ authenticated,
54
+ available: "unknown",
55
+ windows: [],
56
+ creditsRemaining: null,
57
+ };
58
+ }
59
+
60
+ export function buildOpenAiPlatformCapacity(
61
+ buckets: OpenAiUsageBucket[],
62
+ checkedAt: string,
63
+ ): ProviderCapacitySnapshot {
64
+ const nowMs = Date.parse(checkedAt);
65
+ const todayStartMs = Math.floor(nowMs / DAY_MS) * DAY_MS;
66
+ const weekStartMs = todayStartMs - (USAGE_WINDOW_DAYS - 1) * DAY_MS;
67
+ let todayTokens = 0;
68
+ let weekTokens = 0;
69
+ for (const bucket of buckets) {
70
+ if (bucket.startMs === todayStartMs) todayTokens += bucket.tokens;
71
+ if (bucket.startMs >= weekStartMs) weekTokens += bucket.tokens;
72
+ }
73
+ const windows: CapacityWindow[] = [
74
+ {
75
+ id: "openai:tokens:today",
76
+ label: "Tokens · today (UTC)",
77
+ limitType: "TOKENS_LIMIT",
78
+ durationMinutes: 24 * 60,
79
+ usedPercent: null,
80
+ resetsAt: new Date(todayStartMs + DAY_MS).toISOString(),
81
+ total: null,
82
+ current: todayTokens,
83
+ remaining: null,
84
+ },
85
+ {
86
+ id: "openai:tokens:week",
87
+ label: "Tokens · 7 days",
88
+ limitType: "TOKENS_LIMIT",
89
+ durationMinutes: USAGE_WINDOW_DAYS * 24 * 60,
90
+ usedPercent: null,
91
+ resetsAt: null,
92
+ total: null,
93
+ current: weekTokens,
94
+ remaining: null,
95
+ },
96
+ ];
97
+ return {
98
+ authenticated: true,
99
+ available: "yes",
100
+ windows,
101
+ creditsRemaining: null,
102
+ };
103
+ }
104
+
105
+ async function request(
106
+ url: string,
107
+ key: string,
108
+ options: OpenAiPlatformCapacityOptions,
109
+ ): Promise<Response> {
110
+ try {
111
+ return await (options.fetch ?? globalThis.fetch)(url, {
112
+ method: "GET",
113
+ headers: { Authorization: `Bearer ${key}` },
114
+ signal: AbortSignal.timeout(options.timeoutMs ?? 5000),
115
+ });
116
+ } catch {
117
+ throw new Error("OpenAI usage request failed");
118
+ }
119
+ }
120
+
121
+ async function verifyKey(key: string, options: OpenAiPlatformCapacityOptions): Promise<boolean> {
122
+ const response = await request(OPENAI_MODELS_URL, key, options);
123
+ return response.status !== 401;
124
+ }
125
+
126
+ export async function fetchOpenAiPlatformCapacity(
127
+ key: string,
128
+ options: OpenAiPlatformCapacityOptions,
129
+ ): Promise<ProviderCapacitySnapshot> {
130
+ const endSeconds = Math.floor(Date.parse(options.checkedAt) / 1000);
131
+ const startSeconds = endSeconds - USAGE_WINDOW_DAYS * 24 * 60 * 60;
132
+ const query = `start_time=${startSeconds}&end_time=${endSeconds}`;
133
+ const payloads: unknown[] = [];
134
+
135
+ for (const endpoint of OPENAI_USAGE_ENDPOINTS) {
136
+ const response = await request(`${OPENAI_USAGE_BASE_URL}/${endpoint}?${query}`, key, options);
137
+ if (response.status === 401) return emptySnapshot(false);
138
+ if (response.status === 403) return emptySnapshot(await verifyKey(key, options));
139
+ if (response.status !== 200) {
140
+ throw new Error(`OpenAI usage request failed: HTTP ${response.status}`);
141
+ }
142
+ try {
143
+ payloads.push(await response.json());
144
+ } catch {
145
+ throw new Error("OpenAI usage response is not valid JSON");
146
+ }
147
+ }
148
+
149
+ return buildOpenAiPlatformCapacity(payloads.flatMap(parseOpenAiUsage), options.checkedAt);
150
+ }
@@ -1,6 +1,19 @@
1
- import type { CapacityWindow } from "./types.js";
1
+ import type { CapacityWindow, ProviderCapacitySnapshot } from "../types.js";
2
2
 
3
- type WhamUsageSnapshot = {
3
+ const WHAM_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
4
+ const OPENAI_WHOAMI_URL = "https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami";
5
+
6
+ export type OpenAiSubscriptionCredential = {
7
+ access: string;
8
+ accountId: string;
9
+ };
10
+
11
+ export type OpenAiSubscriptionCapacityOptions = {
12
+ fetch?: typeof globalThis.fetch;
13
+ timeoutMs?: number;
14
+ };
15
+
16
+ export type WhamUsageSnapshot = {
4
17
  windows: CapacityWindow[];
5
18
  creditsRemaining: number | null;
6
19
  };
@@ -24,8 +37,9 @@ function nonEmptyText(value: unknown): string | null {
24
37
  export function resetTime(value: unknown): string | null {
25
38
  const seconds = finiteNumber(value);
26
39
  if (seconds !== null) return new Date(seconds * 1000).toISOString();
27
- if (typeof value === "string" && !Number.isNaN(Date.parse(value)))
40
+ if (typeof value === "string" && !Number.isNaN(Date.parse(value))) {
28
41
  return new Date(value).toISOString();
42
+ }
29
43
  return null;
30
44
  }
31
45
 
@@ -64,11 +78,6 @@ function extraWindows(value: unknown): CapacityWindow[] {
64
78
  });
65
79
  }
66
80
 
67
- /**
68
- * Parses the chatgpt.com backend wham/usage payload shared by every
69
- * OAuth-backed OpenAI consumer (codex harness and pi login) into generic
70
- * capacity windows plus the credit balance.
71
- */
72
81
  export function parseWhamUsage(raw: unknown): WhamUsageSnapshot {
73
82
  const response = record(raw) ?? {};
74
83
  const limits = record(response.rate_limit) ?? {};
@@ -82,3 +91,72 @@ export function parseWhamUsage(raw: unknown): WhamUsageSnapshot {
82
91
  creditsRemaining: finiteNumber(credits.balance),
83
92
  };
84
93
  }
94
+
95
+ export async function fetchOpenAiSubscriptionCapacity(
96
+ credential: OpenAiSubscriptionCredential,
97
+ options: OpenAiSubscriptionCapacityOptions = {},
98
+ ): Promise<ProviderCapacitySnapshot> {
99
+ let response: Response;
100
+ try {
101
+ response = await (options.fetch ?? globalThis.fetch)(WHAM_USAGE_URL, {
102
+ method: "GET",
103
+ headers: {
104
+ Authorization: `Bearer ${credential.access}`,
105
+ "ChatGPT-Account-Id": credential.accountId,
106
+ },
107
+ signal: AbortSignal.timeout(options.timeoutMs ?? 5000),
108
+ });
109
+ } catch {
110
+ throw new Error("OpenAI usage request failed");
111
+ }
112
+ if (response.status === 401 || response.status === 403) {
113
+ return {
114
+ authenticated: false,
115
+ available: "unknown",
116
+ windows: [],
117
+ creditsRemaining: null,
118
+ };
119
+ }
120
+ if (response.status !== 200) {
121
+ throw new Error(`OpenAI usage request failed: HTTP ${response.status}`);
122
+ }
123
+ let raw: unknown;
124
+ try {
125
+ raw = await response.json();
126
+ } catch {
127
+ throw new Error("OpenAI usage response is not valid JSON");
128
+ }
129
+ const snapshot = parseWhamUsage(raw);
130
+ const hasUsage = snapshot.windows.some((window) => window.usedPercent !== null);
131
+ return {
132
+ authenticated: true,
133
+ available: hasUsage ? "yes" : "unknown",
134
+ windows: snapshot.windows,
135
+ creditsRemaining: snapshot.creditsRemaining,
136
+ };
137
+ }
138
+
139
+ export async function fetchOpenAiPatAccountId(
140
+ token: string,
141
+ options: OpenAiSubscriptionCapacityOptions = {},
142
+ ): Promise<string> {
143
+ let response: Response;
144
+ try {
145
+ response = await (options.fetch ?? globalThis.fetch)(OPENAI_WHOAMI_URL, {
146
+ headers: { Authorization: `Bearer ${token}` },
147
+ signal: AbortSignal.timeout(options.timeoutMs ?? 5000),
148
+ });
149
+ } catch {
150
+ throw new Error("OpenAI account request failed");
151
+ }
152
+ if (!response.ok) throw new Error("OpenAI account request failed");
153
+ let raw: unknown;
154
+ try {
155
+ raw = await response.json();
156
+ } catch {
157
+ throw new Error("OpenAI account response is not valid JSON");
158
+ }
159
+ const accountId = nonEmptyText(record(raw)?.chatgpt_account_id);
160
+ if (!accountId) throw new Error("OpenAI account unavailable");
161
+ return accountId;
162
+ }