@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
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
1
|
import type {
|
|
5
2
|
Availability,
|
|
6
3
|
CapacityLimitType,
|
|
7
|
-
CapacityReport,
|
|
8
4
|
CapacityWindow,
|
|
9
|
-
|
|
5
|
+
ProviderCapacitySnapshot,
|
|
6
|
+
} from "../types.js";
|
|
10
7
|
|
|
11
8
|
const ZAI_QUOTA_URL = "https://api.z.ai/api/monitor/usage/quota/limit";
|
|
12
|
-
const MISSING_API_KEY_MESSAGE =
|
|
13
|
-
"z.ai API key not found; set Z_AI_API_KEY or configure Pi provider zai";
|
|
14
9
|
const LIMIT_METADATA = {
|
|
15
10
|
TOKENS_LIMIT: { id: "tokens", label: "Tokens" },
|
|
16
11
|
CREDIT_LIMIT: { id: "credit", label: "Credit" },
|
|
@@ -24,13 +19,7 @@ const UNIT_METADATA = new Map<number, { minutes: number; label: string }>([
|
|
|
24
19
|
]);
|
|
25
20
|
type UnknownRecord = Record<string, unknown>;
|
|
26
21
|
|
|
27
|
-
export type
|
|
28
|
-
env?: NodeJS.ProcessEnv;
|
|
29
|
-
readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type ZaiProbeOptions = ZaiCredentialOptions & {
|
|
33
|
-
checkedAt: string;
|
|
22
|
+
export type ZaiRequestOptions = {
|
|
34
23
|
fetch?: typeof globalThis.fetch;
|
|
35
24
|
timeoutMs?: number;
|
|
36
25
|
};
|
|
@@ -41,10 +30,6 @@ function record(value: unknown): UnknownRecord | null {
|
|
|
41
30
|
: null;
|
|
42
31
|
}
|
|
43
32
|
|
|
44
|
-
function nonEmptyText(value: unknown): string | null {
|
|
45
|
-
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
33
|
function optionalNumber(value: unknown, field: string): number | null {
|
|
49
34
|
if (value === undefined || value === null) return null;
|
|
50
35
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -53,10 +38,6 @@ function optionalNumber(value: unknown, field: string): number | null {
|
|
|
53
38
|
return value;
|
|
54
39
|
}
|
|
55
40
|
|
|
56
|
-
function clampPercent(value: number): number {
|
|
57
|
-
return Math.max(0, Math.min(100, value));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
41
|
function integer(value: unknown): number | null {
|
|
61
42
|
return typeof value === "number" && Number.isInteger(value) ? value : null;
|
|
62
43
|
}
|
|
@@ -65,50 +46,33 @@ function isCapacityLimitType(value: string): value is CapacityLimitType {
|
|
|
65
46
|
return Object.hasOwn(LIMIT_METADATA, value);
|
|
66
47
|
}
|
|
67
48
|
|
|
68
|
-
function durationMinutes(
|
|
69
|
-
unit
|
|
70
|
-
number: number,
|
|
71
|
-
type: CapacityLimitType,
|
|
72
|
-
): number | null {
|
|
73
|
-
if (type === "TIME_LIMIT" && unit === 5 && number === 1) return 30 * 24 * 60;
|
|
49
|
+
function durationMinutes(unit: number, count: number, type: CapacityLimitType): number | null {
|
|
50
|
+
if (type === "TIME_LIMIT" && unit === 5 && count === 1) return 30 * 24 * 60;
|
|
74
51
|
const metadata = UNIT_METADATA.get(unit);
|
|
75
|
-
return metadata === undefined ||
|
|
76
|
-
? null
|
|
77
|
-
: metadata.minutes * number;
|
|
52
|
+
return metadata === undefined || count <= 0 ? null : metadata.minutes * count;
|
|
78
53
|
}
|
|
79
54
|
|
|
80
|
-
function windowLabel(
|
|
81
|
-
type
|
|
82
|
-
unit: number,
|
|
83
|
-
number: number,
|
|
84
|
-
): string {
|
|
85
|
-
if (type === "TIME_LIMIT" && unit === 5 && number === 1)
|
|
86
|
-
return "MCP · monthly";
|
|
55
|
+
function windowLabel(type: CapacityLimitType, unit: number, count: number): string {
|
|
56
|
+
if (type === "TIME_LIMIT" && unit === 5 && count === 1) return "MCP · monthly";
|
|
87
57
|
const kind = LIMIT_METADATA[type].label;
|
|
88
58
|
const unitLabel = UNIT_METADATA.get(unit)?.label;
|
|
89
59
|
if (!unitLabel) return kind;
|
|
90
|
-
return `${kind} · ${
|
|
60
|
+
return `${kind} · ${count} ${unitLabel}${count === 1 ? "" : "s"}`;
|
|
91
61
|
}
|
|
92
62
|
|
|
93
63
|
function resetTime(value: unknown): string | null {
|
|
94
64
|
const milliseconds = optionalNumber(value, "limit nextResetTime");
|
|
95
65
|
if (milliseconds === null) return null;
|
|
96
66
|
const date = new Date(milliseconds);
|
|
97
|
-
if (Number.isNaN(date.getTime()))
|
|
98
|
-
throw new Error("Invalid z.ai quota limit nextResetTime");
|
|
67
|
+
if (Number.isNaN(date.getTime())) throw new Error("Invalid z.ai quota limit nextResetTime");
|
|
99
68
|
return date.toISOString();
|
|
100
69
|
}
|
|
101
70
|
|
|
102
71
|
function availability(windows: CapacityWindow[]): Availability {
|
|
103
72
|
if (windows.length === 0) return "unknown";
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
108
|
-
) {
|
|
109
|
-
return "yes";
|
|
110
|
-
}
|
|
111
|
-
return "no";
|
|
73
|
+
return windows.some((window) => window.usedPercent !== null && window.usedPercent < 100)
|
|
74
|
+
? "yes"
|
|
75
|
+
: "no";
|
|
112
76
|
}
|
|
113
77
|
|
|
114
78
|
function parseLimit(value: unknown, index: number): CapacityWindow | null {
|
|
@@ -120,29 +84,25 @@ function parseLimit(value: unknown, index: number): CapacityWindow | null {
|
|
|
120
84
|
throw new Error("Invalid z.ai quota limit entry");
|
|
121
85
|
}
|
|
122
86
|
const serverPercent = optionalNumber(limit.percentage, "limit percentage");
|
|
123
|
-
if (serverPercent === null)
|
|
124
|
-
throw new Error("Invalid z.ai quota limit percentage");
|
|
87
|
+
if (serverPercent === null) throw new Error("Invalid z.ai quota limit percentage");
|
|
125
88
|
if (!isCapacityLimitType(limit.type)) return null;
|
|
126
89
|
|
|
127
90
|
const total = optionalNumber(limit.usage, "limit usage");
|
|
128
91
|
const current = optionalNumber(limit.currentValue, "limit currentValue");
|
|
129
92
|
const remaining = optionalNumber(limit.remaining, "limit remaining");
|
|
130
|
-
let consumed =
|
|
131
|
-
total !== null && remaining !== null ? total - remaining : null;
|
|
93
|
+
let consumed = total !== null && remaining !== null ? total - remaining : null;
|
|
132
94
|
if (current !== null) consumed = Math.max(consumed ?? current, current);
|
|
133
|
-
|
|
134
95
|
let usedPercent = serverPercent;
|
|
135
96
|
if (total !== null && total > 0 && consumed !== null) {
|
|
136
97
|
usedPercent = (consumed / total) * 100;
|
|
137
98
|
}
|
|
138
99
|
const metadata = LIMIT_METADATA[limit.type];
|
|
139
|
-
|
|
140
100
|
return {
|
|
141
101
|
id: `zai:${metadata.id}:${index + 1}`,
|
|
142
102
|
label: windowLabel(limit.type, unit, count),
|
|
143
103
|
limitType: limit.type,
|
|
144
104
|
durationMinutes: durationMinutes(unit, count, limit.type),
|
|
145
|
-
usedPercent:
|
|
105
|
+
usedPercent: Math.max(0, Math.min(100, usedPercent)),
|
|
146
106
|
resetsAt: resetTime(limit.nextResetTime),
|
|
147
107
|
total,
|
|
148
108
|
current,
|
|
@@ -150,55 +110,16 @@ function parseLimit(value: unknown, index: number): CapacityWindow | null {
|
|
|
150
110
|
};
|
|
151
111
|
}
|
|
152
112
|
|
|
153
|
-
export
|
|
154
|
-
options: ZaiCredentialOptions = {},
|
|
155
|
-
): Promise<string> {
|
|
156
|
-
const env = options.env ?? process.env;
|
|
157
|
-
const environmentKey = nonEmptyText(env.Z_AI_API_KEY);
|
|
158
|
-
if (environmentKey) return environmentKey;
|
|
159
|
-
|
|
160
|
-
const authPath = join(env.HOME || homedir(), ".pi", "agent", "auth.json");
|
|
161
|
-
let parsed: UnknownRecord;
|
|
162
|
-
try {
|
|
163
|
-
const contents = await (options.readFile ?? readFile)(authPath, "utf8");
|
|
164
|
-
const root = record(JSON.parse(contents));
|
|
165
|
-
if (!root) throw new Error("invalid");
|
|
166
|
-
parsed = root;
|
|
167
|
-
} catch (error) {
|
|
168
|
-
if (record(error)?.code === "ENOENT") {
|
|
169
|
-
throw new Error(MISSING_API_KEY_MESSAGE);
|
|
170
|
-
}
|
|
171
|
-
throw new Error("z.ai Pi auth file is malformed");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const credential = record(parsed.zai);
|
|
175
|
-
if (!credential) {
|
|
176
|
-
throw new Error(MISSING_API_KEY_MESSAGE);
|
|
177
|
-
}
|
|
178
|
-
const key =
|
|
179
|
-
credential.type === "api_key" ? nonEmptyText(credential.key) : null;
|
|
180
|
-
if (!key) throw new Error("z.ai Pi auth file has a malformed zai credential");
|
|
181
|
-
return key;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export function parseZaiQuota(raw: unknown, checkedAt: string): CapacityReport {
|
|
113
|
+
export function parseZaiCapacity(raw: unknown): ProviderCapacitySnapshot {
|
|
185
114
|
const root = record(raw);
|
|
186
115
|
const data = record(root?.data);
|
|
187
|
-
if (
|
|
188
|
-
root?.success !== true ||
|
|
189
|
-
root.code !== 200 ||
|
|
190
|
-
!data ||
|
|
191
|
-
!Array.isArray(data.limits)
|
|
192
|
-
) {
|
|
116
|
+
if (root?.success !== true || root.code !== 200 || !data || !Array.isArray(data.limits)) {
|
|
193
117
|
throw new Error("Invalid z.ai quota response");
|
|
194
118
|
}
|
|
195
119
|
const windows = data.limits
|
|
196
120
|
.map(parseLimit)
|
|
197
121
|
.filter((window): window is CapacityWindow => window !== null);
|
|
198
122
|
return {
|
|
199
|
-
harness: "pi",
|
|
200
|
-
provider: "zai",
|
|
201
|
-
generatedAt: checkedAt,
|
|
202
123
|
authenticated: true,
|
|
203
124
|
available: availability(windows),
|
|
204
125
|
windows,
|
|
@@ -206,32 +127,29 @@ export function parseZaiQuota(raw: unknown, checkedAt: string): CapacityReport {
|
|
|
206
127
|
};
|
|
207
128
|
}
|
|
208
129
|
|
|
209
|
-
export async function
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const controller = new AbortController();
|
|
214
|
-
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 5000);
|
|
130
|
+
export async function fetchZaiCapacity(
|
|
131
|
+
key: string,
|
|
132
|
+
options: ZaiRequestOptions = {},
|
|
133
|
+
): Promise<ProviderCapacitySnapshot> {
|
|
215
134
|
let response: Response;
|
|
216
135
|
try {
|
|
217
136
|
response = await (options.fetch ?? globalThis.fetch)(ZAI_QUOTA_URL, {
|
|
218
137
|
method: "GET",
|
|
219
138
|
headers: { Authorization: `Bearer ${key}` },
|
|
220
|
-
signal:
|
|
139
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 5000),
|
|
221
140
|
});
|
|
222
141
|
} catch {
|
|
223
142
|
throw new Error("z.ai quota request failed");
|
|
224
|
-
} finally {
|
|
225
|
-
clearTimeout(timer);
|
|
226
143
|
}
|
|
227
144
|
if (response.status !== 200) {
|
|
228
145
|
throw new Error(`z.ai quota request failed: HTTP ${response.status}`);
|
|
229
146
|
}
|
|
230
|
-
let raw: unknown;
|
|
231
147
|
try {
|
|
232
|
-
|
|
233
|
-
} catch {
|
|
234
|
-
|
|
148
|
+
return parseZaiCapacity(await response.json());
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (error instanceof SyntaxError) {
|
|
151
|
+
throw new Error("z.ai quota response is not valid JSON");
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
235
154
|
}
|
|
236
|
-
return parseZaiQuota(raw, options.checkedAt);
|
|
237
155
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fetchAnthropicCapacity,
|
|
3
|
+
type AnthropicCapacityRequestOptions,
|
|
4
|
+
} from "../providers/anthropic.js";
|
|
5
|
+
import type { CapacityReport, ProviderCapacitySnapshot } from "../types.js";
|
|
6
|
+
import {
|
|
7
|
+
resolveClaudeAnthropicToken,
|
|
8
|
+
type ClaudeCredentialOptions,
|
|
9
|
+
} from "../../harnesses/claude/credentials.js";
|
|
10
|
+
|
|
11
|
+
export type ClaudeCapacityOptions = ClaudeCredentialOptions & AnthropicCapacityRequestOptions;
|
|
12
|
+
|
|
13
|
+
export type ClaudeProbeOptions = ClaudeCapacityOptions & {
|
|
14
|
+
checkedAt: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function claudeReport(snapshot: ProviderCapacitySnapshot, checkedAt: string): CapacityReport {
|
|
18
|
+
return {
|
|
19
|
+
harness: "claude",
|
|
20
|
+
provider: "anthropic",
|
|
21
|
+
generatedAt: checkedAt,
|
|
22
|
+
...snapshot,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function probeClaudeCapacity(options: ClaudeProbeOptions): Promise<CapacityReport> {
|
|
27
|
+
const token = await resolveClaudeAnthropicToken(options);
|
|
28
|
+
const snapshot = await fetchAnthropicCapacity(token, options);
|
|
29
|
+
return claudeReport(snapshot, options.checkedAt);
|
|
30
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import {
|
|
3
|
+
fetchOpenAiPatAccountId,
|
|
4
|
+
fetchOpenAiSubscriptionCapacity,
|
|
5
|
+
parseWhamUsage,
|
|
6
|
+
resetTime,
|
|
7
|
+
safeIdentifier,
|
|
8
|
+
} from "../providers/openai-subscription.js";
|
|
9
|
+
import type { CapacityReport, CapacityWindow } from "../types.js";
|
|
10
|
+
import {
|
|
11
|
+
resolveCodexCredentials,
|
|
12
|
+
type CodexCredentialOptions,
|
|
13
|
+
} from "../../harnesses/codex/credentials.js";
|
|
8
14
|
|
|
9
15
|
type CodexUsageSource = "pat" | "oauth" | "cli";
|
|
10
16
|
type UsageSnapshot = {
|
|
@@ -18,19 +24,16 @@ type RpcMessage = { id?: number; method: string; params?: UnknownRecord };
|
|
|
18
24
|
type CliResponses = { rateLimits: unknown; account: unknown };
|
|
19
25
|
type CodexRpc = (messages: RpcMessage[]) => Promise<CliResponses>;
|
|
20
26
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
type CodexProbeOptions = {
|
|
27
|
+
export type CodexProbeOptions = CodexCredentialOptions & {
|
|
24
28
|
installed: boolean;
|
|
25
29
|
checkedAt: string;
|
|
26
|
-
readFile?: (path: string, encoding: BufferEncoding) => Promise<string>;
|
|
27
30
|
fetch?: typeof globalThis.fetch;
|
|
28
31
|
rpc?: CodexRpc;
|
|
29
32
|
timeoutMs?: number;
|
|
30
|
-
env?: NodeJS.ProcessEnv;
|
|
31
|
-
now?: () => Date;
|
|
32
33
|
};
|
|
33
34
|
|
|
35
|
+
export const CODEX_APP_SERVER_ARGS = ["-s", "read-only", "-a", "untrusted", "app-server"] as const;
|
|
36
|
+
|
|
34
37
|
function record(value: unknown): UnknownRecord | null {
|
|
35
38
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
36
39
|
? (value as UnknownRecord)
|
|
@@ -45,11 +48,6 @@ function nonEmptyText(value: unknown): string | null {
|
|
|
45
48
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
export function resolveCodexAuthPath(env: NodeJS.ProcessEnv = process.env): string {
|
|
49
|
-
const root = env.CODEX_HOME || join(env.HOME || "", ".codex");
|
|
50
|
-
return join(root, "auth.json");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
51
|
export function parseUsage(raw: unknown, source: "pat" | "oauth"): UsageSnapshot {
|
|
54
52
|
const { windows, creditsRemaining } = parseWhamUsage(raw);
|
|
55
53
|
return { windows, creditsRemaining, source };
|
|
@@ -77,14 +75,15 @@ function cliSnapshotWindows(value: unknown, fallbackId: string): CapacityWindow[
|
|
|
77
75
|
].filter((item): item is CapacityWindow => item !== null);
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
function parseCliUsage(raw: unknown): UsageSnapshot {
|
|
81
79
|
const response = record(raw) ?? {};
|
|
82
80
|
const primary = record(response.rateLimits);
|
|
83
81
|
const windows = primary ? cliSnapshotWindows(primary, "codex") : [];
|
|
84
82
|
const buckets = record(response.rateLimitsByLimitId);
|
|
85
83
|
if (buckets) {
|
|
86
|
-
for (const [id, snapshot] of Object.entries(buckets))
|
|
84
|
+
for (const [id, snapshot] of Object.entries(buckets)) {
|
|
87
85
|
windows.push(...cliSnapshotWindows(snapshot, id));
|
|
86
|
+
}
|
|
88
87
|
}
|
|
89
88
|
const unique = [...new Map(windows.map((window) => [window.id, window])).values()];
|
|
90
89
|
return { windows: unique, creditsRemaining: null, source: "cli" };
|
|
@@ -92,7 +91,7 @@ export function parseCliUsage(raw: unknown): UsageSnapshot {
|
|
|
92
91
|
|
|
93
92
|
function capacityFromSnapshot(
|
|
94
93
|
snapshot: UsageSnapshot,
|
|
95
|
-
|
|
94
|
+
options: CodexProbeOptions,
|
|
96
95
|
raw?: unknown,
|
|
97
96
|
): CapacityReport {
|
|
98
97
|
const hasUsage = snapshot.windows.some((window) => window.usedPercent !== null);
|
|
@@ -103,7 +102,7 @@ function capacityFromSnapshot(
|
|
|
103
102
|
return {
|
|
104
103
|
harness: "codex",
|
|
105
104
|
provider: "openai",
|
|
106
|
-
generatedAt:
|
|
105
|
+
generatedAt: options.checkedAt,
|
|
107
106
|
authenticated: true,
|
|
108
107
|
available: reached ? "no" : hasUsage ? "yes" : "unknown",
|
|
109
108
|
windows: snapshot.windows,
|
|
@@ -111,70 +110,9 @@ function capacityFromSnapshot(
|
|
|
111
110
|
};
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
function jwtExpiry(token: string): number | null {
|
|
115
|
-
const part = token.split(".")[1];
|
|
116
|
-
if (!part) return null;
|
|
117
|
-
try {
|
|
118
|
-
return finiteNumber(record(JSON.parse(Buffer.from(part, "base64url").toString("utf8")))?.exp);
|
|
119
|
-
} catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function staleOAuth(tokens: UnknownRecord, token: string, now: Date): boolean {
|
|
125
|
-
const metadata = tokens.expires_at ?? tokens.expiresAt ?? tokens.expiry;
|
|
126
|
-
let expiry: number | null = finiteNumber(metadata);
|
|
127
|
-
if (typeof metadata === "string") {
|
|
128
|
-
const parsed = Date.parse(metadata);
|
|
129
|
-
expiry = Number.isNaN(parsed) ? null : parsed / 1000;
|
|
130
|
-
}
|
|
131
|
-
expiry ??= jwtExpiry(token);
|
|
132
|
-
return expiry !== null && expiry <= now.getTime() / 1000;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function fetchJson(
|
|
136
|
-
fetcher: typeof globalThis.fetch,
|
|
137
|
-
url: string,
|
|
138
|
-
init: RequestInit,
|
|
139
|
-
timeoutMs: number,
|
|
140
|
-
): Promise<unknown> {
|
|
141
|
-
const controller = new AbortController();
|
|
142
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
143
|
-
try {
|
|
144
|
-
const response = await fetcher(url, { ...init, signal: controller.signal });
|
|
145
|
-
if (!response.ok) throw new Error(response.status === 401 ? "unauthorized" : "request failed");
|
|
146
|
-
return await response.json();
|
|
147
|
-
} finally {
|
|
148
|
-
clearTimeout(timer);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async function apiSnapshot(
|
|
153
|
-
token: string,
|
|
154
|
-
accountId: string,
|
|
155
|
-
source: "pat" | "oauth",
|
|
156
|
-
options: CodexProbeOptions,
|
|
157
|
-
): Promise<UsageSnapshot> {
|
|
158
|
-
const fetcher = options.fetch ?? globalThis.fetch;
|
|
159
|
-
const raw = await fetchJson(
|
|
160
|
-
fetcher,
|
|
161
|
-
"https://chatgpt.com/backend-api/wham/usage",
|
|
162
|
-
{
|
|
163
|
-
headers: {
|
|
164
|
-
Authorization: `Bearer ${token}`,
|
|
165
|
-
"ChatGPT-Account-Id": accountId,
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
options.timeoutMs ?? 5000,
|
|
169
|
-
);
|
|
170
|
-
return parseUsage(raw, source);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
113
|
function appServerRpc(messages: RpcMessage[], timeoutMs = 5000): Promise<CliResponses> {
|
|
174
114
|
return new Promise((resolve, reject) => {
|
|
175
|
-
const child = spawn("codex", CODEX_APP_SERVER_ARGS, {
|
|
176
|
-
stdio: ["pipe", "pipe", "ignore"],
|
|
177
|
-
});
|
|
115
|
+
const child = spawn("codex", CODEX_APP_SERVER_ARGS, { stdio: ["pipe", "pipe", "ignore"] });
|
|
178
116
|
const results: Partial<CliResponses> = {};
|
|
179
117
|
let buffer = "";
|
|
180
118
|
let settled = false;
|
|
@@ -235,12 +173,8 @@ export function codexUnavailableReport(checkedAt: string): CapacityReport {
|
|
|
235
173
|
};
|
|
236
174
|
}
|
|
237
175
|
|
|
238
|
-
function unavailable(options: CodexProbeOptions): CapacityReport {
|
|
239
|
-
return codexUnavailableReport(options.checkedAt);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
176
|
async function cliFallback(options: CodexProbeOptions): Promise<CapacityReport> {
|
|
243
|
-
if (!options.installed) return
|
|
177
|
+
if (!options.installed) return codexUnavailableReport(options.checkedAt);
|
|
244
178
|
const messages: RpcMessage[] = [
|
|
245
179
|
{
|
|
246
180
|
id: 1,
|
|
@@ -273,57 +207,53 @@ async function cliFallback(options: CodexProbeOptions): Promise<CapacityReport>
|
|
|
273
207
|
}
|
|
274
208
|
return result;
|
|
275
209
|
} catch {
|
|
276
|
-
return
|
|
210
|
+
return codexUnavailableReport(options.checkedAt);
|
|
277
211
|
}
|
|
278
212
|
}
|
|
279
213
|
|
|
214
|
+
async function subscriptionSnapshot(
|
|
215
|
+
access: string,
|
|
216
|
+
accountId: string,
|
|
217
|
+
source: "pat" | "oauth",
|
|
218
|
+
options: CodexProbeOptions,
|
|
219
|
+
): Promise<UsageSnapshot> {
|
|
220
|
+
const snapshot = await fetchOpenAiSubscriptionCapacity({ access, accountId }, options);
|
|
221
|
+
if (snapshot.authenticated === false) throw new Error("unauthorized");
|
|
222
|
+
return {
|
|
223
|
+
windows: snapshot.windows,
|
|
224
|
+
creditsRemaining: snapshot.creditsRemaining,
|
|
225
|
+
source,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
280
229
|
export async function probeCodexCapacity(options: CodexProbeOptions): Promise<CapacityReport> {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const contents = await (options.readFile ?? readFile)(
|
|
284
|
-
resolveCodexAuthPath(options.env),
|
|
285
|
-
"utf8",
|
|
286
|
-
);
|
|
287
|
-
parsed = record(JSON.parse(contents));
|
|
288
|
-
} catch {
|
|
289
|
-
return cliFallback(options);
|
|
290
|
-
}
|
|
230
|
+
const credentials = await resolveCodexCredentials(options);
|
|
231
|
+
if (!credentials) return cliFallback(options);
|
|
291
232
|
|
|
292
|
-
|
|
293
|
-
const pat = nonEmptyText(auth.personal_access_token);
|
|
294
|
-
if (pat) {
|
|
233
|
+
if (credentials.personalAccessToken) {
|
|
295
234
|
try {
|
|
296
|
-
const
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
options.timeoutMs ?? 5000,
|
|
303
|
-
),
|
|
235
|
+
const accountId = await fetchOpenAiPatAccountId(credentials.personalAccessToken, options);
|
|
236
|
+
const snapshot = await subscriptionSnapshot(
|
|
237
|
+
credentials.personalAccessToken,
|
|
238
|
+
accountId,
|
|
239
|
+
"pat",
|
|
240
|
+
options,
|
|
304
241
|
);
|
|
305
|
-
|
|
306
|
-
if (!accountId) throw new Error("account unavailable");
|
|
307
|
-
return capacityFromSnapshot(await apiSnapshot(pat, accountId, "pat", options), options);
|
|
242
|
+
return capacityFromSnapshot(snapshot, options);
|
|
308
243
|
} catch {
|
|
309
244
|
// Continue to a separately available OAuth credential before using the CLI.
|
|
310
245
|
}
|
|
311
246
|
}
|
|
312
247
|
|
|
313
|
-
|
|
314
|
-
const accessToken = nonEmptyText(tokens?.access_token);
|
|
315
|
-
const accountId = nonEmptyText(tokens?.account_id);
|
|
316
|
-
if (
|
|
317
|
-
tokens &&
|
|
318
|
-
accessToken &&
|
|
319
|
-
accountId &&
|
|
320
|
-
!staleOAuth(tokens, accessToken, (options.now ?? (() => new Date()))())
|
|
321
|
-
) {
|
|
248
|
+
if (credentials.oauth) {
|
|
322
249
|
try {
|
|
323
|
-
|
|
324
|
-
|
|
250
|
+
const snapshot = await subscriptionSnapshot(
|
|
251
|
+
credentials.oauth.access,
|
|
252
|
+
credentials.oauth.accountId,
|
|
253
|
+
"oauth",
|
|
325
254
|
options,
|
|
326
255
|
);
|
|
256
|
+
return capacityFromSnapshot(snapshot, options);
|
|
327
257
|
} catch {
|
|
328
258
|
return cliFallback(options);
|
|
329
259
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { fetchAnthropicCapacity } from "../providers/anthropic.js";
|
|
2
|
+
import { fetchOpenAiPlatformCapacity } from "../providers/openai-platform.js";
|
|
3
|
+
import { fetchOpenAiSubscriptionCapacity } from "../providers/openai-subscription.js";
|
|
4
|
+
import { fetchZaiCapacity } from "../providers/zai.js";
|
|
5
|
+
import type { CapacityReport, ProviderCapacitySnapshot } from "../types.js";
|
|
6
|
+
import {
|
|
7
|
+
resolvePiAnthropicCredential,
|
|
8
|
+
resolvePiOpenAiCredential,
|
|
9
|
+
resolvePiZaiApiKey,
|
|
10
|
+
type PiCredentialOptions,
|
|
11
|
+
type PiOpenAiCredential,
|
|
12
|
+
} from "../../harnesses/pi/credentials.js";
|
|
13
|
+
|
|
14
|
+
export type PiAnthropicCapacityOptions = PiCredentialOptions & {
|
|
15
|
+
now?: () => Date;
|
|
16
|
+
fetch?: typeof globalThis.fetch;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type PiAnthropicProbeOptions = PiAnthropicCapacityOptions & {
|
|
21
|
+
checkedAt: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type PiOpenAiCapacityOptions = PiCredentialOptions & {
|
|
25
|
+
now?: () => Date;
|
|
26
|
+
fetch?: typeof globalThis.fetch;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type PiOpenAiProbeOptions = PiOpenAiCapacityOptions & {
|
|
31
|
+
checkedAt: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type PiZaiCapacityOptions = PiCredentialOptions & {
|
|
35
|
+
now?: () => Date;
|
|
36
|
+
fetch?: typeof globalThis.fetch;
|
|
37
|
+
timeoutMs?: number;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export type PiZaiProbeOptions = PiZaiCapacityOptions & {
|
|
41
|
+
checkedAt: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export async function probePiAnthropicCapacity(
|
|
45
|
+
options: PiAnthropicProbeOptions,
|
|
46
|
+
): Promise<CapacityReport> {
|
|
47
|
+
const credential = await resolvePiAnthropicCredential(options);
|
|
48
|
+
const now = options.now?.() ?? new Date();
|
|
49
|
+
if (credential.expiresMs !== null && credential.expiresMs <= now.getTime()) {
|
|
50
|
+
return {
|
|
51
|
+
harness: "pi",
|
|
52
|
+
provider: "anthropic",
|
|
53
|
+
generatedAt: options.checkedAt,
|
|
54
|
+
authenticated: true,
|
|
55
|
+
available: "unknown",
|
|
56
|
+
windows: [],
|
|
57
|
+
creditsRemaining: null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const snapshot = await fetchAnthropicCapacity(credential.access, options);
|
|
61
|
+
return {
|
|
62
|
+
harness: "pi",
|
|
63
|
+
provider: "anthropic",
|
|
64
|
+
generatedAt: options.checkedAt,
|
|
65
|
+
...snapshot,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function piOpenAiReport(snapshot: ProviderCapacitySnapshot, checkedAt: string): CapacityReport {
|
|
70
|
+
return {
|
|
71
|
+
harness: "pi",
|
|
72
|
+
provider: "openai",
|
|
73
|
+
generatedAt: checkedAt,
|
|
74
|
+
...snapshot,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function jwtExpiryMs(token: string): number | null {
|
|
79
|
+
const part = token.split(".")[1];
|
|
80
|
+
if (!part) return null;
|
|
81
|
+
try {
|
|
82
|
+
const payload = JSON.parse(Buffer.from(part, "base64url").toString("utf8")) as unknown;
|
|
83
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return null;
|
|
84
|
+
const exp = (payload as Record<string, unknown>).exp;
|
|
85
|
+
return typeof exp === "number" && Number.isFinite(exp) ? exp * 1000 : null;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function oauthExpired(
|
|
92
|
+
credential: Extract<PiOpenAiCredential, { kind: "oauth" }>,
|
|
93
|
+
nowMs: number,
|
|
94
|
+
): boolean {
|
|
95
|
+
const expiryMs = credential.expiresMs ?? jwtExpiryMs(credential.access);
|
|
96
|
+
return expiryMs !== null && expiryMs <= nowMs;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function probeOpenAiCapacity(options: PiOpenAiProbeOptions): Promise<CapacityReport> {
|
|
100
|
+
const credential = await resolvePiOpenAiCredential(options);
|
|
101
|
+
if (credential.kind === "platform") {
|
|
102
|
+
const snapshot = await fetchOpenAiPlatformCapacity(credential.key, options);
|
|
103
|
+
return piOpenAiReport(snapshot, options.checkedAt);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const nowMs = Date.parse(options.checkedAt);
|
|
107
|
+
if (Number.isNaN(nowMs) || oauthExpired(credential, nowMs)) {
|
|
108
|
+
return piOpenAiReport(
|
|
109
|
+
{
|
|
110
|
+
authenticated: true,
|
|
111
|
+
available: "unknown",
|
|
112
|
+
windows: [],
|
|
113
|
+
creditsRemaining: null,
|
|
114
|
+
},
|
|
115
|
+
options.checkedAt,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const snapshot = await fetchOpenAiSubscriptionCapacity(credential, options);
|
|
119
|
+
return piOpenAiReport(snapshot, options.checkedAt);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function probeZaiCapacity(options: PiZaiProbeOptions): Promise<CapacityReport> {
|
|
123
|
+
const key = await resolvePiZaiApiKey(options);
|
|
124
|
+
const snapshot = await fetchZaiCapacity(key, options);
|
|
125
|
+
return {
|
|
126
|
+
harness: "pi",
|
|
127
|
+
provider: "zai",
|
|
128
|
+
generatedAt: options.checkedAt,
|
|
129
|
+
...snapshot,
|
|
130
|
+
};
|
|
131
|
+
}
|
package/src/capacity/types.ts
CHANGED
|
@@ -24,3 +24,6 @@ export interface CapacityReport {
|
|
|
24
24
|
windows: CapacityWindow[];
|
|
25
25
|
creditsRemaining: number | null;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/** Provider quota data before a harness/source identity is attached. */
|
|
29
|
+
export type ProviderCapacitySnapshot = Omit<CapacityReport, "harness" | "provider" | "generatedAt">;
|