@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.
- package/dist/AgentManager.d.ts +0 -4
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +2 -2
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/capacity/anthropic.test.js +115 -0
- package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
- package/dist/__tests__/capacity/boundaries.test.js +45 -0
- package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
- package/dist/__tests__/capacity/claude.test.js +3 -3
- package/dist/__tests__/capacity/claude.test.js.map +1 -1
- package/dist/__tests__/capacity/codex.test.js +3 -1
- package/dist/__tests__/capacity/codex.test.js.map +1 -1
- package/dist/__tests__/capacity/openai.test.js +21 -12
- package/dist/__tests__/capacity/openai.test.js.map +1 -1
- package/dist/__tests__/capacity/wham.test.js +1 -1
- package/dist/__tests__/capacity/wham.test.js.map +1 -1
- package/dist/__tests__/capacity/zai.test.js +7 -8
- package/dist/__tests__/capacity/zai.test.js.map +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +2 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +7 -15
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +3 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +11 -26
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +3 -7
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -1
- package/dist/__tests__/harnesses/devin/DevinAdapter.test.js +597 -0
- package/dist/__tests__/harnesses/devin/DevinAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js +91 -0
- package/dist/__tests__/harnesses/devin/DevinAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js +192 -0
- package/dist/__tests__/harnesses/devin/DevinSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js +407 -0
- package/dist/__tests__/harnesses/devin/DevinSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/devin/fixtures.js +95 -0
- package/dist/__tests__/harnesses/devin/fixtures.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +5 -11
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -1
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +9 -19
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -1
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +3 -7
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -1
- package/dist/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.js +95 -11
- package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
- package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
- package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
- package/dist/__tests__/print/DurableAgent.test.js +4 -6
- package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
- package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
- package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/terminal/GhosttyBackend.test.js +334 -0
- package/dist/__tests__/terminal/GhosttyBackend.test.js.map +1 -0
- package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +1 -1
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +2 -1
- package/dist/adapters/AgentAdapter.js.map +1 -1
- package/dist/capacity/index.d.ts +9 -19
- package/dist/capacity/index.d.ts.map +1 -1
- package/dist/capacity/index.js +11 -4
- package/dist/capacity/index.js.map +1 -1
- package/dist/capacity/providers/anthropic.d.ts +9 -0
- package/dist/capacity/providers/anthropic.d.ts.map +1 -0
- package/dist/capacity/{claude.js → providers/anthropic.js} +10 -128
- package/dist/capacity/providers/anthropic.js.map +1 -0
- package/dist/capacity/providers/openai-platform.d.ts +14 -0
- package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
- package/dist/capacity/providers/openai-platform.js +120 -0
- package/dist/capacity/providers/openai-platform.js.map +1 -0
- package/dist/capacity/providers/openai-subscription.d.ts +20 -0
- package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
- package/dist/capacity/providers/openai-subscription.js +129 -0
- package/dist/capacity/providers/openai-subscription.js.map +1 -0
- package/dist/capacity/providers/zai.d.ts +8 -0
- package/dist/capacity/providers/zai.d.ts.map +1 -0
- package/dist/capacity/{zai.js → providers/zai.js} +17 -62
- package/dist/capacity/providers/zai.js.map +1 -0
- package/dist/capacity/sources/claude.d.ts +9 -0
- package/dist/capacity/sources/claude.d.ts.map +1 -0
- package/dist/capacity/sources/claude.js +17 -0
- package/dist/capacity/sources/claude.js.map +1 -0
- package/dist/capacity/{codex.d.ts → sources/codex.d.ts} +5 -9
- package/dist/capacity/sources/codex.d.ts.map +1 -0
- package/dist/capacity/{codex.js → sources/codex.js} +31 -84
- package/dist/capacity/sources/codex.js.map +1 -0
- package/dist/capacity/sources/pi.d.ts +30 -0
- package/dist/capacity/sources/pi.d.ts.map +1 -0
- package/dist/capacity/sources/pi.js +81 -0
- package/dist/capacity/sources/pi.js.map +1 -0
- package/dist/capacity/types.d.ts +2 -0
- package/dist/capacity/types.d.ts.map +1 -1
- package/dist/capacity/types.js +1 -1
- package/dist/capacity/types.js.map +1 -1
- package/dist/harnesses/claude/credentials.d.ts +10 -0
- package/dist/harnesses/claude/credentials.d.ts.map +1 -0
- package/dist/harnesses/claude/credentials.js +112 -0
- package/dist/harnesses/claude/credentials.js.map +1 -0
- package/dist/harnesses/claude/readiness.d.ts +3 -0
- package/dist/harnesses/claude/readiness.d.ts.map +1 -0
- package/dist/harnesses/claude/readiness.js +63 -0
- package/dist/harnesses/claude/readiness.js.map +1 -0
- package/dist/harnesses/codex/credentials.d.ts +15 -0
- package/dist/harnesses/codex/credentials.d.ts.map +1 -0
- package/dist/harnesses/codex/credentials.js +58 -0
- package/dist/harnesses/codex/credentials.js.map +1 -0
- package/dist/harnesses/codex/readiness.d.ts +3 -0
- package/dist/harnesses/codex/readiness.d.ts.map +1 -0
- package/dist/harnesses/codex/readiness.js +60 -0
- package/dist/harnesses/codex/readiness.js.map +1 -0
- package/dist/harnesses/copilot/readiness.d.ts +3 -0
- package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
- package/dist/harnesses/copilot/readiness.js +39 -0
- package/dist/harnesses/copilot/readiness.js.map +1 -0
- package/dist/harnesses/devin/DevinAdapter.d.ts +39 -0
- package/dist/harnesses/devin/DevinAdapter.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinAdapter.js +177 -0
- package/dist/harnesses/devin/DevinAdapter.js.map +1 -0
- package/dist/harnesses/devin/DevinAgentMapper.d.ts +11 -0
- package/dist/harnesses/devin/DevinAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinAgentMapper.js +35 -0
- package/dist/harnesses/devin/DevinAgentMapper.js.map +1 -0
- package/dist/harnesses/devin/DevinSessionLocator.d.ts +46 -0
- package/dist/harnesses/devin/DevinSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinSessionLocator.js +176 -0
- package/dist/harnesses/devin/DevinSessionLocator.js.map +1 -0
- package/dist/harnesses/devin/DevinSessionParser.d.ts +29 -0
- package/dist/harnesses/devin/DevinSessionParser.d.ts.map +1 -0
- package/dist/harnesses/devin/DevinSessionParser.js +166 -0
- package/dist/harnesses/devin/DevinSessionParser.js.map +1 -0
- package/dist/harnesses/devin/readiness.d.ts +3 -0
- package/dist/harnesses/devin/readiness.d.ts.map +1 -0
- package/dist/harnesses/devin/readiness.js +39 -0
- package/dist/harnesses/devin/readiness.js.map +1 -0
- package/dist/harnesses/index.d.ts.map +1 -1
- package/dist/harnesses/index.js +3 -1
- package/dist/harnesses/index.js.map +1 -1
- package/dist/harnesses/opencode/readiness.d.ts +3 -0
- package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
- package/dist/harnesses/opencode/readiness.js +50 -0
- package/dist/harnesses/opencode/readiness.js.map +1 -0
- package/dist/harnesses/pi/credentials.d.ts +22 -0
- package/dist/harnesses/pi/credentials.d.ts.map +1 -0
- package/dist/harnesses/pi/credentials.js +98 -0
- package/dist/harnesses/pi/credentials.js.map +1 -0
- package/dist/harnesses/pi/readiness.d.ts +3 -0
- package/dist/harnesses/pi/readiness.d.ts.map +1 -0
- package/dist/harnesses/pi/readiness.js +96 -0
- package/dist/harnesses/pi/readiness.js.map +1 -0
- package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
- package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
- package/dist/harnesses/readiness/AgentReadiness.js +70 -0
- package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
- package/dist/harnesses/readiness/checks.d.ts +31 -0
- package/dist/harnesses/readiness/checks.d.ts.map +1 -0
- package/dist/harnesses/readiness/checks.js +270 -0
- package/dist/harnesses/readiness/checks.js.map +1 -0
- package/dist/{readiness/AgentReadiness.d.ts → harnesses/readiness/types.d.ts} +19 -10
- package/dist/harnesses/readiness/types.d.ts.map +1 -0
- package/dist/harnesses/readiness/types.js +4 -0
- package/dist/harnesses/readiness/types.js.map +1 -0
- package/dist/harnesses/runtimeProfiles.d.ts +11 -0
- package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
- package/dist/harnesses/runtimeProfiles.js +100 -0
- package/dist/harnesses/runtimeProfiles.js.map +1 -0
- package/dist/index.d.ts +16 -42
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -23
- package/dist/index.js.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
- package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/ManagedAgentRuntime.js +6 -20
- package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
- package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
- package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
- package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
- package/dist/runtime/tmux/PidPolling.d.ts +1 -1
- package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
- package/dist/runtime/tmux/PidPolling.js.map +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
- package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
- package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
- package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
- package/dist/{terminal → runtime/tmux}/TmuxManager.js +9 -28
- package/dist/runtime/tmux/TmuxManager.js.map +1 -0
- package/dist/runtime/types.d.ts +1 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/terminal/TerminalFocusManager.d.ts +4 -32
- package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
- package/dist/terminal/TerminalFocusManager.js +17 -267
- package/dist/terminal/TerminalFocusManager.js.map +1 -1
- package/dist/terminal/TtyWriter.d.ts +1 -44
- package/dist/terminal/TtyWriter.d.ts.map +1 -1
- package/dist/terminal/TtyWriter.js +12 -347
- package/dist/terminal/TtyWriter.js.map +1 -1
- package/dist/terminal/backends/ghostty.d.ts +3 -0
- package/dist/terminal/backends/ghostty.d.ts.map +1 -0
- package/dist/terminal/backends/ghostty.js +161 -0
- package/dist/terminal/backends/ghostty.js.map +1 -0
- package/dist/terminal/backends/index.d.ts +5 -0
- package/dist/terminal/backends/index.d.ts.map +1 -0
- package/dist/terminal/backends/index.js +21 -0
- package/dist/terminal/backends/index.js.map +1 -0
- package/dist/terminal/backends/iterm2.d.ts +3 -0
- package/dist/terminal/backends/iterm2.d.ts.map +1 -0
- package/dist/terminal/backends/iterm2.js +135 -0
- package/dist/terminal/backends/iterm2.js.map +1 -0
- package/dist/terminal/backends/shared.d.ts +9 -0
- package/dist/terminal/backends/shared.d.ts.map +1 -0
- package/dist/terminal/backends/shared.js +38 -0
- package/dist/terminal/backends/shared.js.map +1 -0
- package/dist/terminal/backends/terminal-app.d.ts +3 -0
- package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
- package/dist/terminal/backends/terminal-app.js +129 -0
- package/dist/terminal/backends/terminal-app.js.map +1 -0
- package/dist/terminal/backends/tmux.d.ts +3 -0
- package/dist/terminal/backends/tmux.d.ts.map +1 -0
- package/dist/terminal/backends/tmux.js +76 -0
- package/dist/terminal/backends/tmux.js.map +1 -0
- package/dist/terminal/backends/wezterm.d.ts +3 -0
- package/dist/terminal/backends/wezterm.d.ts.map +1 -0
- package/dist/terminal/backends/wezterm.js +71 -0
- package/dist/terminal/backends/wezterm.js.map +1 -0
- package/dist/terminal/types.d.ts +22 -0
- package/dist/terminal/types.d.ts.map +1 -0
- package/dist/terminal/types.js +11 -0
- package/dist/terminal/types.js.map +1 -0
- package/dist/utils/process.d.ts +2 -0
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +3 -0
- package/dist/utils/process.js.map +1 -1
- package/package.json +1 -1
- package/src/AgentManager.ts +1 -1
- package/src/__tests__/capacity/anthropic.test.ts +105 -0
- package/src/__tests__/capacity/boundaries.test.ts +36 -0
- package/src/__tests__/capacity/claude.test.ts +3 -8
- package/src/__tests__/capacity/codex.test.ts +12 -35
- package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
- package/src/__tests__/capacity/openai.test.ts +15 -15
- package/src/__tests__/capacity/wham.test.ts +1 -1
- package/src/__tests__/capacity/zai.test.ts +27 -62
- package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +2 -2
- package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +1 -1
- package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +14 -19
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +3 -3
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +24 -30
- package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +4 -8
- package/src/__tests__/harnesses/devin/DevinAdapter.test.ts +292 -0
- package/src/__tests__/harnesses/devin/DevinAgentMapper.test.ts +88 -0
- package/src/__tests__/harnesses/devin/DevinSessionLocator.test.ts +139 -0
- package/src/__tests__/harnesses/devin/DevinSessionParser.test.ts +218 -0
- package/src/__tests__/harnesses/devin/fixtures.ts +144 -0
- package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +7 -11
- package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +19 -22
- package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +7 -8
- package/src/__tests__/{readiness → harnesses/readiness}/AgentReadiness.test.ts +77 -9
- package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
- package/src/__tests__/print/DurableAgent.test.ts +4 -13
- package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
- package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +1 -1
- package/src/__tests__/terminal/GhosttyBackend.test.ts +271 -0
- package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
- package/src/adapters/AgentAdapter.ts +1 -0
- package/src/capacity/index.ts +29 -23
- package/src/capacity/{claude.ts → providers/anthropic.ts} +16 -131
- package/src/capacity/providers/openai-platform.ts +150 -0
- package/src/capacity/{wham.ts → providers/openai-subscription.ts} +86 -8
- package/src/capacity/{zai.ts → providers/zai.ts} +29 -111
- package/src/capacity/sources/claude.ts +30 -0
- package/src/capacity/{codex.ts → sources/codex.ts} +54 -124
- package/src/capacity/sources/pi.ts +131 -0
- package/src/capacity/types.ts +3 -0
- package/src/harnesses/claude/credentials.ts +122 -0
- package/src/harnesses/claude/readiness.ts +69 -0
- package/src/harnesses/codex/credentials.ts +81 -0
- package/src/harnesses/codex/readiness.ts +72 -0
- package/src/harnesses/copilot/readiness.ts +33 -0
- package/src/harnesses/devin/DevinAdapter.ts +224 -0
- package/src/harnesses/devin/DevinAgentMapper.ts +43 -0
- package/src/harnesses/devin/DevinSessionLocator.ts +230 -0
- package/src/harnesses/devin/DevinSessionParser.ts +236 -0
- package/src/harnesses/devin/readiness.ts +36 -0
- package/src/harnesses/index.ts +2 -0
- package/src/harnesses/opencode/readiness.ts +48 -0
- package/src/harnesses/pi/credentials.ts +129 -0
- package/src/harnesses/pi/readiness.ts +104 -0
- package/src/harnesses/readiness/AgentReadiness.ts +89 -0
- package/src/harnesses/readiness/checks.ts +336 -0
- package/src/harnesses/readiness/types.ts +90 -0
- package/src/{utils/agents.ts → harnesses/runtimeProfiles.ts} +35 -38
- package/src/index.ts +15 -128
- package/src/runtime/ManagedAgentRuntime.ts +7 -22
- package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
- package/src/runtime/tmux/PidPolling.ts +1 -1
- package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
- package/src/{terminal → runtime/tmux}/TmuxManager.ts +9 -30
- package/src/runtime/types.ts +1 -1
- package/src/terminal/TerminalFocusManager.ts +19 -292
- package/src/terminal/TtyWriter.ts +15 -335
- package/src/terminal/backends/ghostty.ts +180 -0
- package/src/terminal/backends/index.ts +23 -0
- package/src/terminal/backends/iterm2.ts +126 -0
- package/src/terminal/backends/shared.ts +47 -0
- package/src/terminal/backends/terminal-app.ts +122 -0
- package/src/terminal/backends/tmux.ts +62 -0
- package/src/terminal/backends/wezterm.ts +65 -0
- package/src/terminal/types.ts +23 -0
- package/src/utils/process.ts +5 -0
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
- package/dist/__tests__/utils/agents.test.js +0 -93
- package/dist/__tests__/utils/agents.test.js.map +0 -1
- package/dist/capacity/claude.d.ts +0 -17
- package/dist/capacity/claude.d.ts.map +0 -1
- package/dist/capacity/claude.js.map +0 -1
- package/dist/capacity/codex.d.ts.map +0 -1
- package/dist/capacity/codex.js.map +0 -1
- package/dist/capacity/openai.d.ts +0 -47
- package/dist/capacity/openai.d.ts.map +0 -1
- package/dist/capacity/openai.js +0 -307
- package/dist/capacity/openai.js.map +0 -1
- package/dist/capacity/wham.d.ts +0 -16
- package/dist/capacity/wham.d.ts.map +0 -1
- package/dist/capacity/wham.js +0 -66
- package/dist/capacity/wham.js.map +0 -1
- package/dist/capacity/zai.d.ts +0 -14
- package/dist/capacity/zai.d.ts.map +0 -1
- package/dist/capacity/zai.js.map +0 -1
- package/dist/readiness/AgentReadiness.d.ts.map +0 -1
- package/dist/readiness/AgentReadiness.js +0 -614
- package/dist/readiness/AgentReadiness.js.map +0 -1
- package/dist/terminal/TmuxManager.d.ts +0 -28
- package/dist/terminal/TmuxManager.d.ts.map +0 -1
- package/dist/terminal/TmuxManager.js.map +0 -1
- package/dist/terminal/index.d.ts +0 -5
- package/dist/terminal/index.d.ts.map +0 -1
- package/dist/terminal/index.js +0 -5
- package/dist/terminal/index.js.map +0 -1
- package/dist/utils/agents.d.ts +0 -16
- package/dist/utils/agents.d.ts.map +0 -1
- package/dist/utils/agents.js +0 -117
- package/dist/utils/agents.js.map +0 -1
- package/dist/utils/index.d.ts +0 -8
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -6
- package/dist/utils/index.js.map +0 -1
- package/src/__tests__/utils/agents.test.ts +0 -105
- package/src/capacity/openai.ts +0 -355
- package/src/readiness/AgentReadiness.ts +0 -730
- package/src/terminal/index.ts +0 -4
- package/src/utils/index.ts +0 -14
package/src/capacity/index.ts
CHANGED
|
@@ -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 {
|
|
7
|
-
|
|
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:
|
|
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:
|
|
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 {
|
|
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
|
|
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
|
|
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
|
|
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
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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)(
|
|
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:
|
|
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
|
|
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 "
|
|
1
|
+
import type { CapacityWindow, ProviderCapacitySnapshot } from "../types.js";
|
|
2
2
|
|
|
3
|
-
|
|
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
|
+
}
|