@ai-devkit/agent-manager 0.36.0 → 0.38.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AgentManager.d.ts +9 -8
- package/dist/AgentManager.d.ts.map +1 -1
- package/dist/AgentManager.js +23 -4
- package/dist/AgentManager.js.map +1 -1
- package/dist/__tests__/AgentManager.test.js +151 -3
- package/dist/__tests__/AgentManager.test.js.map +1 -1
- package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js +486 -0
- package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js.map +1 -0
- package/dist/__tests__/adapters/adapterProcessImports.test.js +52 -0
- package/dist/__tests__/adapters/adapterProcessImports.test.js.map +1 -0
- package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js +247 -0
- package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js.map +1 -0
- 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 +32 -25
- 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/BoundedSummarySkip.test.js +568 -0
- package/dist/__tests__/harnesses/BoundedSummarySkip.test.js.map +1 -0
- package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js +1089 -0
- package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js.map +1 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js +143 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js.map +1 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js +462 -0
- package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/builtinAdapters.test.js +33 -0
- package/dist/__tests__/harnesses/builtinAdapters.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js +79 -0
- package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js +1881 -0
- package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/ClaudeSessionLocator.test.js +425 -0
- package/dist/__tests__/harnesses/claude/ClaudeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js +314 -0
- package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js +49 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +76 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js +173 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js.map +1 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js +181 -0
- package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/CodexAdapter.test.js +685 -0
- package/dist/__tests__/harnesses/codex/CodexAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js +463 -0
- package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/CodexSessionMapping.test.js +86 -0
- package/dist/__tests__/harnesses/codex/CodexSessionMapping.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/CodexSessionParser.test.js +254 -0
- package/dist/__tests__/harnesses/codex/CodexSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +121 -0
- package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js +84 -0
- package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +128 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +246 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +384 -0
- package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -0
- package/dist/__tests__/harnesses/copilot/CopilotAdapter.test.js +659 -0
- package/dist/__tests__/harnesses/copilot/CopilotAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js +290 -0
- package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js.map +1 -0
- package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js +1443 -0
- package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js +491 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js.map +1 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js +399 -0
- package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/grok/GrokAgentMapper.test.js +56 -0
- package/dist/__tests__/harnesses/grok/GrokAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/grok/GrokCliAdapter.test.js +421 -0
- package/dist/__tests__/harnesses/grok/GrokCliAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js +167 -0
- package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js.map +1 -0
- package/dist/__tests__/harnesses/grok/GrokSessionLocator.test.js +133 -0
- package/dist/__tests__/harnesses/grok/GrokSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js +301 -0
- package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js +662 -0
- package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeAdapter.test.js +213 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.js +89 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.js.map +1 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.js +94 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.js.map +1 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js +147 -0
- package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/PiAdapter.test.js +367 -0
- package/dist/__tests__/harnesses/pi/PiAdapter.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js +382 -0
- package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/PiSessionParser.test.js +416 -0
- package/dist/__tests__/harnesses/pi/PiSessionParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/PiSessionTracker.test.js +108 -0
- package/dist/__tests__/harnesses/pi/PiSessionTracker.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +70 -0
- package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiDurableAgentRepository.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +192 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintProtocol.test.js +119 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintProtocol.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +382 -0
- package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -0
- package/dist/__tests__/harnesses/pi/durable/PiStreamParser.test.js +34 -0
- package/dist/__tests__/harnesses/pi/durable/PiStreamParser.test.js.map +1 -0
- package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js +342 -0
- 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 +49 -0
- package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
- package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
- package/dist/__tests__/utils/IncrementalJsonlSummary.test.js +650 -0
- package/dist/__tests__/utils/IncrementalJsonlSummary.test.js.map +1 -0
- package/dist/__tests__/utils/conversationTail.bench.test.js +258 -0
- package/dist/__tests__/utils/conversationTail.bench.test.js.map +1 -0
- package/dist/__tests__/utils/conversationTailParity.test.js +588 -0
- package/dist/__tests__/utils/conversationTailParity.test.js.map +1 -0
- package/dist/__tests__/utils/jsonlTail.test.js +360 -0
- package/dist/__tests__/utils/jsonlTail.test.js.map +1 -0
- package/dist/__tests__/utils/matchingConstants.test.js +35 -0
- package/dist/__tests__/utils/matchingConstants.test.js.map +1 -0
- package/dist/__tests__/utils/process.test.js +436 -2
- package/dist/__tests__/utils/process.test.js.map +1 -1
- package/dist/adapters/AgentAdapter.d.ts +25 -6
- package/dist/adapters/AgentAdapter.d.ts.map +1 -1
- package/dist/adapters/AgentAdapter.js +12 -3
- 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/providers/anthropic.js +153 -0
- 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/providers/zai.js +158 -0
- 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/sources/codex.d.ts +32 -0
- package/dist/capacity/sources/codex.d.ts.map +1 -0
- package/dist/capacity/sources/codex.js +227 -0
- 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/antigravity/AntigravityAgentMapper.d.ts +13 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.js +30 -0
- package/dist/harnesses/antigravity/AntigravityAgentMapper.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts +32 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.js +97 -0
- package/dist/harnesses/antigravity/AntigravityCliAdapter.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts +30 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.js +56 -0
- package/dist/harnesses/antigravity/AntigravitySessionLocator.js.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts +75 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts.map +1 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.js +174 -0
- package/dist/harnesses/antigravity/AntigravitySessionParser.js.map +1 -0
- package/dist/harnesses/claude/ClaudeAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/claude/ClaudeAgentMapper.js +36 -0
- package/dist/harnesses/claude/ClaudeAgentMapper.js.map +1 -0
- package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts +30 -0
- package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts.map +1 -0
- package/dist/harnesses/claude/ClaudeCodeAdapter.js +134 -0
- package/dist/harnesses/claude/ClaudeCodeAdapter.js.map +1 -0
- package/dist/harnesses/claude/ClaudeSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/claude/ClaudeSessionLocator.js +260 -0
- package/dist/harnesses/claude/ClaudeSessionLocator.js.map +1 -0
- package/dist/harnesses/claude/ClaudeSessionParser.d.ts +148 -0
- package/dist/harnesses/claude/ClaudeSessionParser.d.ts.map +1 -0
- package/dist/harnesses/claude/ClaudeSessionParser.js +365 -0
- package/dist/harnesses/claude/ClaudeSessionParser.js.map +1 -0
- 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/durable/ClaudeCliProbe.d.ts.map +1 -0
- package/dist/harnesses/claude/durable/ClaudeCliProbe.js.map +1 -0
- package/dist/harnesses/claude/durable/ClaudePrintAgentService.d.ts.map +1 -0
- package/dist/harnesses/claude/durable/ClaudePrintAgentService.js.map +1 -0
- package/dist/harnesses/claude/durable/ClaudePrintRunner.d.ts.map +1 -0
- package/dist/harnesses/claude/durable/ClaudePrintRunner.js.map +1 -0
- package/dist/harnesses/claude/durable/ClaudeStreamParser.d.ts.map +1 -0
- package/dist/harnesses/claude/durable/ClaudeStreamParser.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/CodexAdapter.d.ts +29 -0
- package/dist/harnesses/codex/CodexAdapter.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexAdapter.js +290 -0
- package/dist/harnesses/codex/CodexAdapter.js.map +1 -0
- package/dist/harnesses/codex/CodexAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexAgentMapper.js +28 -0
- package/dist/harnesses/codex/CodexAgentMapper.js.map +1 -0
- package/dist/harnesses/codex/CodexSessionLocator.d.ts +74 -0
- package/dist/harnesses/codex/CodexSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexSessionLocator.js +359 -0
- package/dist/harnesses/codex/CodexSessionLocator.js.map +1 -0
- package/dist/harnesses/codex/CodexSessionMapping.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexSessionMapping.js +68 -0
- package/dist/harnesses/codex/CodexSessionMapping.js.map +1 -0
- package/dist/harnesses/codex/CodexSessionParser.d.ts +89 -0
- package/dist/harnesses/codex/CodexSessionParser.d.ts.map +1 -0
- package/dist/harnesses/codex/CodexSessionParser.js +308 -0
- package/dist/harnesses/codex/CodexSessionParser.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/durable/CodexCliProbe.d.ts.map +1 -0
- package/dist/harnesses/codex/durable/CodexCliProbe.js.map +1 -0
- package/dist/harnesses/codex/durable/CodexPrintAgentService.d.ts.map +1 -0
- package/dist/harnesses/codex/durable/CodexPrintAgentService.js.map +1 -0
- package/dist/harnesses/codex/durable/CodexPrintRunner.d.ts.map +1 -0
- package/dist/harnesses/codex/durable/CodexPrintRunner.js.map +1 -0
- package/dist/harnesses/codex/durable/CodexStreamParser.d.ts.map +1 -0
- package/dist/harnesses/codex/durable/CodexStreamParser.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/CopilotAdapter.d.ts +36 -0
- package/dist/harnesses/copilot/CopilotAdapter.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotAdapter.js +128 -0
- package/dist/harnesses/copilot/CopilotAdapter.js.map +1 -0
- package/dist/harnesses/copilot/CopilotAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotAgentMapper.js +30 -0
- package/dist/harnesses/copilot/CopilotAgentMapper.js.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.d.ts +42 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.js +126 -0
- package/dist/harnesses/copilot/CopilotSessionLocator.js.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionParser.d.ts +62 -0
- package/dist/harnesses/copilot/CopilotSessionParser.d.ts.map +1 -0
- package/dist/harnesses/copilot/CopilotSessionParser.js +236 -0
- package/dist/harnesses/copilot/CopilotSessionParser.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/gemini/GeminiAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiAgentMapper.js +30 -0
- package/dist/harnesses/gemini/GeminiAgentMapper.js.map +1 -0
- package/dist/harnesses/gemini/GeminiCliAdapter.d.ts +52 -0
- package/dist/harnesses/gemini/GeminiCliAdapter.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiCliAdapter.js +196 -0
- package/dist/harnesses/gemini/GeminiCliAdapter.js.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.d.ts +72 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.js +300 -0
- package/dist/harnesses/gemini/GeminiSessionLocator.js.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionParser.d.ts +121 -0
- package/dist/harnesses/gemini/GeminiSessionParser.d.ts.map +1 -0
- package/dist/harnesses/gemini/GeminiSessionParser.js +272 -0
- package/dist/harnesses/gemini/GeminiSessionParser.js.map +1 -0
- package/dist/harnesses/gemini/fileSignature.d.ts +8 -0
- package/dist/harnesses/gemini/fileSignature.d.ts.map +1 -0
- package/dist/harnesses/gemini/fileSignature.js +9 -0
- package/dist/harnesses/gemini/fileSignature.js.map +1 -0
- package/dist/harnesses/grok/GrokAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/grok/GrokAgentMapper.js +30 -0
- package/dist/harnesses/grok/GrokAgentMapper.js.map +1 -0
- package/dist/harnesses/grok/GrokCliAdapter.d.ts +36 -0
- package/dist/harnesses/grok/GrokCliAdapter.d.ts.map +1 -0
- package/dist/harnesses/grok/GrokCliAdapter.js +102 -0
- package/dist/harnesses/grok/GrokCliAdapter.js.map +1 -0
- package/dist/harnesses/grok/GrokSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/grok/GrokSessionLocator.js +140 -0
- package/dist/harnesses/grok/GrokSessionLocator.js.map +1 -0
- package/dist/harnesses/grok/GrokSessionParser.d.ts +87 -0
- package/dist/harnesses/grok/GrokSessionParser.d.ts.map +1 -0
- package/dist/harnesses/grok/GrokSessionParser.js +185 -0
- package/dist/harnesses/grok/GrokSessionParser.js.map +1 -0
- package/dist/harnesses/index.d.ts +7 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +27 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/kiro/KiroAdapter.d.ts +31 -0
- package/dist/harnesses/kiro/KiroAdapter.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroAdapter.js +125 -0
- package/dist/harnesses/kiro/KiroAdapter.js.map +1 -0
- package/dist/harnesses/kiro/KiroAgentMapper.d.ts +13 -0
- package/dist/harnesses/kiro/KiroAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroAgentMapper.js +29 -0
- package/dist/harnesses/kiro/KiroAgentMapper.js.map +1 -0
- package/dist/harnesses/kiro/KiroSessionLocator.d.ts +38 -0
- package/dist/harnesses/kiro/KiroSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroSessionLocator.js +95 -0
- package/dist/harnesses/kiro/KiroSessionLocator.js.map +1 -0
- package/dist/harnesses/kiro/KiroSessionParser.d.ts +81 -0
- package/dist/harnesses/kiro/KiroSessionParser.d.ts.map +1 -0
- package/dist/harnesses/kiro/KiroSessionParser.js +251 -0
- package/dist/harnesses/kiro/KiroSessionParser.js.map +1 -0
- package/dist/harnesses/opencode/OpenCodeAdapter.d.ts +29 -0
- package/dist/harnesses/opencode/OpenCodeAdapter.d.ts.map +1 -0
- package/dist/harnesses/opencode/OpenCodeAdapter.js +86 -0
- package/dist/harnesses/opencode/OpenCodeAdapter.js.map +1 -0
- package/dist/harnesses/opencode/OpenCodeAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/opencode/OpenCodeAgentMapper.js +42 -0
- package/dist/harnesses/opencode/OpenCodeAgentMapper.js.map +1 -0
- package/dist/harnesses/opencode/OpenCodeSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/opencode/OpenCodeSessionLocator.js +118 -0
- package/dist/harnesses/opencode/OpenCodeSessionLocator.js.map +1 -0
- package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts +16 -0
- package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts.map +1 -0
- package/dist/harnesses/opencode/OpenCodeSessionParser.js +105 -0
- package/dist/harnesses/opencode/OpenCodeSessionParser.js.map +1 -0
- 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/PiAdapter.d.ts +30 -0
- package/dist/harnesses/pi/PiAdapter.d.ts.map +1 -0
- package/dist/harnesses/pi/PiAdapter.js +167 -0
- package/dist/harnesses/pi/PiAdapter.js.map +1 -0
- package/dist/harnesses/pi/PiAgentMapper.d.ts.map +1 -0
- package/dist/harnesses/pi/PiAgentMapper.js +30 -0
- package/dist/harnesses/pi/PiAgentMapper.js.map +1 -0
- package/dist/harnesses/pi/PiSessionLocator.d.ts +61 -0
- package/dist/harnesses/pi/PiSessionLocator.d.ts.map +1 -0
- package/dist/harnesses/pi/PiSessionLocator.js +212 -0
- package/dist/harnesses/pi/PiSessionLocator.js.map +1 -0
- package/dist/harnesses/pi/PiSessionParser.d.ts +88 -0
- package/dist/harnesses/pi/PiSessionParser.d.ts.map +1 -0
- package/dist/harnesses/pi/PiSessionParser.js +318 -0
- package/dist/harnesses/pi/PiSessionParser.js.map +1 -0
- package/dist/harnesses/pi/PiSessionTracker.d.ts.map +1 -0
- package/dist/harnesses/pi/PiSessionTracker.js +69 -0
- package/dist/harnesses/pi/PiSessionTracker.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/durable/PiCliProbe.d.ts.map +1 -0
- package/dist/harnesses/pi/durable/PiCliProbe.js.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintAgentService.d.ts.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintAgentService.js.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintProtocol.d.ts.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintProtocol.js.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintRunner.d.ts.map +1 -0
- package/dist/harnesses/pi/durable/PiPrintRunner.js.map +1 -0
- package/dist/harnesses/pi/durable/PiStreamParser.d.ts.map +1 -0
- package/dist/harnesses/pi/durable/PiStreamParser.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 +68 -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/harnesses/readiness/types.d.ts +76 -0
- 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 +99 -0
- package/dist/harnesses/runtimeProfiles.js.map +1 -0
- package/dist/harnesses/shared.d.ts +41 -0
- package/dist/harnesses/shared.d.ts.map +1 -0
- package/dist/harnesses/shared.js +71 -0
- package/dist/harnesses/shared.js.map +1 -0
- package/dist/index.d.ts +21 -46
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -27
- 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/runtime/tmux/TmuxManager.js +116 -0
- 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 +11 -347
- package/dist/terminal/TtyWriter.js.map +1 -1
- 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 +19 -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 +7 -0
- package/dist/terminal/backends/shared.d.ts.map +1 -0
- package/dist/terminal/backends/shared.js +35 -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 +21 -0
- package/dist/terminal/types.d.ts.map +1 -0
- package/dist/terminal/types.js +10 -0
- package/dist/terminal/types.js.map +1 -0
- package/dist/utils/IncrementalJsonlSummary.d.ts +100 -0
- package/dist/utils/IncrementalJsonlSummary.d.ts.map +1 -0
- package/dist/utils/IncrementalJsonlSummary.js +209 -0
- package/dist/utils/IncrementalJsonlSummary.js.map +1 -0
- package/dist/utils/jsonlTail.d.ts +73 -0
- package/dist/utils/jsonlTail.d.ts.map +1 -0
- package/dist/utils/jsonlTail.js +238 -0
- package/dist/utils/jsonlTail.js.map +1 -0
- package/dist/utils/matching.d.ts +2 -0
- package/dist/utils/matching.d.ts.map +1 -1
- package/dist/utils/matching.js +3 -2
- package/dist/utils/matching.js.map +1 -1
- package/dist/utils/matchingConstants.d.ts +15 -0
- package/dist/utils/matchingConstants.d.ts.map +1 -0
- package/dist/utils/matchingConstants.js +14 -0
- package/dist/utils/matchingConstants.js.map +1 -0
- package/dist/utils/process.d.ts +38 -2
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +131 -43
- package/dist/utils/process.js.map +1 -1
- package/package.json +2 -1
- package/scripts/benchmark-cold-start.mjs +350 -0
- package/src/AgentManager.ts +27 -6
- package/src/__tests__/AgentManager.test.ts +141 -3
- package/src/__tests__/adapters/IncrementalSessionRefresh.test.ts +437 -0
- package/src/__tests__/adapters/adapterProcessImports.test.ts +58 -0
- package/src/__tests__/adapters/adapterSnapshotCandidates.test.ts +243 -0
- 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 +20 -30
- package/src/__tests__/capacity/wham.test.ts +1 -1
- package/src/__tests__/capacity/zai.test.ts +27 -62
- package/src/__tests__/harnesses/BoundedSummarySkip.test.ts +496 -0
- package/src/__tests__/harnesses/SessionSummaryEquivalence.test.ts +726 -0
- package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.ts +133 -0
- package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.ts +396 -0
- package/src/__tests__/harnesses/builtinAdapters.test.ts +33 -0
- package/src/__tests__/harnesses/claude/ClaudeAgentMapper.test.ts +84 -0
- package/src/__tests__/harnesses/claude/ClaudeCodeAdapter.test.ts +1793 -0
- package/src/__tests__/harnesses/claude/ClaudeSessionLocator.test.ts +423 -0
- package/src/__tests__/harnesses/claude/ClaudeSessionParser.test.ts +300 -0
- package/src/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.ts +34 -0
- package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +61 -0
- package/src/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.ts +129 -0
- package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +152 -0
- package/src/__tests__/harnesses/codex/CodexAdapter.test.ts +652 -0
- package/src/__tests__/harnesses/codex/CodexSessionLocator.test.ts +419 -0
- package/src/__tests__/harnesses/codex/CodexSessionMapping.test.ts +63 -0
- package/src/__tests__/harnesses/codex/CodexSessionParser.test.ts +192 -0
- package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +80 -0
- package/src/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.ts +65 -0
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +104 -0
- package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +201 -0
- package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +299 -0
- package/src/__tests__/harnesses/copilot/CopilotAdapter.test.ts +614 -0
- package/src/__tests__/harnesses/copilot/CopilotRefreshIO.test.ts +270 -0
- package/src/__tests__/harnesses/gemini/GeminiCliAdapter.test.ts +1324 -0
- package/src/__tests__/harnesses/gemini/GeminiSessionJsonl.test.ts +402 -0
- package/src/__tests__/harnesses/gemini/GeminiSessionLocator.test.ts +396 -0
- package/src/__tests__/harnesses/grok/GrokAgentMapper.test.ts +57 -0
- package/src/__tests__/harnesses/grok/GrokCliAdapter.test.ts +376 -0
- package/src/__tests__/harnesses/grok/GrokIncrementalRefresh.test.ts +170 -0
- package/src/__tests__/harnesses/grok/GrokSessionLocator.test.ts +106 -0
- package/src/__tests__/harnesses/grok/GrokSessionParser.test.ts +230 -0
- package/src/__tests__/harnesses/kiro/KiroAdapter.test.ts +552 -0
- package/src/__tests__/harnesses/opencode/OpenCodeAdapter.test.ts +215 -0
- package/src/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.ts +83 -0
- package/src/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.ts +84 -0
- package/src/__tests__/harnesses/opencode/OpenCodeSessionParser.test.ts +148 -0
- package/src/__tests__/harnesses/pi/PiAdapter.test.ts +325 -0
- package/src/__tests__/harnesses/pi/PiDiscoveryIO.test.ts +337 -0
- package/src/__tests__/harnesses/pi/PiSessionParser.test.ts +280 -0
- package/src/__tests__/harnesses/pi/PiSessionTracker.test.ts +79 -0
- package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +50 -0
- package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +138 -0
- package/src/__tests__/harnesses/pi/durable/PiPrintProtocol.test.ts +71 -0
- package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +252 -0
- package/src/__tests__/harnesses/pi/durable/PiStreamParser.test.ts +26 -0
- package/src/__tests__/harnesses/readiness/AgentReadiness.test.ts +285 -0
- 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 +31 -1
- package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
- package/src/__tests__/utils/IncrementalJsonlSummary.test.ts +414 -0
- package/src/__tests__/utils/conversationTail.bench.test.ts +193 -0
- package/src/__tests__/utils/conversationTailParity.test.ts +365 -0
- package/src/__tests__/utils/jsonlTail.test.ts +317 -0
- package/src/__tests__/utils/matchingConstants.test.ts +40 -0
- package/src/__tests__/utils/process.test.ts +254 -0
- package/src/adapters/AgentAdapter.ts +37 -14
- package/src/capacity/index.ts +29 -23
- package/src/capacity/providers/anthropic.ts +198 -0
- package/src/capacity/providers/openai-platform.ts +150 -0
- package/src/capacity/providers/openai-subscription.ts +162 -0
- package/src/capacity/providers/zai.ts +155 -0
- package/src/capacity/sources/claude.ts +30 -0
- package/src/capacity/sources/codex.ts +262 -0
- package/src/capacity/sources/pi.ts +131 -0
- package/src/capacity/types.ts +3 -0
- package/src/harnesses/antigravity/AntigravityAgentMapper.ts +34 -0
- package/src/harnesses/antigravity/AntigravityCliAdapter.ts +126 -0
- package/src/harnesses/antigravity/AntigravitySessionLocator.ts +75 -0
- package/src/harnesses/antigravity/AntigravitySessionParser.ts +252 -0
- package/src/harnesses/claude/ClaudeAgentMapper.ts +55 -0
- package/src/harnesses/claude/ClaudeCodeAdapter.ts +175 -0
- package/src/harnesses/claude/ClaudeSessionLocator.ts +358 -0
- package/src/harnesses/claude/ClaudeSessionParser.ts +524 -0
- package/src/harnesses/claude/credentials.ts +122 -0
- package/src/harnesses/claude/readiness.ts +69 -0
- package/src/harnesses/codex/CodexAdapter.ts +337 -0
- package/src/harnesses/codex/CodexAgentMapper.ts +26 -0
- package/src/harnesses/codex/CodexSessionLocator.ts +509 -0
- package/src/harnesses/codex/CodexSessionMapping.ts +89 -0
- package/src/harnesses/codex/CodexSessionParser.ts +462 -0
- package/src/harnesses/codex/credentials.ts +81 -0
- package/src/harnesses/codex/readiness.ts +72 -0
- package/src/harnesses/copilot/CopilotAdapter.ts +161 -0
- package/src/harnesses/copilot/CopilotAgentMapper.ts +27 -0
- package/src/harnesses/copilot/CopilotSessionLocator.ts +161 -0
- package/src/harnesses/copilot/CopilotSessionParser.ts +380 -0
- package/src/harnesses/copilot/readiness.ts +33 -0
- package/src/harnesses/gemini/GeminiAgentMapper.ts +27 -0
- package/src/harnesses/gemini/GeminiCliAdapter.ts +272 -0
- package/src/harnesses/gemini/GeminiSessionLocator.ts +394 -0
- package/src/harnesses/gemini/GeminiSessionParser.ts +395 -0
- package/src/harnesses/gemini/fileSignature.ts +10 -0
- package/src/harnesses/grok/GrokAgentMapper.ts +32 -0
- package/src/harnesses/grok/GrokCliAdapter.ts +126 -0
- package/src/harnesses/grok/GrokSessionLocator.ts +179 -0
- package/src/harnesses/grok/GrokSessionParser.ts +251 -0
- package/src/harnesses/index.ts +28 -0
- package/src/harnesses/kiro/KiroAdapter.ts +143 -0
- package/src/harnesses/kiro/KiroAgentMapper.ts +34 -0
- package/src/harnesses/kiro/KiroSessionLocator.ts +143 -0
- package/src/harnesses/kiro/KiroSessionParser.ts +376 -0
- package/src/harnesses/opencode/OpenCodeAdapter.ts +110 -0
- package/src/harnesses/opencode/OpenCodeAgentMapper.ts +51 -0
- package/src/harnesses/opencode/OpenCodeSessionLocator.ts +151 -0
- package/src/harnesses/opencode/OpenCodeSessionParser.ts +146 -0
- package/src/harnesses/opencode/readiness.ts +48 -0
- package/src/harnesses/pi/PiAdapter.ts +197 -0
- package/src/harnesses/pi/PiAgentMapper.ts +27 -0
- package/src/harnesses/pi/PiSessionLocator.ts +288 -0
- package/src/harnesses/pi/PiSessionParser.ts +488 -0
- package/src/harnesses/pi/PiSessionTracker.ts +87 -0
- package/src/harnesses/pi/credentials.ts +129 -0
- package/src/harnesses/pi/readiness.ts +104 -0
- package/src/harnesses/readiness/AgentReadiness.ts +87 -0
- package/src/harnesses/readiness/checks.ts +336 -0
- package/src/harnesses/readiness/types.ts +90 -0
- package/src/harnesses/runtimeProfiles.ts +103 -0
- package/src/harnesses/shared.ts +119 -0
- package/src/index.ts +20 -131
- 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/runtime/tmux/TmuxManager.ts +102 -0
- package/src/runtime/types.ts +1 -1
- package/src/terminal/TerminalFocusManager.ts +19 -292
- package/src/terminal/TtyWriter.ts +16 -336
- package/src/terminal/backends/index.ts +21 -0
- package/src/terminal/backends/iterm2.ts +126 -0
- package/src/terminal/backends/shared.ts +42 -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 +22 -0
- package/src/utils/IncrementalJsonlSummary.ts +306 -0
- package/src/utils/jsonlTail.ts +349 -0
- package/src/utils/matching.ts +3 -3
- package/src/utils/matchingConstants.ts +15 -0
- package/src/utils/process.ts +189 -45
- package/dist/__tests__/adapters/AntigravityCliAdapter.test.js +0 -381
- package/dist/__tests__/adapters/AntigravityCliAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +0 -1853
- package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/CodexAdapter.test.js +0 -391
- package/dist/__tests__/adapters/CodexAdapter.test.js.map +0 -1
- package/dist/__tests__/adapters/KiroAdapter.test.js +0 -607
- package/dist/__tests__/adapters/KiroAdapter.test.js.map +0 -1
- package/dist/__tests__/durable/CodexCliProbe.test.js +0 -129
- package/dist/__tests__/durable/CodexCliProbe.test.js.map +0 -1
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +0 -84
- package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +0 -126
- package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintAgentService.test.js +0 -271
- package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +0 -1
- package/dist/__tests__/durable/CodexPrintRunner.test.js +0 -393
- package/dist/__tests__/durable/CodexPrintRunner.test.js.map +0 -1
- package/dist/__tests__/print/ClaudeCliProbe.test.js +0 -49
- package/dist/__tests__/print/ClaudeCliProbe.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +0 -75
- package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintAgentService.test.js +0 -173
- package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +0 -1
- package/dist/__tests__/print/ClaudePrintRunner.test.js +0 -181
- package/dist/__tests__/print/ClaudePrintRunner.test.js.map +0 -1
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +0 -79
- package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +0 -1
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +0 -436
- package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +0 -1
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +0 -194
- package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +0 -1
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +0 -86
- package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +0 -1
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js +0 -254
- package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +0 -1
- package/dist/__tests__/providers/copilot/CopilotAdapter.test.js +0 -659
- package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js +0 -1434
- package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/grok/GrokAgentMapper.test.js +0 -56
- package/dist/__tests__/providers/grok/GrokAgentMapper.test.js.map +0 -1
- package/dist/__tests__/providers/grok/GrokCliAdapter.test.js +0 -421
- package/dist/__tests__/providers/grok/GrokCliAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/grok/GrokSessionLocator.test.js +0 -133
- package/dist/__tests__/providers/grok/GrokSessionLocator.test.js.map +0 -1
- package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js +0 -213
- package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js +0 -89
- package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js.map +0 -1
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js +0 -94
- package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js.map +0 -1
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js +0 -147
- package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js.map +0 -1
- package/dist/__tests__/providers/pi/PiAdapter.test.js +0 -367
- package/dist/__tests__/providers/pi/PiAdapter.test.js.map +0 -1
- package/dist/__tests__/providers/pi/PiSessionParser.test.js +0 -246
- package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +0 -1
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js +0 -108
- package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +0 -76
- package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +0 -202
- package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +0 -119
- package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +0 -386
- package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +0 -1
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +0 -34
- package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +0 -1
- package/dist/__tests__/readiness/AgentReadiness.test.js +0 -301
- package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
- package/dist/__tests__/utils/ClaudeSessionParser.test.js +0 -314
- package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +0 -1
- package/dist/__tests__/utils/agents.test.js +0 -29
- package/dist/__tests__/utils/agents.test.js.map +0 -1
- package/dist/adapters/AntigravityCliAdapter.d.ts +0 -57
- package/dist/adapters/AntigravityCliAdapter.d.ts.map +0 -1
- package/dist/adapters/AntigravityCliAdapter.js +0 -273
- package/dist/adapters/AntigravityCliAdapter.js.map +0 -1
- package/dist/adapters/KiroAdapter.d.ts +0 -46
- package/dist/adapters/KiroAdapter.d.ts.map +0 -1
- package/dist/adapters/KiroAdapter.js +0 -344
- package/dist/adapters/KiroAdapter.js.map +0 -1
- package/dist/adapters/index.d.ts +0 -12
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -12
- package/dist/adapters/index.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 +0 -271
- package/dist/capacity/claude.js.map +0 -1
- package/dist/capacity/codex.d.ts +0 -36
- package/dist/capacity/codex.d.ts.map +0 -1
- package/dist/capacity/codex.js +0 -280
- package/dist/capacity/codex.js.map +0 -1
- package/dist/capacity/openai.d.ts +0 -48
- package/dist/capacity/openai.d.ts.map +0 -1
- package/dist/capacity/openai.js +0 -312
- 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 +0 -203
- package/dist/capacity/zai.js.map +0 -1
- package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeAgentMapper.js +0 -42
- package/dist/providers/claude/ClaudeAgentMapper.js.map +0 -1
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts +0 -31
- package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeCodeAdapter.js +0 -132
- package/dist/providers/claude/ClaudeCodeAdapter.js.map +0 -1
- package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeSessionLocator.js +0 -260
- package/dist/providers/claude/ClaudeSessionLocator.js.map +0 -1
- package/dist/providers/claude/ClaudeSessionParser.d.ts +0 -114
- package/dist/providers/claude/ClaudeSessionParser.d.ts.map +0 -1
- package/dist/providers/claude/ClaudeSessionParser.js +0 -309
- package/dist/providers/claude/ClaudeSessionParser.js.map +0 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +0 -1
- package/dist/providers/claude/durable/ClaudeCliProbe.js.map +0 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +0 -1
- package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +0 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +0 -1
- package/dist/providers/claude/durable/ClaudePrintRunner.js.map +0 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +0 -1
- package/dist/providers/claude/durable/ClaudeStreamParser.js.map +0 -1
- package/dist/providers/codex/CodexAdapter.d.ts +0 -28
- package/dist/providers/codex/CodexAdapter.d.ts.map +0 -1
- package/dist/providers/codex/CodexAdapter.js +0 -170
- package/dist/providers/codex/CodexAdapter.js.map +0 -1
- package/dist/providers/codex/CodexAgentMapper.d.ts.map +0 -1
- package/dist/providers/codex/CodexAgentMapper.js +0 -35
- package/dist/providers/codex/CodexAgentMapper.js.map +0 -1
- package/dist/providers/codex/CodexSessionLocator.d.ts +0 -44
- package/dist/providers/codex/CodexSessionLocator.d.ts.map +0 -1
- package/dist/providers/codex/CodexSessionLocator.js +0 -207
- package/dist/providers/codex/CodexSessionLocator.js.map +0 -1
- package/dist/providers/codex/CodexSessionMapping.d.ts.map +0 -1
- package/dist/providers/codex/CodexSessionMapping.js +0 -68
- package/dist/providers/codex/CodexSessionMapping.js.map +0 -1
- package/dist/providers/codex/CodexSessionParser.d.ts +0 -58
- package/dist/providers/codex/CodexSessionParser.d.ts.map +0 -1
- package/dist/providers/codex/CodexSessionParser.js +0 -262
- package/dist/providers/codex/CodexSessionParser.js.map +0 -1
- package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +0 -1
- package/dist/providers/codex/durable/CodexCliProbe.js.map +0 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +0 -1
- package/dist/providers/codex/durable/CodexPrintAgentService.js.map +0 -1
- package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +0 -1
- package/dist/providers/codex/durable/CodexPrintRunner.js.map +0 -1
- package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +0 -1
- package/dist/providers/codex/durable/CodexStreamParser.js.map +0 -1
- package/dist/providers/copilot/CopilotAdapter.d.ts +0 -35
- package/dist/providers/copilot/CopilotAdapter.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotAdapter.js +0 -123
- package/dist/providers/copilot/CopilotAdapter.js.map +0 -1
- package/dist/providers/copilot/CopilotAgentMapper.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotAgentMapper.js +0 -37
- package/dist/providers/copilot/CopilotAgentMapper.js.map +0 -1
- package/dist/providers/copilot/CopilotSessionLocator.d.ts +0 -20
- package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotSessionLocator.js +0 -49
- package/dist/providers/copilot/CopilotSessionLocator.js.map +0 -1
- package/dist/providers/copilot/CopilotSessionParser.d.ts +0 -30
- package/dist/providers/copilot/CopilotSessionParser.d.ts.map +0 -1
- package/dist/providers/copilot/CopilotSessionParser.js +0 -181
- package/dist/providers/copilot/CopilotSessionParser.js.map +0 -1
- package/dist/providers/gemini/GeminiAgentMapper.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiAgentMapper.js +0 -37
- package/dist/providers/gemini/GeminiAgentMapper.js.map +0 -1
- package/dist/providers/gemini/GeminiCliAdapter.d.ts +0 -53
- package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiCliAdapter.js +0 -197
- package/dist/providers/gemini/GeminiCliAdapter.js.map +0 -1
- package/dist/providers/gemini/GeminiSessionLocator.d.ts +0 -30
- package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiSessionLocator.js +0 -142
- package/dist/providers/gemini/GeminiSessionLocator.js.map +0 -1
- package/dist/providers/gemini/GeminiSessionParser.d.ts +0 -94
- package/dist/providers/gemini/GeminiSessionParser.d.ts.map +0 -1
- package/dist/providers/gemini/GeminiSessionParser.js +0 -166
- package/dist/providers/gemini/GeminiSessionParser.js.map +0 -1
- package/dist/providers/grok/GrokAgentMapper.d.ts.map +0 -1
- package/dist/providers/grok/GrokAgentMapper.js +0 -36
- package/dist/providers/grok/GrokAgentMapper.js.map +0 -1
- package/dist/providers/grok/GrokCliAdapter.d.ts +0 -36
- package/dist/providers/grok/GrokCliAdapter.d.ts.map +0 -1
- package/dist/providers/grok/GrokCliAdapter.js +0 -98
- package/dist/providers/grok/GrokCliAdapter.js.map +0 -1
- package/dist/providers/grok/GrokSessionLocator.d.ts.map +0 -1
- package/dist/providers/grok/GrokSessionLocator.js +0 -140
- package/dist/providers/grok/GrokSessionLocator.js.map +0 -1
- package/dist/providers/grok/GrokSessionParser.d.ts +0 -54
- package/dist/providers/grok/GrokSessionParser.d.ts.map +0 -1
- package/dist/providers/grok/GrokSessionParser.js +0 -122
- package/dist/providers/grok/GrokSessionParser.js.map +0 -1
- package/dist/providers/opencode/OpenCodeAdapter.d.ts +0 -31
- package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeAdapter.js +0 -89
- package/dist/providers/opencode/OpenCodeAdapter.js.map +0 -1
- package/dist/providers/opencode/OpenCodeAgentMapper.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeAgentMapper.js +0 -50
- package/dist/providers/opencode/OpenCodeAgentMapper.js.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionLocator.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionLocator.js +0 -118
- package/dist/providers/opencode/OpenCodeSessionLocator.js.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts +0 -18
- package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +0 -1
- package/dist/providers/opencode/OpenCodeSessionParser.js +0 -104
- package/dist/providers/opencode/OpenCodeSessionParser.js.map +0 -1
- package/dist/providers/pi/PiAdapter.d.ts +0 -29
- package/dist/providers/pi/PiAdapter.d.ts.map +0 -1
- package/dist/providers/pi/PiAdapter.js +0 -163
- package/dist/providers/pi/PiAdapter.js.map +0 -1
- package/dist/providers/pi/PiAgentMapper.d.ts.map +0 -1
- package/dist/providers/pi/PiAgentMapper.js +0 -37
- package/dist/providers/pi/PiAgentMapper.js.map +0 -1
- package/dist/providers/pi/PiSessionLocator.d.ts +0 -24
- package/dist/providers/pi/PiSessionLocator.d.ts.map +0 -1
- package/dist/providers/pi/PiSessionLocator.js +0 -86
- package/dist/providers/pi/PiSessionLocator.js.map +0 -1
- package/dist/providers/pi/PiSessionParser.d.ts +0 -36
- package/dist/providers/pi/PiSessionParser.d.ts.map +0 -1
- package/dist/providers/pi/PiSessionParser.js +0 -191
- package/dist/providers/pi/PiSessionParser.js.map +0 -1
- package/dist/providers/pi/PiSessionTracker.d.ts.map +0 -1
- package/dist/providers/pi/PiSessionTracker.js +0 -69
- package/dist/providers/pi/PiSessionTracker.js.map +0 -1
- package/dist/providers/pi/durable/PiCliProbe.d.ts.map +0 -1
- package/dist/providers/pi/durable/PiCliProbe.js.map +0 -1
- package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +0 -1
- package/dist/providers/pi/durable/PiPrintAgentService.js.map +0 -1
- package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +0 -1
- package/dist/providers/pi/durable/PiPrintProtocol.js.map +0 -1
- package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +0 -1
- package/dist/providers/pi/durable/PiPrintRunner.js.map +0 -1
- package/dist/providers/pi/durable/PiStreamParser.d.ts.map +0 -1
- package/dist/providers/pi/durable/PiStreamParser.js.map +0 -1
- package/dist/readiness/AgentReadiness.d.ts +0 -67
- 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 +0 -135
- 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 -15
- package/dist/utils/agents.d.ts.map +0 -1
- package/dist/utils/agents.js +0 -82
- package/dist/utils/agents.js.map +0 -1
- package/dist/utils/index.d.ts +0 -7
- 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__/adapters/AntigravityCliAdapter.test.ts +0 -324
- package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +0 -1763
- package/src/__tests__/adapters/CodexAdapter.test.ts +0 -387
- package/src/__tests__/adapters/KiroAdapter.test.ts +0 -534
- package/src/__tests__/durable/CodexCliProbe.test.ts +0 -85
- package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +0 -65
- package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +0 -104
- package/src/__tests__/durable/CodexPrintAgentService.test.ts +0 -217
- package/src/__tests__/durable/CodexPrintRunner.test.ts +0 -309
- package/src/__tests__/fixtures/fake-claude.cjs +0 -31
- package/src/__tests__/fixtures/fake-codex.cjs +0 -56
- package/src/__tests__/print/ClaudeCliProbe.test.ts +0 -34
- package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +0 -61
- package/src/__tests__/print/ClaudePrintAgentService.test.ts +0 -129
- package/src/__tests__/print/ClaudePrintRunner.test.ts +0 -152
- package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +0 -84
- package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +0 -434
- package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +0 -182
- package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +0 -63
- package/src/__tests__/providers/codex/CodexSessionParser.test.ts +0 -192
- package/src/__tests__/providers/copilot/CopilotAdapter.test.ts +0 -614
- package/src/__tests__/providers/gemini/GeminiCliAdapter.test.ts +0 -1320
- package/src/__tests__/providers/grok/GrokAgentMapper.test.ts +0 -57
- package/src/__tests__/providers/grok/GrokCliAdapter.test.ts +0 -376
- package/src/__tests__/providers/grok/GrokSessionLocator.test.ts +0 -106
- package/src/__tests__/providers/opencode/OpenCodeAdapter.test.ts +0 -215
- package/src/__tests__/providers/opencode/OpenCodeAgentMapper.test.ts +0 -83
- package/src/__tests__/providers/opencode/OpenCodeSessionLocator.test.ts +0 -84
- package/src/__tests__/providers/opencode/OpenCodeSessionParser.test.ts +0 -148
- package/src/__tests__/providers/pi/PiAdapter.test.ts +0 -325
- package/src/__tests__/providers/pi/PiSessionParser.test.ts +0 -190
- package/src/__tests__/providers/pi/PiSessionTracker.test.ts +0 -79
- package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +0 -54
- package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +0 -141
- package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +0 -71
- package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +0 -253
- package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +0 -26
- package/src/__tests__/readiness/AgentReadiness.test.ts +0 -242
- package/src/__tests__/utils/ClaudeSessionParser.test.ts +0 -300
- package/src/__tests__/utils/agents.test.ts +0 -31
- package/src/adapters/AntigravityCliAdapter.ts +0 -356
- package/src/adapters/KiroAdapter.ts +0 -456
- package/src/adapters/index.ts +0 -17
- package/src/capacity/claude.ts +0 -313
- package/src/capacity/codex.ts +0 -332
- package/src/capacity/openai.ts +0 -361
- package/src/capacity/wham.ts +0 -84
- package/src/capacity/zai.ts +0 -237
- package/src/providers/claude/ClaudeAgentMapper.ts +0 -63
- package/src/providers/claude/ClaudeCodeAdapter.ts +0 -173
- package/src/providers/claude/ClaudeSessionLocator.ts +0 -358
- package/src/providers/claude/ClaudeSessionParser.ts +0 -432
- package/src/providers/codex/CodexAdapter.ts +0 -213
- package/src/providers/codex/CodexAgentMapper.ts +0 -35
- package/src/providers/codex/CodexSessionLocator.ts +0 -279
- package/src/providers/codex/CodexSessionMapping.ts +0 -89
- package/src/providers/codex/CodexSessionParser.ts +0 -385
- package/src/providers/copilot/CopilotAdapter.ts +0 -161
- package/src/providers/copilot/CopilotAgentMapper.ts +0 -36
- package/src/providers/copilot/CopilotSessionLocator.ts +0 -63
- package/src/providers/copilot/CopilotSessionParser.ts +0 -289
- package/src/providers/gemini/GeminiAgentMapper.ts +0 -36
- package/src/providers/gemini/GeminiCliAdapter.ts +0 -274
- package/src/providers/gemini/GeminiSessionLocator.ts +0 -183
- package/src/providers/gemini/GeminiSessionParser.ts +0 -271
- package/src/providers/grok/GrokAgentMapper.ts +0 -41
- package/src/providers/grok/GrokCliAdapter.ts +0 -125
- package/src/providers/grok/GrokSessionLocator.ts +0 -179
- package/src/providers/grok/GrokSessionParser.ts +0 -166
- package/src/providers/opencode/OpenCodeAdapter.ts +0 -116
- package/src/providers/opencode/OpenCodeAgentMapper.ts +0 -61
- package/src/providers/opencode/OpenCodeSessionLocator.ts +0 -151
- package/src/providers/opencode/OpenCodeSessionParser.ts +0 -145
- package/src/providers/pi/PiAdapter.ts +0 -195
- package/src/providers/pi/PiAgentMapper.ts +0 -36
- package/src/providers/pi/PiSessionLocator.ts +0 -110
- package/src/providers/pi/PiSessionParser.ts +0 -284
- package/src/providers/pi/PiSessionTracker.ts +0 -87
- package/src/readiness/AgentReadiness.ts +0 -730
- package/src/terminal/TmuxManager.ts +0 -123
- package/src/terminal/index.ts +0 -4
- package/src/utils/agents.ts +0 -75
- package/src/utils/index.ts +0 -12
- /package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js +0 -0
- /package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js +0 -0
- /package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js +0 -0
- /package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts +0 -0
- /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js +0 -0
- /package/src/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudeCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudePrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudePrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/claude/durable/ClaudeStreamParser.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexPrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexPrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/codex/durable/CodexStreamParser.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiCliProbe.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintAgentService.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintProtocol.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiPrintRunner.ts +0 -0
- /package/src/{providers → harnesses}/pi/durable/PiStreamParser.ts +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { CODEX_APP_SERVER_ARGS, parseUsage, probeCodexCapacity
|
|
2
|
+
import { CODEX_APP_SERVER_ARGS, parseUsage, probeCodexCapacity } from "../../capacity/sources/codex.js";
|
|
3
|
+
import { resolveCodexAuthPath } from "../../harnesses/codex/credentials.js";
|
|
4
|
+
import { toRateWindow } from "../../capacity/providers/openai-subscription.js";
|
|
3
5
|
const checkedAt = "2026-08-20T10:00:00.000Z";
|
|
4
6
|
const context = {
|
|
5
7
|
installed: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/capacity/codex.test.ts"],"sourcesContent":["import { describe, expect, it, vi } from \"vitest\";\nimport {\n CODEX_APP_SERVER_ARGS,\n parseUsage,\n probeCodexCapacity,\n resolveCodexAuthPath,\n toRateWindow,\n} from \"../../capacity/codex.js\";\n\nconst checkedAt = \"2026-08-20T10:00:00.000Z\";\nconst context = { installed: true, checkedAt };\n\nfunction apiUsage(overrides: Record<string, unknown> = {}) {\n return {\n rate_limit: {\n primary_window: {\n used_percent: 20,\n limit_window_seconds: 18_000,\n reset_at: 1_787_220_000,\n },\n secondary_window: {\n used_percent: 60,\n limit_window_seconds: 604_800,\n reset_at: 1_787_824_800,\n },\n ...overrides,\n },\n credits: { balance: 12.5 },\n additional_rate_limits: [\n {\n limit_name: \"reviews\",\n rate_limit: {\n primary_window: {\n used_percent: 10,\n limit_window_seconds: 3_600,\n reset_at: 1_787_220_000,\n },\n },\n },\n ],\n };\n}\n\ndescribe(\"Codex auth resolution\", () => {\n it(\"uses CODEX_HOME before HOME\", () => {\n expect(\n resolveCodexAuthPath({\n CODEX_HOME: \"/custom/codex\",\n HOME: \"/users/test\",\n }),\n ).toBe(\"/custom/codex/auth.json\");\n });\n\n it(\"falls back to ~/.codex/auth.json\", () => {\n expect(resolveCodexAuthPath({ HOME: \"/users/test\" })).toBe(\n \"/users/test/.codex/auth.json\",\n );\n });\n});\n\ndescribe(\"Codex API usage mapping\", () => {\n it(\"converts an API window without treating missing data as zero\", () => {\n expect(\n toRateWindow(\n {\n used_percent: 25,\n limit_window_seconds: 18_000,\n reset_at: 1_787_220_000,\n },\n \"session\",\n \"Session\",\n ),\n ).toEqual({\n id: \"session\",\n label: \"Session\",\n durationMinutes: 300,\n usedPercent: 25,\n resetsAt: \"2026-08-20T10:00:00.000Z\",\n });\n expect(toRateWindow({}, \"session\", \"Session\")).toMatchObject({\n usedPercent: null,\n });\n });\n\n it(\"maps session, weekly, credits, and extra limits\", () => {\n const snapshot = parseUsage(apiUsage(), \"pat\");\n expect(snapshot).toMatchObject({ source: \"pat\", creditsRemaining: 12.5 });\n expect(snapshot.windows).toEqual([\n expect.objectContaining({ id: \"session\", durationMinutes: 300 }),\n expect.objectContaining({ id: \"weekly\", durationMinutes: 10080 }),\n expect.objectContaining({ id: \"reviews:primary\", durationMinutes: 60 }),\n ]);\n });\n\n it(\"represents missing limits as unavailable rather than zero\", () => {\n const snapshot = parseUsage({ credits: {} }, \"oauth\");\n expect(snapshot.windows).toEqual([]);\n expect(snapshot.creditsRemaining).toBeNull();\n });\n});\n\ndescribe(\"tiered Codex probing\", () => {\n it(\"selects PAT, calls whoami then usage, and never invokes the CLI\", async () => {\n const fetch = vi\n .fn()\n .mockResolvedValueOnce(\n new Response(JSON.stringify({ chatgpt_account_id: \"acct-1\" }), {\n status: 200,\n }),\n )\n .mockResolvedValueOnce(\n new Response(JSON.stringify(apiUsage()), { status: 200 }),\n );\n const rpc = vi.fn();\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: \"pat-secret\",\n tokens: {\n access_token: \"ignored-oauth\",\n account_id: \"ignored-account\",\n },\n }),\n fetch,\n rpc,\n });\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(fetch.mock.calls[0][0]).toBe(\n \"https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami\",\n );\n expect(fetch.mock.calls[1][0]).toBe(\n \"https://chatgpt.com/backend-api/wham/usage\",\n );\n expect(fetch.mock.calls[1][1].headers).toMatchObject({\n Authorization: \"Bearer pat-secret\",\n \"ChatGPT-Account-Id\": \"acct-1\",\n });\n expect(rpc).not.toHaveBeenCalled();\n expect(result).toMatchObject({\n harness: \"codex\",\n provider: \"openai\",\n available: \"yes\",\n creditsRemaining: 12.5,\n authenticated: true,\n });\n expect(result.windows.map((window) => window.id)).toEqual([\n \"session\",\n \"weekly\",\n \"reviews:primary\",\n ]);\n });\n\n it(\"selects a fresh OAuth token without calling whoami\", async () => {\n const fetch = vi\n .fn()\n .mockResolvedValue(\n new Response(JSON.stringify(apiUsage()), { status: 200 }),\n );\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct-2\",\n expires_at: 1_800_000_000,\n },\n }),\n fetch,\n now: () => new Date(\"2026-08-20T10:00:00.000Z\"),\n });\n expect(fetch).toHaveBeenCalledOnce();\n expect(fetch.mock.calls[0][1].headers).toMatchObject({\n Authorization: \"Bearer oauth-secret\",\n \"ChatGPT-Account-Id\": \"acct-2\",\n });\n expect(result.available).toBe(\"yes\");\n });\n\n it.each([\n [\n \"missing auth file\",\n async () => {\n throw Object.assign(new Error(\"missing\"), { code: \"ENOENT\" });\n },\n ],\n [\n \"stale OAuth token\",\n async () =>\n JSON.stringify({\n tokens: {\n access_token: \"stale-secret\",\n account_id: \"acct\",\n expires_at: 1,\n },\n }),\n ],\n [\n \"OAuth 401\",\n async () =>\n JSON.stringify({\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct\",\n expires_at: 1_800_000_000,\n },\n }),\n ],\n ])(\"falls back to the CLI for %s\", async (name, readFile) => {\n const fetch = vi\n .fn()\n .mockResolvedValue(\n new Response(\"\", { status: name === \"OAuth 401\" ? 401 : 200 }),\n );\n const rpc = vi.fn(async () => ({\n rateLimits: {\n rateLimits: {\n primary: { usedPercent: 5, windowDurationMins: 300, resetsAt: null },\n },\n },\n account: { account: { type: \"chatgpt\" } },\n }));\n const result = await probeCodexCapacity({\n ...context,\n readFile,\n fetch,\n rpc,\n now: () => new Date(checkedAt),\n });\n expect(rpc).toHaveBeenCalledOnce();\n expect(result.windows).toHaveLength(1);\n });\n\n it(\"falls back to CLI if PAT requests fail\", async () => {\n const rpc = vi.fn(async () => ({\n rateLimits: {},\n account: { account: null },\n }));\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({ personal_access_token: \"pat-secret\" }),\n fetch: vi.fn().mockRejectedValue(new Error(\"network failure pat-secret\")),\n rpc,\n });\n expect(rpc).toHaveBeenCalledOnce();\n expect(result.available).toBe(\"unknown\");\n });\n\n it(\"tries fresh OAuth after a PAT request fails\", async () => {\n const fetch = vi\n .fn()\n .mockRejectedValueOnce(new Error(\"PAT failed\"))\n .mockResolvedValueOnce(\n new Response(JSON.stringify(apiUsage()), { status: 200 }),\n );\n const rpc = vi.fn();\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: \"pat-secret\",\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct\",\n expires_at: 1_800_000_000,\n },\n }),\n fetch,\n rpc,\n now: () => new Date(checkedAt),\n });\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(result.available).toBe(\"yes\");\n expect(rpc).not.toHaveBeenCalled();\n });\n\n it(\"uses hardened read-only app-server arguments and both account methods\", async () => {\n const rpc = vi.fn(async () => ({\n rateLimits: {\n rateLimits: {\n primary: { usedPercent: 5, windowDurationMins: 300, resetsAt: null },\n },\n },\n account: { account: { type: \"chatgpt\" } },\n }));\n await probeCodexCapacity({ ...context, readFile: async () => \"{}\", rpc });\n const messages = rpc.mock.calls[0][0];\n expect(messages.map((message) => message.method)).toEqual([\n \"initialize\",\n \"initialized\",\n \"account/rateLimits/read\",\n \"account/read\",\n ]);\n expect(JSON.stringify(messages)).not.toMatch(/prompt|turn\\/start/);\n expect(CODEX_APP_SERVER_ARGS).toEqual([\n \"-s\",\n \"read-only\",\n \"-a\",\n \"untrusted\",\n \"app-server\",\n ]);\n });\n\n it(\"uses account/read to distinguish logged-out CLI state\", async () => {\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () => \"{}\",\n rpc: async () => ({ rateLimits: {}, account: { account: null } }),\n });\n expect(result).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n });\n });\n\n it(\"never exposes tokens or raw auth content through failures\", async () => {\n const secrets = [\n \"pat-secret-value\",\n \"oauth-secret-value\",\n \"refresh-secret-value\",\n ];\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: secrets[0],\n tokens: { access_token: secrets[1], refresh_token: secrets[2] },\n }),\n fetch: vi.fn().mockRejectedValue(new Error(secrets.join(\" \"))),\n rpc: async () => {\n throw new Error(secrets.join(\" \"));\n },\n });\n const output = JSON.stringify(result);\n for (const secret of secrets) expect(output).not.toContain(secret);\n });\n});\n"],"names":["describe","expect","it","vi","CODEX_APP_SERVER_ARGS","parseUsage","probeCodexCapacity","resolveCodexAuthPath","toRateWindow","checkedAt","context","installed","apiUsage","overrides","rate_limit","primary_window","used_percent","limit_window_seconds","reset_at","secondary_window","credits","balance","additional_rate_limits","limit_name","CODEX_HOME","HOME","toBe","toEqual","id","label","durationMinutes","usedPercent","resetsAt","toMatchObject","snapshot","source","creditsRemaining","windows","objectContaining","toBeNull","fetch","fn","mockResolvedValueOnce","Response","JSON","stringify","chatgpt_account_id","status","rpc","result","readFile","personal_access_token","tokens","access_token","account_id","toHaveBeenCalledTimes","mock","calls","headers","Authorization","not","toHaveBeenCalled","harness","provider","available","authenticated","map","window","mockResolvedValue","expires_at","now","Date","toHaveBeenCalledOnce","each","Object","assign","Error","code","name","rateLimits","primary","windowDurationMins","account","type","toHaveLength","mockRejectedValue","mockRejectedValueOnce","messages","message","method","toMatch","secrets","refresh_token","join","output","secret","toContain"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/capacity/codex.test.ts"],"sourcesContent":["import { describe, expect, it, vi } from \"vitest\";\nimport {\n CODEX_APP_SERVER_ARGS,\n parseUsage,\n probeCodexCapacity,\n} from \"../../capacity/sources/codex.js\";\nimport { resolveCodexAuthPath } from \"../../harnesses/codex/credentials.js\";\nimport { toRateWindow } from \"../../capacity/providers/openai-subscription.js\";\n\nconst checkedAt = \"2026-08-20T10:00:00.000Z\";\nconst context = { installed: true, checkedAt };\n\nfunction apiUsage(overrides: Record<string, unknown> = {}) {\n return {\n rate_limit: {\n primary_window: {\n used_percent: 20,\n limit_window_seconds: 18_000,\n reset_at: 1_787_220_000,\n },\n secondary_window: {\n used_percent: 60,\n limit_window_seconds: 604_800,\n reset_at: 1_787_824_800,\n },\n ...overrides,\n },\n credits: { balance: 12.5 },\n additional_rate_limits: [\n {\n limit_name: \"reviews\",\n rate_limit: {\n primary_window: {\n used_percent: 10,\n limit_window_seconds: 3_600,\n reset_at: 1_787_220_000,\n },\n },\n },\n ],\n };\n}\n\ndescribe(\"Codex auth resolution\", () => {\n it(\"uses CODEX_HOME before HOME\", () => {\n expect(\n resolveCodexAuthPath({\n CODEX_HOME: \"/custom/codex\",\n HOME: \"/users/test\",\n }),\n ).toBe(\"/custom/codex/auth.json\");\n });\n\n it(\"falls back to ~/.codex/auth.json\", () => {\n expect(resolveCodexAuthPath({ HOME: \"/users/test\" })).toBe(\"/users/test/.codex/auth.json\");\n });\n});\n\ndescribe(\"Codex API usage mapping\", () => {\n it(\"converts an API window without treating missing data as zero\", () => {\n expect(\n toRateWindow(\n {\n used_percent: 25,\n limit_window_seconds: 18_000,\n reset_at: 1_787_220_000,\n },\n \"session\",\n \"Session\",\n ),\n ).toEqual({\n id: \"session\",\n label: \"Session\",\n durationMinutes: 300,\n usedPercent: 25,\n resetsAt: \"2026-08-20T10:00:00.000Z\",\n });\n expect(toRateWindow({}, \"session\", \"Session\")).toMatchObject({\n usedPercent: null,\n });\n });\n\n it(\"maps session, weekly, credits, and extra limits\", () => {\n const snapshot = parseUsage(apiUsage(), \"pat\");\n expect(snapshot).toMatchObject({ source: \"pat\", creditsRemaining: 12.5 });\n expect(snapshot.windows).toEqual([\n expect.objectContaining({ id: \"session\", durationMinutes: 300 }),\n expect.objectContaining({ id: \"weekly\", durationMinutes: 10080 }),\n expect.objectContaining({ id: \"reviews:primary\", durationMinutes: 60 }),\n ]);\n });\n\n it(\"represents missing limits as unavailable rather than zero\", () => {\n const snapshot = parseUsage({ credits: {} }, \"oauth\");\n expect(snapshot.windows).toEqual([]);\n expect(snapshot.creditsRemaining).toBeNull();\n });\n});\n\ndescribe(\"tiered Codex probing\", () => {\n it(\"selects PAT, calls whoami then usage, and never invokes the CLI\", async () => {\n const fetch = vi\n .fn()\n .mockResolvedValueOnce(\n new Response(JSON.stringify({ chatgpt_account_id: \"acct-1\" }), {\n status: 200,\n }),\n )\n .mockResolvedValueOnce(new Response(JSON.stringify(apiUsage()), { status: 200 }));\n const rpc = vi.fn();\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: \"pat-secret\",\n tokens: {\n access_token: \"ignored-oauth\",\n account_id: \"ignored-account\",\n },\n }),\n fetch,\n rpc,\n });\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(fetch.mock.calls[0][0]).toBe(\n \"https://auth.openai.com/api/accounts/v1/user-auth-credential/whoami\",\n );\n expect(fetch.mock.calls[1][0]).toBe(\"https://chatgpt.com/backend-api/wham/usage\");\n expect(fetch.mock.calls[1][1].headers).toMatchObject({\n Authorization: \"Bearer pat-secret\",\n \"ChatGPT-Account-Id\": \"acct-1\",\n });\n expect(rpc).not.toHaveBeenCalled();\n expect(result).toMatchObject({\n harness: \"codex\",\n provider: \"openai\",\n available: \"yes\",\n creditsRemaining: 12.5,\n authenticated: true,\n });\n expect(result.windows.map((window) => window.id)).toEqual([\n \"session\",\n \"weekly\",\n \"reviews:primary\",\n ]);\n });\n\n it(\"selects a fresh OAuth token without calling whoami\", async () => {\n const fetch = vi\n .fn()\n .mockResolvedValue(new Response(JSON.stringify(apiUsage()), { status: 200 }));\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct-2\",\n expires_at: 1_800_000_000,\n },\n }),\n fetch,\n now: () => new Date(\"2026-08-20T10:00:00.000Z\"),\n });\n expect(fetch).toHaveBeenCalledOnce();\n expect(fetch.mock.calls[0][1].headers).toMatchObject({\n Authorization: \"Bearer oauth-secret\",\n \"ChatGPT-Account-Id\": \"acct-2\",\n });\n expect(result.available).toBe(\"yes\");\n });\n\n it.each([\n [\n \"missing auth file\",\n async () => {\n throw Object.assign(new Error(\"missing\"), { code: \"ENOENT\" });\n },\n ],\n [\n \"stale OAuth token\",\n async () =>\n JSON.stringify({\n tokens: {\n access_token: \"stale-secret\",\n account_id: \"acct\",\n expires_at: 1,\n },\n }),\n ],\n [\n \"OAuth 401\",\n async () =>\n JSON.stringify({\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct\",\n expires_at: 1_800_000_000,\n },\n }),\n ],\n ])(\"falls back to the CLI for %s\", async (name, readFile) => {\n const fetch = vi\n .fn()\n .mockResolvedValue(new Response(\"\", { status: name === \"OAuth 401\" ? 401 : 200 }));\n const rpc = vi.fn(async () => ({\n rateLimits: {\n rateLimits: {\n primary: { usedPercent: 5, windowDurationMins: 300, resetsAt: null },\n },\n },\n account: { account: { type: \"chatgpt\" } },\n }));\n const result = await probeCodexCapacity({\n ...context,\n readFile,\n fetch,\n rpc,\n now: () => new Date(checkedAt),\n });\n expect(rpc).toHaveBeenCalledOnce();\n expect(result.windows).toHaveLength(1);\n });\n\n it(\"falls back to CLI if PAT requests fail\", async () => {\n const rpc = vi.fn(async () => ({\n rateLimits: {},\n account: { account: null },\n }));\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () => JSON.stringify({ personal_access_token: \"pat-secret\" }),\n fetch: vi.fn().mockRejectedValue(new Error(\"network failure pat-secret\")),\n rpc,\n });\n expect(rpc).toHaveBeenCalledOnce();\n expect(result.available).toBe(\"unknown\");\n });\n\n it(\"tries fresh OAuth after a PAT request fails\", async () => {\n const fetch = vi\n .fn()\n .mockRejectedValueOnce(new Error(\"PAT failed\"))\n .mockResolvedValueOnce(new Response(JSON.stringify(apiUsage()), { status: 200 }));\n const rpc = vi.fn();\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: \"pat-secret\",\n tokens: {\n access_token: \"oauth-secret\",\n account_id: \"acct\",\n expires_at: 1_800_000_000,\n },\n }),\n fetch,\n rpc,\n now: () => new Date(checkedAt),\n });\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(result.available).toBe(\"yes\");\n expect(rpc).not.toHaveBeenCalled();\n });\n\n it(\"uses hardened read-only app-server arguments and both account methods\", async () => {\n const rpc = vi.fn(async () => ({\n rateLimits: {\n rateLimits: {\n primary: { usedPercent: 5, windowDurationMins: 300, resetsAt: null },\n },\n },\n account: { account: { type: \"chatgpt\" } },\n }));\n await probeCodexCapacity({ ...context, readFile: async () => \"{}\", rpc });\n const messages = rpc.mock.calls[0][0];\n expect(messages.map((message) => message.method)).toEqual([\n \"initialize\",\n \"initialized\",\n \"account/rateLimits/read\",\n \"account/read\",\n ]);\n expect(JSON.stringify(messages)).not.toMatch(/prompt|turn\\/start/);\n expect(CODEX_APP_SERVER_ARGS).toEqual([\"-s\", \"read-only\", \"-a\", \"untrusted\", \"app-server\"]);\n });\n\n it(\"uses account/read to distinguish logged-out CLI state\", async () => {\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () => \"{}\",\n rpc: async () => ({ rateLimits: {}, account: { account: null } }),\n });\n expect(result).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n });\n });\n\n it(\"never exposes tokens or raw auth content through failures\", async () => {\n const secrets = [\"pat-secret-value\", \"oauth-secret-value\", \"refresh-secret-value\"];\n const result = await probeCodexCapacity({\n ...context,\n readFile: async () =>\n JSON.stringify({\n personal_access_token: secrets[0],\n tokens: { access_token: secrets[1], refresh_token: secrets[2] },\n }),\n fetch: vi.fn().mockRejectedValue(new Error(secrets.join(\" \"))),\n rpc: async () => {\n throw new Error(secrets.join(\" \"));\n },\n });\n const output = JSON.stringify(result);\n for (const secret of secrets) expect(output).not.toContain(secret);\n });\n});\n"],"names":["describe","expect","it","vi","CODEX_APP_SERVER_ARGS","parseUsage","probeCodexCapacity","resolveCodexAuthPath","toRateWindow","checkedAt","context","installed","apiUsage","overrides","rate_limit","primary_window","used_percent","limit_window_seconds","reset_at","secondary_window","credits","balance","additional_rate_limits","limit_name","CODEX_HOME","HOME","toBe","toEqual","id","label","durationMinutes","usedPercent","resetsAt","toMatchObject","snapshot","source","creditsRemaining","windows","objectContaining","toBeNull","fetch","fn","mockResolvedValueOnce","Response","JSON","stringify","chatgpt_account_id","status","rpc","result","readFile","personal_access_token","tokens","access_token","account_id","toHaveBeenCalledTimes","mock","calls","headers","Authorization","not","toHaveBeenCalled","harness","provider","available","authenticated","map","window","mockResolvedValue","expires_at","now","Date","toHaveBeenCalledOnce","each","Object","assign","Error","code","name","rateLimits","primary","windowDurationMins","account","type","toHaveLength","mockRejectedValue","mockRejectedValueOnce","messages","message","method","toMatch","secrets","refresh_token","join","output","secret","toContain"],"mappings":"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"}
|
|
@@ -2,29 +2,43 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { describe, expect, it, vi } from "vitest";
|
|
5
|
-
import {
|
|
5
|
+
import { probeOpenAiCapacity } from "../../capacity/sources/pi.js";
|
|
6
|
+
import { buildOpenAiPlatformCapacity, parseOpenAiUsage } from "../../capacity/providers/openai-platform.js";
|
|
7
|
+
import { resolvePiOpenAiCredential as resolveOpenAiCredential } from "../../harnesses/pi/credentials.js";
|
|
6
8
|
const checkedAt = "2026-09-26T10:00:00.000Z";
|
|
9
|
+
const fixtureOauthAccess = "sample access value for tests";
|
|
10
|
+
const fakeJwt = (payload)=>[
|
|
11
|
+
"test",
|
|
12
|
+
Buffer.from(payload).toString("base64url"),
|
|
13
|
+
"test"
|
|
14
|
+
].join(".");
|
|
7
15
|
const fixture = (name)=>readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
|
|
8
16
|
const fixtureString = (name)=>readFileSync(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
|
|
9
17
|
describe("OpenAI credential resolution", ()=>{
|
|
10
18
|
it("prefers OPENAI_API_KEY without reading Pi auth", async ()=>{
|
|
11
19
|
const readAuth = vi.fn(async ()=>fixture("openai-auth.json"));
|
|
12
|
-
await expect(
|
|
20
|
+
await expect(resolveOpenAiCredential({
|
|
13
21
|
env: {
|
|
14
22
|
OPENAI_API_KEY: "env-openai-test-key"
|
|
15
23
|
},
|
|
16
24
|
readFile: readAuth
|
|
17
|
-
})).resolves.
|
|
25
|
+
})).resolves.toEqual({
|
|
26
|
+
kind: "platform",
|
|
27
|
+
key: "env-openai-test-key"
|
|
28
|
+
});
|
|
18
29
|
expect(readAuth).not.toHaveBeenCalled();
|
|
19
30
|
});
|
|
20
31
|
it("reads the Pi openai api_key credential from ~/.pi/agent/auth.json", async ()=>{
|
|
21
32
|
const readAuth = vi.fn(async ()=>fixture("openai-auth.json"));
|
|
22
|
-
await expect(
|
|
33
|
+
await expect(resolveOpenAiCredential({
|
|
23
34
|
env: {
|
|
24
35
|
HOME: "/users/test"
|
|
25
36
|
},
|
|
26
37
|
readFile: readAuth
|
|
27
|
-
})).resolves.
|
|
38
|
+
})).resolves.toEqual({
|
|
39
|
+
kind: "platform",
|
|
40
|
+
key: "pi-openai-test-key"
|
|
41
|
+
});
|
|
28
42
|
expect(readAuth).toHaveBeenCalledWith("/users/test/.pi/agent/auth.json", "utf8");
|
|
29
43
|
});
|
|
30
44
|
it.each([
|
|
@@ -56,7 +70,7 @@ describe("OpenAI credential resolution", ()=>{
|
|
|
56
70
|
})
|
|
57
71
|
]
|
|
58
72
|
])("fails clearly for %s credentials without exposing file content", async (_name, readAuth)=>{
|
|
59
|
-
await expect(
|
|
73
|
+
await expect(resolveOpenAiCredential({
|
|
60
74
|
env: {
|
|
61
75
|
HOME: "/users/test"
|
|
62
76
|
},
|
|
@@ -73,7 +87,7 @@ describe("OpenAI tiered credential resolution", ()=>{
|
|
|
73
87
|
},
|
|
74
88
|
"openai-codex": {
|
|
75
89
|
type: "oauth",
|
|
76
|
-
access:
|
|
90
|
+
access: fixtureOauthAccess,
|
|
77
91
|
refresh: "fixture-refresh-token",
|
|
78
92
|
expires: 1793000000000,
|
|
79
93
|
accountId: "fixture-chatgpt-account-id"
|
|
@@ -98,7 +112,7 @@ describe("OpenAI tiered credential resolution", ()=>{
|
|
|
98
112
|
readFile: async ()=>oauthFixture()
|
|
99
113
|
})).resolves.toEqual({
|
|
100
114
|
kind: "oauth",
|
|
101
|
-
access:
|
|
115
|
+
access: fixtureOauthAccess,
|
|
102
116
|
accountId: "fixture-chatgpt-account-id",
|
|
103
117
|
expiresMs: 1793000000000
|
|
104
118
|
});
|
|
@@ -177,14 +191,6 @@ describe("OpenAI tiered credential resolution", ()=>{
|
|
|
177
191
|
readFile: async ()=>auth
|
|
178
192
|
})).rejects.toThrow("OpenAI credentials not found");
|
|
179
193
|
});
|
|
180
|
-
it("still throws for OAuth-only machines on the legacy platform-key resolver", async ()=>{
|
|
181
|
-
await expect(resolveOpenAiApiKey({
|
|
182
|
-
env: {
|
|
183
|
-
HOME: "/users/test"
|
|
184
|
-
},
|
|
185
|
-
readFile: async ()=>oauthFixture()
|
|
186
|
-
})).rejects.toThrow("OpenAI credentials not found");
|
|
187
|
-
});
|
|
188
194
|
});
|
|
189
195
|
describe("OpenAI OAuth capacity probe", ()=>{
|
|
190
196
|
const freshOauth = ()=>fixture("openai-codex-auth.json");
|
|
@@ -204,7 +210,7 @@ describe("OpenAI OAuth capacity probe", ()=>{
|
|
|
204
210
|
expect(fetch).toHaveBeenCalledWith("https://chatgpt.com/backend-api/wham/usage", expect.objectContaining({
|
|
205
211
|
method: "GET",
|
|
206
212
|
headers: {
|
|
207
|
-
Authorization:
|
|
213
|
+
Authorization: `Bearer ${fixtureOauthAccess}`,
|
|
208
214
|
"ChatGPT-Account-Id": "fixture-chatgpt-account-id"
|
|
209
215
|
}
|
|
210
216
|
}));
|
|
@@ -276,7 +282,9 @@ describe("OpenAI OAuth capacity probe", ()=>{
|
|
|
276
282
|
const expiredJwtAuth = JSON.stringify({
|
|
277
283
|
"openai-codex": {
|
|
278
284
|
type: "oauth",
|
|
279
|
-
access:
|
|
285
|
+
access: fakeJwt(JSON.stringify({
|
|
286
|
+
exp: 1789000000
|
|
287
|
+
})),
|
|
280
288
|
accountId: "fixture-chatgpt-account-id"
|
|
281
289
|
}
|
|
282
290
|
});
|
|
@@ -296,7 +304,9 @@ describe("OpenAI OAuth capacity probe", ()=>{
|
|
|
296
304
|
const futureJwtAuth = JSON.stringify({
|
|
297
305
|
"openai-codex": {
|
|
298
306
|
type: "oauth",
|
|
299
|
-
access:
|
|
307
|
+
access: fakeJwt(JSON.stringify({
|
|
308
|
+
exp: 1793000000
|
|
309
|
+
})),
|
|
300
310
|
accountId: "fixture-chatgpt-account-id"
|
|
301
311
|
}
|
|
302
312
|
});
|
|
@@ -318,7 +328,7 @@ describe("OpenAI OAuth capacity probe", ()=>{
|
|
|
318
328
|
const auth = JSON.stringify({
|
|
319
329
|
"openai-codex": {
|
|
320
330
|
type: "oauth",
|
|
321
|
-
access: "
|
|
331
|
+
access: fakeJwt("not-json"),
|
|
322
332
|
accountId: "fixture-chatgpt-account-id"
|
|
323
333
|
}
|
|
324
334
|
});
|
|
@@ -494,11 +504,8 @@ describe("OpenAI usage mapping", ()=>{
|
|
|
494
504
|
...parseOpenAiUsage(JSON.parse(await fixture("openai-usage-completions.json"))),
|
|
495
505
|
...parseOpenAiUsage(JSON.parse(await fixture("openai-usage-responses.json")))
|
|
496
506
|
];
|
|
497
|
-
const report =
|
|
507
|
+
const report = buildOpenAiPlatformCapacity(buckets, checkedAt);
|
|
498
508
|
expect(report).toMatchObject({
|
|
499
|
-
harness: "pi",
|
|
500
|
-
provider: "openai",
|
|
501
|
-
generatedAt: checkedAt,
|
|
502
509
|
authenticated: true,
|
|
503
510
|
available: "yes",
|
|
504
511
|
creditsRemaining: null
|
|
@@ -529,7 +536,7 @@ describe("OpenAI usage mapping", ()=>{
|
|
|
529
536
|
]);
|
|
530
537
|
});
|
|
531
538
|
it("reports zero usage for days without buckets", ()=>{
|
|
532
|
-
const report =
|
|
539
|
+
const report = buildOpenAiPlatformCapacity([], checkedAt);
|
|
533
540
|
expect(report.windows.map((window)=>window.current)).toEqual([
|
|
534
541
|
0,
|
|
535
542
|
0
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/capacity/openai.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport {\n buildOpenAiReport,\n parseOpenAiUsage,\n probeOpenAiCapacity,\n resolveOpenAiApiKey,\n resolveOpenAiCredential,\n} from \"../../capacity/openai.js\";\n\nconst checkedAt = \"2026-09-26T10:00:00.000Z\";\nconst fixture = (name: string) =>\n readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\nconst fixtureString = (name: string) =>\n readFileSync(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\n\ndescribe(\"OpenAI credential resolution\", () => {\n it(\"prefers OPENAI_API_KEY without reading Pi auth\", async () => {\n const readAuth = vi.fn(async () => fixture(\"openai-auth.json\"));\n await expect(\n resolveOpenAiApiKey({\n env: { OPENAI_API_KEY: \"env-openai-test-key\" },\n readFile: readAuth,\n }),\n ).resolves.toBe(\"env-openai-test-key\");\n expect(readAuth).not.toHaveBeenCalled();\n });\n\n it(\"reads the Pi openai api_key credential from ~/.pi/agent/auth.json\", async () => {\n const readAuth = vi.fn(async () => fixture(\"openai-auth.json\"));\n await expect(\n resolveOpenAiApiKey({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).resolves.toBe(\"pi-openai-test-key\");\n expect(readAuth).toHaveBeenCalledWith(\"/users/test/.pi/agent/auth.json\", \"utf8\");\n });\n\n it.each([\n [\n \"missing\",\n async () => Promise.reject(Object.assign(new Error(\"missing\"), { code: \"ENOENT\" })),\n ],\n [\"invalid JSON\", async () => \"{\"],\n [\"wrong credential type\", async () => JSON.stringify({ openai: { type: \"oauth\", key: \"x\" } })],\n [\"missing key\", async () => JSON.stringify({ openai: { type: \"api_key\" } })],\n ])(\"fails clearly for %s credentials without exposing file content\", async (_name, readAuth) => {\n await expect(\n resolveOpenAiApiKey({\n env: { HOME: \"/users/test\" },\n readFile: readAuth,\n }),\n ).rejects.toThrow(/OpenAI credentials not found|OpenAI Pi auth file/);\n });\n});\n\ndescribe(\"OpenAI tiered credential resolution\", () => {\n const oauthFixture = () => fixture(\"openai-codex-auth.json\");\n const bothCredentials = JSON.stringify({\n openai: { type: \"api_key\", key: \"pi-openai-test-key\" },\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature\",\n refresh: \"fixture-refresh-token\",\n expires: 1793000000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n\n it(\"prefers the Pi openai platform credential over the openai-codex OAuth login\", async () => {\n await expect(\n resolveOpenAiCredential({\n env: { HOME: \"/users/test\" },\n readFile: async () => bothCredentials,\n }),\n ).resolves.toEqual({ kind: \"platform\", key: \"pi-openai-test-key\" });\n });\n\n it(\"resolves the Pi openai-codex OAuth login when no platform credential exists\", async () => {\n await expect(\n resolveOpenAiCredential({\n env: { HOME: \"/users/test\" },\n readFile: async () => oauthFixture(),\n }),\n ).resolves.toEqual({\n kind: \"oauth\",\n access: \"fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature\",\n accountId: \"fixture-chatgpt-account-id\",\n expiresMs: 1793000000000,\n });\n });\n\n it(\"normalizes second-based expires values to epoch milliseconds\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-access\",\n refresh: \"fixture-refresh\",\n expires: 1793000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).resolves.toMatchObject({ kind: \"oauth\", expiresMs: 1793000000000 });\n });\n\n it(\"keeps a null expiry for OAuth logins without usable expires metadata\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-access\",\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).resolves.toMatchObject({ kind: \"oauth\", expiresMs: null });\n });\n\n it.each([\n [\"wrong credential type\", JSON.stringify({ \"openai-codex\": { type: \"api_key\", key: \"x\" } })],\n [\"missing access token\", JSON.stringify({ \"openai-codex\": { type: \"oauth\", accountId: \"a\" } })],\n [\"missing account id\", JSON.stringify({ \"openai-codex\": { type: \"oauth\", access: \"t\" } })],\n ])(\n \"skips a malformed openai-codex credential (%s) with a sanitized error\",\n async (_name, auth) => {\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).rejects.toThrow(\"OpenAI credentials not found\");\n },\n );\n\n it(\"still throws for OAuth-only machines on the legacy platform-key resolver\", async () => {\n await expect(\n resolveOpenAiApiKey({\n env: { HOME: \"/users/test\" },\n readFile: async () => oauthFixture(),\n }),\n ).rejects.toThrow(\"OpenAI credentials not found\");\n });\n});\n\ndescribe(\"OpenAI OAuth capacity probe\", () => {\n const freshOauth = () => fixture(\"openai-codex-auth.json\");\n const whamResponse = () => new Response(fixtureString(\"wham-usage.json\"), { status: 200 });\n\n it(\"reports wham usage windows for a fresh Pi OAuth login\", async () => {\n const fetch = vi.fn(async () => whamResponse());\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://chatgpt.com/backend-api/wham/usage\",\n expect.objectContaining({\n method: \"GET\",\n headers: {\n Authorization: \"Bearer fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature\",\n \"ChatGPT-Account-Id\": \"fixture-chatgpt-account-id\",\n },\n }),\n );\n expect(report).toMatchObject({\n harness: \"pi\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"yes\",\n creditsRemaining: 4.5,\n });\n expect(report.windows.map((window) => window.id)).toEqual([\"session\", \"weekly\"]);\n expect(JSON.stringify(report)).not.toContain(\"fixture-signature\");\n });\n\n it(\"does not fetch and reports an authenticated-but-stale state for expired logins\", async () => {\n const staleAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"stale-fixture-access\",\n expires: 1790000000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn();\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => staleAuth,\n fetch,\n });\n expect(fetch).not.toHaveBeenCalled();\n expect(report).toEqual({\n harness: \"pi\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n });\n\n it(\"treats second-based expiry metadata as stale the same way\", async () => {\n const staleAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"stale-fixture-access\",\n expires: 1790000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn();\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => staleAuth,\n fetch,\n });\n expect(fetch).not.toHaveBeenCalled();\n expect(report.available).toBe(\"unknown\");\n });\n\n it(\"falls back to the JWT exp when expires metadata is missing\", async () => {\n const expiredJwtAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"h.eyJleHAiOjE3ODkwMDAwMDB9.s\",\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const noFetch = vi.fn();\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => expiredJwtAuth,\n fetch: noFetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"unknown\" });\n expect(noFetch).not.toHaveBeenCalled();\n\n const futureJwtAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"h.eyJleHAiOjE3OTMwMDAwMDB9.s\",\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => futureJwtAuth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n });\n\n it(\"treats unparseable JWT payloads as unknown expiry and probes anyway\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-header.bm90LWpzb24.fixture-signature\",\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => auth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n });\n\n it(\"treats non-JWT and exp-less access tokens as unknown expiry and probes anyway\", async () => {\n for (const access of [\"opaque-fixture-access\", \"h.eyJzdWIiOiJ4In0.s\"]) {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => auth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n }\n });\n\n it(\"reports unknown availability when wham returns no usable windows\", async () => {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: vi.fn(async () => new Response(\"{}\", { status: 200 })),\n });\n expect(report).toMatchObject({ authenticated: true, available: \"unknown\", windows: [] });\n });\n\n it(\"reports unauthenticated when wham rejects the OAuth token\", async () => {\n for (const status of [401, 403]) {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: vi.fn(async () => new Response(\"denied\", { status })),\n });\n expect(report).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n }\n });\n\n it(\"throws sanitized errors for transport failures without leaking tokens\", async () => {\n const probe = (fetch: unknown) =>\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: fetch as typeof globalThis.fetch,\n timeoutMs: 10,\n });\n await expect(\n probe(\n (_url: string, init: RequestInit) =>\n new Promise((_resolve, reject) =>\n init.signal?.addEventListener(\"abort\", () => reject(new Error(\"aborted\"))),\n ),\n ),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n await expect(probe(vi.fn(async () => new Response(\"boom\", { status: 503 })))).rejects.toThrow(\n \"OpenAI usage request failed: HTTP 503\",\n );\n await expect(\n probe(vi.fn(async () => new Response(\"not-json\", { status: 200 }))),\n ).rejects.toThrow(\"OpenAI usage response is not valid JSON\");\n try {\n await probe(vi.fn(async () => new Response(\"boom\", { status: 503 })));\n } catch (error) {\n expect(String(error)).not.toContain(\"fixture-signature\");\n expect(String(error)).not.toContain(\"fixture-chatgpt-account-id\");\n }\n });\n});\n\ndescribe(\"OpenAI usage mapping\", () => {\n it(\"sums per-model input and output tokens into UTC day buckets\", async () => {\n const buckets = parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-completions.json\")));\n expect(buckets).toEqual([\n { startMs: 1790380800000, tokens: 2000 },\n { startMs: 1790294400000, tokens: 5000 },\n { startMs: 1789862400000, tokens: 1000 },\n { startMs: 1789689600000, tokens: 19998 },\n ]);\n });\n\n it(\"keeps empty buckets and skips entries it cannot place in time\", () => {\n expect(\n parseOpenAiUsage({\n object: \"list\",\n data: [\n null,\n 42,\n { aggregation_timestamp: 1790380800 },\n { aggregation_timestamp: \"yesterday\", results: [] },\n { aggregation_timestamp: 1790294400, results: null },\n ],\n }),\n ).toEqual([\n { startMs: 1790380800000, tokens: 0 },\n { startMs: 1790294400000, tokens: 0 },\n ]);\n });\n\n it(\"rejects responses without a usage data array\", () => {\n expect(() => parseOpenAiUsage({ object: \"list\" })).toThrow(\"Invalid OpenAI usage response\");\n expect(() => parseOpenAiUsage({ data: {} })).toThrow(\"Invalid OpenAI usage response\");\n });\n\n it(\"builds today and 7-day windows without faked limits\", async () => {\n const buckets = [\n ...parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-completions.json\"))),\n ...parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-responses.json\"))),\n ];\n const report = buildOpenAiReport(buckets, checkedAt);\n expect(report).toMatchObject({\n harness: \"pi\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"yes\",\n creditsRemaining: null,\n });\n expect(report.windows).toEqual([\n {\n id: \"openai:tokens:today\",\n label: \"Tokens · today (UTC)\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 1440,\n usedPercent: null,\n resetsAt: \"2026-09-27T00:00:00.000Z\",\n total: null,\n current: 2000,\n remaining: null,\n },\n {\n id: \"openai:tokens:week\",\n label: \"Tokens · 7 days\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 10080,\n usedPercent: null,\n resetsAt: null,\n total: null,\n current: 13000,\n remaining: null,\n },\n ]);\n });\n\n it(\"reports zero usage for days without buckets\", () => {\n const report = buildOpenAiReport([], checkedAt);\n expect(report.windows.map((window) => window.current)).toEqual([0, 0]);\n expect(report.windows[0].resetsAt).toBe(\"2026-09-27T00:00:00.000Z\");\n });\n});\n\ndescribe(\"OpenAI request\", () => {\n it(\"GETs both usage endpoints for the trailing week with only Bearer authentication\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.includes(\"/responses?\")\n ? new Response(await fixture(\"openai-usage-responses.json\"), {\n status: 200,\n })\n : new Response(await fixture(\"openai-usage-completions.json\"), {\n status: 200,\n }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"request-test-key\" },\n fetch,\n });\n const query = \"start_time=1789812000&end_time=1790416800\";\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(fetch).toHaveBeenCalledWith(\n `https://api.openai.com/v1/organization/usage/completions?${query}`,\n expect.objectContaining({\n method: \"GET\",\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(fetch).toHaveBeenCalledWith(\n `https://api.openai.com/v1/organization/usage/responses?${query}`,\n expect.objectContaining({\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(report.windows.map((window) => window.current)).toEqual([2000, 13000]);\n expect(JSON.stringify(report)).not.toContain(\"request-test-key\");\n });\n\n it(\"reports unauthenticated for rejected keys\", async () => {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"rejected-key\" },\n fetch: vi.fn(async () => new Response(\"denied\", { status: 401 })),\n });\n expect(report).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n });\n\n it(\"degrades to authentication-only when usage requires an admin key\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? new Response(\"{}\", { status: 200 })\n : new Response(\"forbidden\", { status: 403 }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"member-key\" },\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://api.openai.com/v1/models\",\n expect.objectContaining({\n headers: { Authorization: \"Bearer member-key\" },\n }),\n );\n expect(report).toMatchObject({\n authenticated: true,\n available: \"unknown\",\n windows: [],\n });\n });\n\n it(\"falls back to unauthenticated when the degraded check rejects the key\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? new Response(\"denied\", { status: 401 })\n : new Response(\"forbidden\", { status: 403 }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"revoked-key\" },\n fetch,\n });\n expect(report).toMatchObject({ authenticated: false, windows: [] });\n });\n\n it(\"sanitizes network failures on the platform key path\", async () => {\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"network-key\" },\n fetch: vi.fn(async () => Promise.reject(new Error(\"ECONNRESET secret\"))),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"network-key\" },\n fetch: vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? Promise.reject(new Error(\"ECONNRESET secret\"))\n : new Response(\"forbidden\", { status: 403 }),\n ),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n });\n\n it(\"rejects other statuses and malformed JSON responses with sanitized errors\", async () => {\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"private body\", { status: 503 })),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed: HTTP 503\");\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"not-json\", { status: 200 })),\n }),\n ).rejects.toThrow(\"OpenAI usage response is not valid JSON\");\n });\n});\n"],"names":["readFile","readFileSync","fileURLToPath","describe","expect","it","vi","buildOpenAiReport","parseOpenAiUsage","probeOpenAiCapacity","resolveOpenAiApiKey","resolveOpenAiCredential","checkedAt","fixture","name","URL","url","fixtureString","readAuth","fn","env","OPENAI_API_KEY","resolves","toBe","not","toHaveBeenCalled","HOME","toHaveBeenCalledWith","each","Promise","reject","Object","assign","Error","code","JSON","stringify","openai","type","key","_name","rejects","toThrow","oauthFixture","bothCredentials","access","refresh","expires","accountId","toEqual","kind","expiresMs","auth","toMatchObject","freshOauth","whamResponse","Response","status","fetch","report","objectContaining","method","headers","Authorization","harness","provider","generatedAt","authenticated","available","creditsRemaining","windows","map","window","id","toContain","staleAuth","expiredJwtAuth","noFetch","futureJwtAuth","toHaveBeenCalledOnce","probe","timeoutMs","_url","init","_resolve","signal","addEventListener","error","String","buckets","parse","startMs","tokens","object","data","aggregation_timestamp","results","label","limitType","durationMinutes","usedPercent","resetsAt","total","current","remaining","includes","query","toHaveBeenCalledTimes","endsWith"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/capacity/openai.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { probeOpenAiCapacity } from \"../../capacity/sources/pi.js\";\nimport {\n buildOpenAiPlatformCapacity,\n parseOpenAiUsage,\n} from \"../../capacity/providers/openai-platform.js\";\nimport { resolvePiOpenAiCredential as resolveOpenAiCredential } from \"../../harnesses/pi/credentials.js\";\n\nconst checkedAt = \"2026-09-26T10:00:00.000Z\";\nconst fixtureOauthAccess = \"sample access value for tests\";\nconst fakeJwt = (payload: string) =>\n [\"test\", Buffer.from(payload).toString(\"base64url\"), \"test\"].join(\".\");\nconst fixture = (name: string) =>\n readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\nconst fixtureString = (name: string) =>\n readFileSync(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\n\ndescribe(\"OpenAI credential resolution\", () => {\n it(\"prefers OPENAI_API_KEY without reading Pi auth\", async () => {\n const readAuth = vi.fn(async () => fixture(\"openai-auth.json\"));\n await expect(\n resolveOpenAiCredential({\n env: { OPENAI_API_KEY: \"env-openai-test-key\" },\n readFile: readAuth,\n }),\n ).resolves.toEqual({ kind: \"platform\", key: \"env-openai-test-key\" });\n expect(readAuth).not.toHaveBeenCalled();\n });\n\n it(\"reads the Pi openai api_key credential from ~/.pi/agent/auth.json\", async () => {\n const readAuth = vi.fn(async () => fixture(\"openai-auth.json\"));\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).resolves.toEqual({ kind: \"platform\", key: \"pi-openai-test-key\" });\n expect(readAuth).toHaveBeenCalledWith(\"/users/test/.pi/agent/auth.json\", \"utf8\");\n });\n\n it.each([\n [\n \"missing\",\n async () => Promise.reject(Object.assign(new Error(\"missing\"), { code: \"ENOENT\" })),\n ],\n [\"invalid JSON\", async () => \"{\"],\n [\"wrong credential type\", async () => JSON.stringify({ openai: { type: \"oauth\", key: \"x\" } })],\n [\"missing key\", async () => JSON.stringify({ openai: { type: \"api_key\" } })],\n ])(\"fails clearly for %s credentials without exposing file content\", async (_name, readAuth) => {\n await expect(\n resolveOpenAiCredential({\n env: { HOME: \"/users/test\" },\n readFile: readAuth,\n }),\n ).rejects.toThrow(/OpenAI credentials not found|OpenAI Pi auth file/);\n });\n});\n\ndescribe(\"OpenAI tiered credential resolution\", () => {\n const oauthFixture = () => fixture(\"openai-codex-auth.json\");\n const bothCredentials = JSON.stringify({\n openai: { type: \"api_key\", key: \"pi-openai-test-key\" },\n \"openai-codex\": {\n type: \"oauth\",\n access: fixtureOauthAccess,\n refresh: \"fixture-refresh-token\",\n expires: 1793000000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n\n it(\"prefers the Pi openai platform credential over the openai-codex OAuth login\", async () => {\n await expect(\n resolveOpenAiCredential({\n env: { HOME: \"/users/test\" },\n readFile: async () => bothCredentials,\n }),\n ).resolves.toEqual({ kind: \"platform\", key: \"pi-openai-test-key\" });\n });\n\n it(\"resolves the Pi openai-codex OAuth login when no platform credential exists\", async () => {\n await expect(\n resolveOpenAiCredential({\n env: { HOME: \"/users/test\" },\n readFile: async () => oauthFixture(),\n }),\n ).resolves.toEqual({\n kind: \"oauth\",\n access: fixtureOauthAccess,\n accountId: \"fixture-chatgpt-account-id\",\n expiresMs: 1793000000000,\n });\n });\n\n it(\"normalizes second-based expires values to epoch milliseconds\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-access\",\n refresh: \"fixture-refresh\",\n expires: 1793000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).resolves.toMatchObject({ kind: \"oauth\", expiresMs: 1793000000000 });\n });\n\n it(\"keeps a null expiry for OAuth logins without usable expires metadata\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"fixture-access\",\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).resolves.toMatchObject({ kind: \"oauth\", expiresMs: null });\n });\n\n it.each([\n [\"wrong credential type\", JSON.stringify({ \"openai-codex\": { type: \"api_key\", key: \"x\" } })],\n [\"missing access token\", JSON.stringify({ \"openai-codex\": { type: \"oauth\", accountId: \"a\" } })],\n [\"missing account id\", JSON.stringify({ \"openai-codex\": { type: \"oauth\", access: \"t\" } })],\n ])(\n \"skips a malformed openai-codex credential (%s) with a sanitized error\",\n async (_name, auth) => {\n await expect(\n resolveOpenAiCredential({ env: { HOME: \"/users/test\" }, readFile: async () => auth }),\n ).rejects.toThrow(\"OpenAI credentials not found\");\n },\n );\n});\n\ndescribe(\"OpenAI OAuth capacity probe\", () => {\n const freshOauth = () => fixture(\"openai-codex-auth.json\");\n const whamResponse = () => new Response(fixtureString(\"wham-usage.json\"), { status: 200 });\n\n it(\"reports wham usage windows for a fresh Pi OAuth login\", async () => {\n const fetch = vi.fn(async () => whamResponse());\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://chatgpt.com/backend-api/wham/usage\",\n expect.objectContaining({\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${fixtureOauthAccess}`,\n \"ChatGPT-Account-Id\": \"fixture-chatgpt-account-id\",\n },\n }),\n );\n expect(report).toMatchObject({\n harness: \"pi\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"yes\",\n creditsRemaining: 4.5,\n });\n expect(report.windows.map((window) => window.id)).toEqual([\"session\", \"weekly\"]);\n expect(JSON.stringify(report)).not.toContain(\"fixture-signature\");\n });\n\n it(\"does not fetch and reports an authenticated-but-stale state for expired logins\", async () => {\n const staleAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"stale-fixture-access\",\n expires: 1790000000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn();\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => staleAuth,\n fetch,\n });\n expect(fetch).not.toHaveBeenCalled();\n expect(report).toEqual({\n harness: \"pi\",\n provider: \"openai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n });\n\n it(\"treats second-based expiry metadata as stale the same way\", async () => {\n const staleAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: \"stale-fixture-access\",\n expires: 1790000000,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn();\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => staleAuth,\n fetch,\n });\n expect(fetch).not.toHaveBeenCalled();\n expect(report.available).toBe(\"unknown\");\n });\n\n it(\"falls back to the JWT exp when expires metadata is missing\", async () => {\n const expiredJwtAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: fakeJwt(JSON.stringify({ exp: 1789000000 })),\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const noFetch = vi.fn();\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => expiredJwtAuth,\n fetch: noFetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"unknown\" });\n expect(noFetch).not.toHaveBeenCalled();\n\n const futureJwtAuth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: fakeJwt(JSON.stringify({ exp: 1793000000 })),\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => futureJwtAuth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n });\n\n it(\"treats unparseable JWT payloads as unknown expiry and probes anyway\", async () => {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access: fakeJwt(\"not-json\"),\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => auth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n });\n\n it(\"treats non-JWT and exp-less access tokens as unknown expiry and probes anyway\", async () => {\n for (const access of [\"opaque-fixture-access\", \"h.eyJzdWIiOiJ4In0.s\"]) {\n const auth = JSON.stringify({\n \"openai-codex\": {\n type: \"oauth\",\n access,\n accountId: \"fixture-chatgpt-account-id\",\n },\n });\n const fetch = vi.fn(async () => whamResponse());\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => auth,\n fetch,\n }),\n ).resolves.toMatchObject({ authenticated: true, available: \"yes\" });\n expect(fetch).toHaveBeenCalledOnce();\n }\n });\n\n it(\"reports unknown availability when wham returns no usable windows\", async () => {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: vi.fn(async () => new Response(\"{}\", { status: 200 })),\n });\n expect(report).toMatchObject({ authenticated: true, available: \"unknown\", windows: [] });\n });\n\n it(\"reports unauthenticated when wham rejects the OAuth token\", async () => {\n for (const status of [401, 403]) {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: vi.fn(async () => new Response(\"denied\", { status })),\n });\n expect(report).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n }\n });\n\n it(\"throws sanitized errors for transport failures without leaking tokens\", async () => {\n const probe = (fetch: unknown) =>\n probeOpenAiCapacity({\n checkedAt,\n env: { HOME: \"/users/test\" },\n readFile: async () => freshOauth(),\n fetch: fetch as typeof globalThis.fetch,\n timeoutMs: 10,\n });\n await expect(\n probe(\n (_url: string, init: RequestInit) =>\n new Promise((_resolve, reject) =>\n init.signal?.addEventListener(\"abort\", () => reject(new Error(\"aborted\"))),\n ),\n ),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n await expect(probe(vi.fn(async () => new Response(\"boom\", { status: 503 })))).rejects.toThrow(\n \"OpenAI usage request failed: HTTP 503\",\n );\n await expect(\n probe(vi.fn(async () => new Response(\"not-json\", { status: 200 }))),\n ).rejects.toThrow(\"OpenAI usage response is not valid JSON\");\n try {\n await probe(vi.fn(async () => new Response(\"boom\", { status: 503 })));\n } catch (error) {\n expect(String(error)).not.toContain(\"fixture-signature\");\n expect(String(error)).not.toContain(\"fixture-chatgpt-account-id\");\n }\n });\n});\n\ndescribe(\"OpenAI usage mapping\", () => {\n it(\"sums per-model input and output tokens into UTC day buckets\", async () => {\n const buckets = parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-completions.json\")));\n expect(buckets).toEqual([\n { startMs: 1790380800000, tokens: 2000 },\n { startMs: 1790294400000, tokens: 5000 },\n { startMs: 1789862400000, tokens: 1000 },\n { startMs: 1789689600000, tokens: 19998 },\n ]);\n });\n\n it(\"keeps empty buckets and skips entries it cannot place in time\", () => {\n expect(\n parseOpenAiUsage({\n object: \"list\",\n data: [\n null,\n 42,\n { aggregation_timestamp: 1790380800 },\n { aggregation_timestamp: \"yesterday\", results: [] },\n { aggregation_timestamp: 1790294400, results: null },\n ],\n }),\n ).toEqual([\n { startMs: 1790380800000, tokens: 0 },\n { startMs: 1790294400000, tokens: 0 },\n ]);\n });\n\n it(\"rejects responses without a usage data array\", () => {\n expect(() => parseOpenAiUsage({ object: \"list\" })).toThrow(\"Invalid OpenAI usage response\");\n expect(() => parseOpenAiUsage({ data: {} })).toThrow(\"Invalid OpenAI usage response\");\n });\n\n it(\"builds today and 7-day windows without faked limits\", async () => {\n const buckets = [\n ...parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-completions.json\"))),\n ...parseOpenAiUsage(JSON.parse(await fixture(\"openai-usage-responses.json\"))),\n ];\n const report = buildOpenAiPlatformCapacity(buckets, checkedAt);\n expect(report).toMatchObject({\n authenticated: true,\n available: \"yes\",\n creditsRemaining: null,\n });\n expect(report.windows).toEqual([\n {\n id: \"openai:tokens:today\",\n label: \"Tokens · today (UTC)\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 1440,\n usedPercent: null,\n resetsAt: \"2026-09-27T00:00:00.000Z\",\n total: null,\n current: 2000,\n remaining: null,\n },\n {\n id: \"openai:tokens:week\",\n label: \"Tokens · 7 days\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 10080,\n usedPercent: null,\n resetsAt: null,\n total: null,\n current: 13000,\n remaining: null,\n },\n ]);\n });\n\n it(\"reports zero usage for days without buckets\", () => {\n const report = buildOpenAiPlatformCapacity([], checkedAt);\n expect(report.windows.map((window) => window.current)).toEqual([0, 0]);\n expect(report.windows[0].resetsAt).toBe(\"2026-09-27T00:00:00.000Z\");\n });\n});\n\ndescribe(\"OpenAI request\", () => {\n it(\"GETs both usage endpoints for the trailing week with only Bearer authentication\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.includes(\"/responses?\")\n ? new Response(await fixture(\"openai-usage-responses.json\"), {\n status: 200,\n })\n : new Response(await fixture(\"openai-usage-completions.json\"), {\n status: 200,\n }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"request-test-key\" },\n fetch,\n });\n const query = \"start_time=1789812000&end_time=1790416800\";\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(fetch).toHaveBeenCalledWith(\n `https://api.openai.com/v1/organization/usage/completions?${query}`,\n expect.objectContaining({\n method: \"GET\",\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(fetch).toHaveBeenCalledWith(\n `https://api.openai.com/v1/organization/usage/responses?${query}`,\n expect.objectContaining({\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(report.windows.map((window) => window.current)).toEqual([2000, 13000]);\n expect(JSON.stringify(report)).not.toContain(\"request-test-key\");\n });\n\n it(\"reports unauthenticated for rejected keys\", async () => {\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"rejected-key\" },\n fetch: vi.fn(async () => new Response(\"denied\", { status: 401 })),\n });\n expect(report).toMatchObject({\n authenticated: false,\n available: \"unknown\",\n windows: [],\n creditsRemaining: null,\n });\n });\n\n it(\"degrades to authentication-only when usage requires an admin key\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? new Response(\"{}\", { status: 200 })\n : new Response(\"forbidden\", { status: 403 }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"member-key\" },\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://api.openai.com/v1/models\",\n expect.objectContaining({\n headers: { Authorization: \"Bearer member-key\" },\n }),\n );\n expect(report).toMatchObject({\n authenticated: true,\n available: \"unknown\",\n windows: [],\n });\n });\n\n it(\"falls back to unauthenticated when the degraded check rejects the key\", async () => {\n const fetch = vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? new Response(\"denied\", { status: 401 })\n : new Response(\"forbidden\", { status: 403 }),\n );\n const report = await probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"revoked-key\" },\n fetch,\n });\n expect(report).toMatchObject({ authenticated: false, windows: [] });\n });\n\n it(\"sanitizes network failures on the platform key path\", async () => {\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"network-key\" },\n fetch: vi.fn(async () => Promise.reject(new Error(\"ECONNRESET secret\"))),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"network-key\" },\n fetch: vi.fn(async (url: string) =>\n url.endsWith(\"/models\")\n ? Promise.reject(new Error(\"ECONNRESET secret\"))\n : new Response(\"forbidden\", { status: 403 }),\n ),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed\");\n });\n\n it(\"rejects other statuses and malformed JSON responses with sanitized errors\", async () => {\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"private body\", { status: 503 })),\n }),\n ).rejects.toThrow(\"OpenAI usage request failed: HTTP 503\");\n await expect(\n probeOpenAiCapacity({\n checkedAt,\n env: { OPENAI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"not-json\", { status: 200 })),\n }),\n ).rejects.toThrow(\"OpenAI usage response is not valid JSON\");\n });\n});\n"],"names":["readFile","readFileSync","fileURLToPath","describe","expect","it","vi","probeOpenAiCapacity","buildOpenAiPlatformCapacity","parseOpenAiUsage","resolvePiOpenAiCredential","resolveOpenAiCredential","checkedAt","fixtureOauthAccess","fakeJwt","payload","Buffer","from","toString","join","fixture","name","URL","url","fixtureString","readAuth","fn","env","OPENAI_API_KEY","resolves","toEqual","kind","key","not","toHaveBeenCalled","HOME","toHaveBeenCalledWith","each","Promise","reject","Object","assign","Error","code","JSON","stringify","openai","type","_name","rejects","toThrow","oauthFixture","bothCredentials","access","refresh","expires","accountId","expiresMs","auth","toMatchObject","freshOauth","whamResponse","Response","status","fetch","report","objectContaining","method","headers","Authorization","harness","provider","generatedAt","authenticated","available","creditsRemaining","windows","map","window","id","toContain","staleAuth","toBe","expiredJwtAuth","exp","noFetch","futureJwtAuth","toHaveBeenCalledOnce","probe","timeoutMs","_url","init","_resolve","signal","addEventListener","error","String","buckets","parse","startMs","tokens","object","data","aggregation_timestamp","results","label","limitType","durationMinutes","usedPercent","resetsAt","total","current","remaining","includes","query","toHaveBeenCalledTimes","endsWith"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,mBAAmB;AAC5C,SAASC,YAAY,QAAQ,UAAU;AACvC,SAASC,aAAa,QAAQ,WAAW;AACzC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAS;AAClD,SAASC,mBAAmB,QAAQ,+BAA+B;AACnE,SACEC,2BAA2B,EAC3BC,gBAAgB,QACX,8CAA8C;AACrD,SAASC,6BAA6BC,uBAAuB,QAAQ,oCAAoC;AAEzG,MAAMC,YAAY;AAClB,MAAMC,qBAAqB;AAC3B,MAAMC,UAAU,CAACC,UACf;QAAC;QAAQC,OAAOC,IAAI,CAACF,SAASG,QAAQ,CAAC;QAAc;KAAO,CAACC,IAAI,CAAC;AACpE,MAAMC,UAAU,CAACC,OACfrB,SAASE,cAAc,IAAIoB,IAAI,CAAC,WAAW,EAAED,MAAM,EAAE,YAAYE,GAAG,IAAI;AAC1E,MAAMC,gBAAgB,CAACH,OACrBpB,aAAaC,cAAc,IAAIoB,IAAI,CAAC,WAAW,EAAED,MAAM,EAAE,YAAYE,GAAG,IAAI;AAE9EpB,SAAS,gCAAgC;IACvCE,GAAG,kDAAkD;QACnD,MAAMoB,WAAWnB,GAAGoB,EAAE,CAAC,UAAYN,QAAQ;QAC3C,MAAMhB,OACJO,wBAAwB;YACtBgB,KAAK;gBAAEC,gBAAgB;YAAsB;YAC7C5B,UAAUyB;QACZ,IACAI,QAAQ,CAACC,OAAO,CAAC;YAAEC,MAAM;YAAYC,KAAK;QAAsB;QAClE5B,OAAOqB,UAAUQ,GAAG,CAACC,gBAAgB;IACvC;IAEA7B,GAAG,qEAAqE;QACtE,MAAMoB,WAAWnB,GAAGoB,EAAE,CAAC,UAAYN,QAAQ;QAC3C,MAAMhB,OACJO,wBAAwB;YAAEgB,KAAK;gBAAEQ,MAAM;YAAc;YAAGnC,UAAUyB;QAAS,IAC3EI,QAAQ,CAACC,OAAO,CAAC;YAAEC,MAAM;YAAYC,KAAK;QAAqB;QACjE5B,OAAOqB,UAAUW,oBAAoB,CAAC,mCAAmC;IAC3E;IAEA/B,GAAGgC,IAAI,CAAC;QACN;YACE;YACA,UAAYC,QAAQC,MAAM,CAACC,OAAOC,MAAM,CAAC,IAAIC,MAAM,YAAY;oBAAEC,MAAM;gBAAS;SACjF;QACD;YAAC;YAAgB,UAAY;SAAI;QACjC;YAAC;YAAyB,UAAYC,KAAKC,SAAS,CAAC;oBAAEC,QAAQ;wBAAEC,MAAM;wBAASf,KAAK;oBAAI;gBAAE;SAAG;QAC9F;YAAC;YAAe,UAAYY,KAAKC,SAAS,CAAC;oBAAEC,QAAQ;wBAAEC,MAAM;oBAAU;gBAAE;SAAG;KAC7E,EAAE,kEAAkE,OAAOC,OAAOvB;QACjF,MAAMrB,OACJO,wBAAwB;YACtBgB,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAUyB;QACZ,IACAwB,OAAO,CAACC,OAAO,CAAC;IACpB;AACF;AAEA/C,SAAS,uCAAuC;IAC9C,MAAMgD,eAAe,IAAM/B,QAAQ;IACnC,MAAMgC,kBAAkBR,KAAKC,SAAS,CAAC;QACrCC,QAAQ;YAAEC,MAAM;YAAWf,KAAK;QAAqB;QACrD,gBAAgB;YACde,MAAM;YACNM,QAAQxC;YACRyC,SAAS;YACTC,SAAS;YACTC,WAAW;QACb;IACF;IAEAnD,GAAG,+EAA+E;QAChF,MAAMD,OACJO,wBAAwB;YACtBgB,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYoD;QACxB,IACAvB,QAAQ,CAACC,OAAO,CAAC;YAAEC,MAAM;YAAYC,KAAK;QAAqB;IACnE;IAEA3B,GAAG,+EAA+E;QAChF,MAAMD,OACJO,wBAAwB;YACtBgB,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYmD;QACxB,IACAtB,QAAQ,CAACC,OAAO,CAAC;YACjBC,MAAM;YACNsB,QAAQxC;YACR2C,WAAW;YACXC,WAAW;QACb;IACF;IAEApD,GAAG,gEAAgE;QACjE,MAAMqD,OAAOd,KAAKC,SAAS,CAAC;YAC1B,gBAAgB;gBACdE,MAAM;gBACNM,QAAQ;gBACRC,SAAS;gBACTC,SAAS;gBACTC,WAAW;YACb;QACF;QACA,MAAMpD,OACJO,wBAAwB;YAAEgB,KAAK;gBAAEQ,MAAM;YAAc;YAAGnC,UAAU,UAAY0D;QAAK,IACnF7B,QAAQ,CAAC8B,aAAa,CAAC;YAAE5B,MAAM;YAAS0B,WAAW;QAAc;IACrE;IAEApD,GAAG,wEAAwE;QACzE,MAAMqD,OAAOd,KAAKC,SAAS,CAAC;YAC1B,gBAAgB;gBACdE,MAAM;gBACNM,QAAQ;gBACRG,WAAW;YACb;QACF;QACA,MAAMpD,OACJO,wBAAwB;YAAEgB,KAAK;gBAAEQ,MAAM;YAAc;YAAGnC,UAAU,UAAY0D;QAAK,IACnF7B,QAAQ,CAAC8B,aAAa,CAAC;YAAE5B,MAAM;YAAS0B,WAAW;QAAK;IAC5D;IAEApD,GAAGgC,IAAI,CAAC;QACN;YAAC;YAAyBO,KAAKC,SAAS,CAAC;gBAAE,gBAAgB;oBAAEE,MAAM;oBAAWf,KAAK;gBAAI;YAAE;SAAG;QAC5F;YAAC;YAAwBY,KAAKC,SAAS,CAAC;gBAAE,gBAAgB;oBAAEE,MAAM;oBAASS,WAAW;gBAAI;YAAE;SAAG;QAC/F;YAAC;YAAsBZ,KAAKC,SAAS,CAAC;gBAAE,gBAAgB;oBAAEE,MAAM;oBAASM,QAAQ;gBAAI;YAAE;SAAG;KAC3F,EACC,yEACA,OAAOL,OAAOU;QACZ,MAAMtD,OACJO,wBAAwB;YAAEgB,KAAK;gBAAEQ,MAAM;YAAc;YAAGnC,UAAU,UAAY0D;QAAK,IACnFT,OAAO,CAACC,OAAO,CAAC;IACpB;AAEJ;AAEA/C,SAAS,+BAA+B;IACtC,MAAMyD,aAAa,IAAMxC,QAAQ;IACjC,MAAMyC,eAAe,IAAM,IAAIC,SAAStC,cAAc,oBAAoB;YAAEuC,QAAQ;QAAI;IAExF1D,GAAG,yDAAyD;QAC1D,MAAM2D,QAAQ1D,GAAGoB,EAAE,CAAC,UAAYmC;QAChC,MAAMI,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAY4D;YACtBI;QACF;QACA5D,OAAO4D,OAAO5B,oBAAoB,CAChC,8CACAhC,OAAO8D,gBAAgB,CAAC;YACtBC,QAAQ;YACRC,SAAS;gBACPC,eAAe,CAAC,OAAO,EAAExD,oBAAoB;gBAC7C,sBAAsB;YACxB;QACF;QAEFT,OAAO6D,QAAQN,aAAa,CAAC;YAC3BW,SAAS;YACTC,UAAU;YACVC,aAAa5D;YACb6D,eAAe;YACfC,WAAW;YACXC,kBAAkB;QACpB;QACAvE,OAAO6D,OAAOW,OAAO,CAACC,GAAG,CAAC,CAACC,SAAWA,OAAOC,EAAE,GAAGjD,OAAO,CAAC;YAAC;YAAW;SAAS;QAC/E1B,OAAOwC,KAAKC,SAAS,CAACoB,SAAShC,GAAG,CAAC+C,SAAS,CAAC;IAC/C;IAEA3E,GAAG,kFAAkF;QACnF,MAAM4E,YAAYrC,KAAKC,SAAS,CAAC;YAC/B,gBAAgB;gBACdE,MAAM;gBACNM,QAAQ;gBACRE,SAAS;gBACTC,WAAW;YACb;QACF;QACA,MAAMQ,QAAQ1D,GAAGoB,EAAE;QACnB,MAAMuC,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYiF;YACtBjB;QACF;QACA5D,OAAO4D,OAAO/B,GAAG,CAACC,gBAAgB;QAClC9B,OAAO6D,QAAQnC,OAAO,CAAC;YACrBwC,SAAS;YACTC,UAAU;YACVC,aAAa5D;YACb6D,eAAe;YACfC,WAAW;YACXE,SAAS,EAAE;YACXD,kBAAkB;QACpB;IACF;IAEAtE,GAAG,6DAA6D;QAC9D,MAAM4E,YAAYrC,KAAKC,SAAS,CAAC;YAC/B,gBAAgB;gBACdE,MAAM;gBACNM,QAAQ;gBACRE,SAAS;gBACTC,WAAW;YACb;QACF;QACA,MAAMQ,QAAQ1D,GAAGoB,EAAE;QACnB,MAAMuC,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYiF;YACtBjB;QACF;QACA5D,OAAO4D,OAAO/B,GAAG,CAACC,gBAAgB;QAClC9B,OAAO6D,OAAOS,SAAS,EAAEQ,IAAI,CAAC;IAChC;IAEA7E,GAAG,8DAA8D;QAC/D,MAAM8E,iBAAiBvC,KAAKC,SAAS,CAAC;YACpC,gBAAgB;gBACdE,MAAM;gBACNM,QAAQvC,QAAQ8B,KAAKC,SAAS,CAAC;oBAAEuC,KAAK;gBAAW;gBACjD5B,WAAW;YACb;QACF;QACA,MAAM6B,UAAU/E,GAAGoB,EAAE;QACrB,MAAMtB,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYmF;YACtBnB,OAAOqB;QACT,IACAxD,QAAQ,CAAC8B,aAAa,CAAC;YAAEc,eAAe;YAAMC,WAAW;QAAU;QACrEtE,OAAOiF,SAASpD,GAAG,CAACC,gBAAgB;QAEpC,MAAMoD,gBAAgB1C,KAAKC,SAAS,CAAC;YACnC,gBAAgB;gBACdE,MAAM;gBACNM,QAAQvC,QAAQ8B,KAAKC,SAAS,CAAC;oBAAEuC,KAAK;gBAAW;gBACjD5B,WAAW;YACb;QACF;QACA,MAAMQ,QAAQ1D,GAAGoB,EAAE,CAAC,UAAYmC;QAChC,MAAMzD,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAYsF;YACtBtB;QACF,IACAnC,QAAQ,CAAC8B,aAAa,CAAC;YAAEc,eAAe;YAAMC,WAAW;QAAM;QACjEtE,OAAO4D,OAAOuB,oBAAoB;IACpC;IAEAlF,GAAG,uEAAuE;QACxE,MAAMqD,OAAOd,KAAKC,SAAS,CAAC;YAC1B,gBAAgB;gBACdE,MAAM;gBACNM,QAAQvC,QAAQ;gBAChB0C,WAAW;YACb;QACF;QACA,MAAMQ,QAAQ1D,GAAGoB,EAAE,CAAC,UAAYmC;QAChC,MAAMzD,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAY0D;YACtBM;QACF,IACAnC,QAAQ,CAAC8B,aAAa,CAAC;YAAEc,eAAe;YAAMC,WAAW;QAAM;QACjEtE,OAAO4D,OAAOuB,oBAAoB;IACpC;IAEAlF,GAAG,iFAAiF;QAClF,KAAK,MAAMgD,UAAU;YAAC;YAAyB;SAAsB,CAAE;YACrE,MAAMK,OAAOd,KAAKC,SAAS,CAAC;gBAC1B,gBAAgB;oBACdE,MAAM;oBACNM;oBACAG,WAAW;gBACb;YACF;YACA,MAAMQ,QAAQ1D,GAAGoB,EAAE,CAAC,UAAYmC;YAChC,MAAMzD,OACJG,oBAAoB;gBAClBK;gBACAe,KAAK;oBAAEQ,MAAM;gBAAc;gBAC3BnC,UAAU,UAAY0D;gBACtBM;YACF,IACAnC,QAAQ,CAAC8B,aAAa,CAAC;gBAAEc,eAAe;gBAAMC,WAAW;YAAM;YACjEtE,OAAO4D,OAAOuB,oBAAoB;QACpC;IACF;IAEAlF,GAAG,oEAAoE;QACrE,MAAM4D,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEQ,MAAM;YAAc;YAC3BnC,UAAU,UAAY4D;YACtBI,OAAO1D,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,MAAM;oBAAEC,QAAQ;gBAAI;QAC5D;QACA3D,OAAO6D,QAAQN,aAAa,CAAC;YAAEc,eAAe;YAAMC,WAAW;YAAWE,SAAS,EAAE;QAAC;IACxF;IAEAvE,GAAG,6DAA6D;QAC9D,KAAK,MAAM0D,UAAU;YAAC;YAAK;SAAI,CAAE;YAC/B,MAAME,SAAS,MAAM1D,oBAAoB;gBACvCK;gBACAe,KAAK;oBAAEQ,MAAM;gBAAc;gBAC3BnC,UAAU,UAAY4D;gBACtBI,OAAO1D,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,UAAU;wBAAEC;oBAAO;YAC3D;YACA3D,OAAO6D,QAAQN,aAAa,CAAC;gBAC3Bc,eAAe;gBACfC,WAAW;gBACXE,SAAS,EAAE;gBACXD,kBAAkB;YACpB;QACF;IACF;IAEAtE,GAAG,yEAAyE;QAC1E,MAAMmF,QAAQ,CAACxB,QACbzD,oBAAoB;gBAClBK;gBACAe,KAAK;oBAAEQ,MAAM;gBAAc;gBAC3BnC,UAAU,UAAY4D;gBACtBI,OAAOA;gBACPyB,WAAW;YACb;QACF,MAAMrF,OACJoF,MACE,CAACE,MAAcC,OACb,IAAIrD,QAAQ,CAACsD,UAAUrD,SACrBoD,KAAKE,MAAM,EAAEC,iBAAiB,SAAS,IAAMvD,OAAO,IAAIG,MAAM,gBAGpEO,OAAO,CAACC,OAAO,CAAC;QAClB,MAAM9C,OAAOoF,MAAMlF,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,QAAQ;gBAAEC,QAAQ;YAAI,MAAMd,OAAO,CAACC,OAAO,CAC3F;QAEF,MAAM9C,OACJoF,MAAMlF,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,YAAY;gBAAEC,QAAQ;YAAI,MAC/Dd,OAAO,CAACC,OAAO,CAAC;QAClB,IAAI;YACF,MAAMsC,MAAMlF,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,QAAQ;oBAAEC,QAAQ;gBAAI;QACnE,EAAE,OAAOgC,OAAO;YACd3F,OAAO4F,OAAOD,QAAQ9D,GAAG,CAAC+C,SAAS,CAAC;YACpC5E,OAAO4F,OAAOD,QAAQ9D,GAAG,CAAC+C,SAAS,CAAC;QACtC;IACF;AACF;AAEA7E,SAAS,wBAAwB;IAC/BE,GAAG,+DAA+D;QAChE,MAAM4F,UAAUxF,iBAAiBmC,KAAKsD,KAAK,CAAC,MAAM9E,QAAQ;QAC1DhB,OAAO6F,SAASnE,OAAO,CAAC;YACtB;gBAAEqE,SAAS;gBAAeC,QAAQ;YAAK;YACvC;gBAAED,SAAS;gBAAeC,QAAQ;YAAK;YACvC;gBAAED,SAAS;gBAAeC,QAAQ;YAAK;YACvC;gBAAED,SAAS;gBAAeC,QAAQ;YAAM;SACzC;IACH;IAEA/F,GAAG,iEAAiE;QAClED,OACEK,iBAAiB;YACf4F,QAAQ;YACRC,MAAM;gBACJ;gBACA;gBACA;oBAAEC,uBAAuB;gBAAW;gBACpC;oBAAEA,uBAAuB;oBAAaC,SAAS,EAAE;gBAAC;gBAClD;oBAAED,uBAAuB;oBAAYC,SAAS;gBAAK;aACpD;QACH,IACA1E,OAAO,CAAC;YACR;gBAAEqE,SAAS;gBAAeC,QAAQ;YAAE;YACpC;gBAAED,SAAS;gBAAeC,QAAQ;YAAE;SACrC;IACH;IAEA/F,GAAG,gDAAgD;QACjDD,OAAO,IAAMK,iBAAiB;gBAAE4F,QAAQ;YAAO,IAAInD,OAAO,CAAC;QAC3D9C,OAAO,IAAMK,iBAAiB;gBAAE6F,MAAM,CAAC;YAAE,IAAIpD,OAAO,CAAC;IACvD;IAEA7C,GAAG,uDAAuD;QACxD,MAAM4F,UAAU;eACXxF,iBAAiBmC,KAAKsD,KAAK,CAAC,MAAM9E,QAAQ;eAC1CX,iBAAiBmC,KAAKsD,KAAK,CAAC,MAAM9E,QAAQ;SAC9C;QACD,MAAM6C,SAASzD,4BAA4ByF,SAASrF;QACpDR,OAAO6D,QAAQN,aAAa,CAAC;YAC3Bc,eAAe;YACfC,WAAW;YACXC,kBAAkB;QACpB;QACAvE,OAAO6D,OAAOW,OAAO,EAAE9C,OAAO,CAAC;YAC7B;gBACEiD,IAAI;gBACJ0B,OAAO;gBACPC,WAAW;gBACXC,iBAAiB;gBACjBC,aAAa;gBACbC,UAAU;gBACVC,OAAO;gBACPC,SAAS;gBACTC,WAAW;YACb;YACA;gBACEjC,IAAI;gBACJ0B,OAAO;gBACPC,WAAW;gBACXC,iBAAiB;gBACjBC,aAAa;gBACbC,UAAU;gBACVC,OAAO;gBACPC,SAAS;gBACTC,WAAW;YACb;SACD;IACH;IAEA3G,GAAG,+CAA+C;QAChD,MAAM4D,SAASzD,4BAA4B,EAAE,EAAEI;QAC/CR,OAAO6D,OAAOW,OAAO,CAACC,GAAG,CAAC,CAACC,SAAWA,OAAOiC,OAAO,GAAGjF,OAAO,CAAC;YAAC;YAAG;SAAE;QACrE1B,OAAO6D,OAAOW,OAAO,CAAC,EAAE,CAACiC,QAAQ,EAAE3B,IAAI,CAAC;IAC1C;AACF;AAEA/E,SAAS,kBAAkB;IACzBE,GAAG,mFAAmF;QACpF,MAAM2D,QAAQ1D,GAAGoB,EAAE,CAAC,OAAOH,MACzBA,IAAI0F,QAAQ,CAAC,iBACT,IAAInD,SAAS,MAAM1C,QAAQ,gCAAgC;gBACzD2C,QAAQ;YACV,KACA,IAAID,SAAS,MAAM1C,QAAQ,kCAAkC;gBAC3D2C,QAAQ;YACV;QAEN,MAAME,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEC,gBAAgB;YAAmB;YAC1CoC;QACF;QACA,MAAMkD,QAAQ;QACd9G,OAAO4D,OAAOmD,qBAAqB,CAAC;QACpC/G,OAAO4D,OAAO5B,oBAAoB,CAChC,CAAC,yDAAyD,EAAE8E,OAAO,EACnE9G,OAAO8D,gBAAgB,CAAC;YACtBC,QAAQ;YACRC,SAAS;gBAAEC,eAAe;YAA0B;QACtD;QAEFjE,OAAO4D,OAAO5B,oBAAoB,CAChC,CAAC,uDAAuD,EAAE8E,OAAO,EACjE9G,OAAO8D,gBAAgB,CAAC;YACtBE,SAAS;gBAAEC,eAAe;YAA0B;QACtD;QAEFjE,OAAO6D,OAAOW,OAAO,CAACC,GAAG,CAAC,CAACC,SAAWA,OAAOiC,OAAO,GAAGjF,OAAO,CAAC;YAAC;YAAM;SAAM;QAC5E1B,OAAOwC,KAAKC,SAAS,CAACoB,SAAShC,GAAG,CAAC+C,SAAS,CAAC;IAC/C;IAEA3E,GAAG,6CAA6C;QAC9C,MAAM4D,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEC,gBAAgB;YAAe;YACtCoC,OAAO1D,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,UAAU;oBAAEC,QAAQ;gBAAI;QAChE;QACA3D,OAAO6D,QAAQN,aAAa,CAAC;YAC3Bc,eAAe;YACfC,WAAW;YACXE,SAAS,EAAE;YACXD,kBAAkB;QACpB;IACF;IAEAtE,GAAG,oEAAoE;QACrE,MAAM2D,QAAQ1D,GAAGoB,EAAE,CAAC,OAAOH,MACzBA,IAAI6F,QAAQ,CAAC,aACT,IAAItD,SAAS,MAAM;gBAAEC,QAAQ;YAAI,KACjC,IAAID,SAAS,aAAa;gBAAEC,QAAQ;YAAI;QAE9C,MAAME,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEC,gBAAgB;YAAa;YACpCoC;QACF;QACA5D,OAAO4D,OAAO5B,oBAAoB,CAChC,oCACAhC,OAAO8D,gBAAgB,CAAC;YACtBE,SAAS;gBAAEC,eAAe;YAAoB;QAChD;QAEFjE,OAAO6D,QAAQN,aAAa,CAAC;YAC3Bc,eAAe;YACfC,WAAW;YACXE,SAAS,EAAE;QACb;IACF;IAEAvE,GAAG,yEAAyE;QAC1E,MAAM2D,QAAQ1D,GAAGoB,EAAE,CAAC,OAAOH,MACzBA,IAAI6F,QAAQ,CAAC,aACT,IAAItD,SAAS,UAAU;gBAAEC,QAAQ;YAAI,KACrC,IAAID,SAAS,aAAa;gBAAEC,QAAQ;YAAI;QAE9C,MAAME,SAAS,MAAM1D,oBAAoB;YACvCK;YACAe,KAAK;gBAAEC,gBAAgB;YAAc;YACrCoC;QACF;QACA5D,OAAO6D,QAAQN,aAAa,CAAC;YAAEc,eAAe;YAAOG,SAAS,EAAE;QAAC;IACnE;IAEAvE,GAAG,uDAAuD;QACxD,MAAMD,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEC,gBAAgB;YAAc;YACrCoC,OAAO1D,GAAGoB,EAAE,CAAC,UAAYY,QAAQC,MAAM,CAAC,IAAIG,MAAM;QACpD,IACAO,OAAO,CAACC,OAAO,CAAC;QAClB,MAAM9C,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEC,gBAAgB;YAAc;YACrCoC,OAAO1D,GAAGoB,EAAE,CAAC,OAAOH,MAClBA,IAAI6F,QAAQ,CAAC,aACT9E,QAAQC,MAAM,CAAC,IAAIG,MAAM,wBACzB,IAAIoB,SAAS,aAAa;oBAAEC,QAAQ;gBAAI;QAEhD,IACAd,OAAO,CAACC,OAAO,CAAC;IACpB;IAEA7C,GAAG,6EAA6E;QAC9E,MAAMD,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEC,gBAAgB;YAAwB;YAC/CoC,OAAO1D,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,gBAAgB;oBAAEC,QAAQ;gBAAI;QACtE,IACAd,OAAO,CAACC,OAAO,CAAC;QAClB,MAAM9C,OACJG,oBAAoB;YAClBK;YACAe,KAAK;gBAAEC,gBAAgB;YAAwB;YAC/CoC,OAAO1D,GAAGoB,EAAE,CAAC,UAAY,IAAIoC,SAAS,YAAY;oBAAEC,QAAQ;gBAAI;QAClE,IACAd,OAAO,CAACC,OAAO,CAAC;IACpB;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
|
-
import { parseWhamUsage, toRateWindow } from "../../capacity/
|
|
4
|
+
import { parseWhamUsage, toRateWindow } from "../../capacity/providers/openai-subscription.js";
|
|
5
5
|
const fixture = (name)=>readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
|
|
6
6
|
describe("wham usage parsing", ()=>{
|
|
7
7
|
it("maps primary and secondary rate windows onto session and weekly", async ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/capacity/wham.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it } from \"vitest\";\nimport { parseWhamUsage, toRateWindow } from \"../../capacity/
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/capacity/wham.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it } from \"vitest\";\nimport { parseWhamUsage, toRateWindow } from \"../../capacity/providers/openai-subscription.js\";\n\nconst fixture = (name: string) =>\n readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\n\ndescribe(\"wham usage parsing\", () => {\n it(\"maps primary and secondary rate windows onto session and weekly\", async () => {\n const snapshot = parseWhamUsage(JSON.parse(await fixture(\"wham-usage.json\")));\n expect(snapshot.windows).toEqual([\n {\n id: \"session\",\n label: \"Session\",\n durationMinutes: 300,\n usedPercent: 12.5,\n resetsAt: \"2026-09-27T13:52:07.000Z\",\n },\n {\n id: \"weekly\",\n label: \"Weekly\",\n durationMinutes: 10080,\n usedPercent: 43.2,\n resetsAt: \"2026-10-04T08:52:07.000Z\",\n },\n ]);\n expect(snapshot.creditsRemaining).toBe(4.5);\n });\n\n it(\"accepts epoch seconds and ISO strings for reset_at\", () => {\n expect(toRateWindow({ used_percent: 1, reset_at: 1_787_220_000 }, \"a\", \"A\")?.resetsAt).toBe(\n \"2026-08-20T10:00:00.000Z\",\n );\n expect(\n toRateWindow({ used_percent: 1, reset_at: \"2026-08-20T10:00:00Z\" }, \"a\", \"A\")?.resetsAt,\n ).toBe(\"2026-08-20T10:00:00.000Z\");\n expect(toRateWindow({ used_percent: 1, reset_at: \"nope\" }, \"a\", \"A\")?.resetsAt).toBeNull();\n });\n\n it(\"maps additional_rate_limits into scoped windows and tolerates non-array values\", () => {\n const scoped = parseWhamUsage({\n rate_limit: {},\n additional_rate_limits: [\n {\n limit_name: \"code-review\",\n rate_limit: {\n primary_window: { used_percent: 10, limit_window_seconds: 3600, reset_at: 100 },\n secondary_window: { used_percent: 20, limit_window_seconds: 7200, reset_at: 200 },\n },\n },\n ],\n });\n expect(scoped.windows.map((window) => window.id)).toEqual([\n \"code-review:primary\",\n \"code-review:secondary\",\n ]);\n expect(parseWhamUsage({ additional_rate_limits: null }).windows).toEqual([]);\n });\n\n it(\"falls back to positional ids and inline windows for degraded extra limits\", () => {\n const scoped = parseWhamUsage({\n additional_rate_limits: [\n null,\n 42,\n { primary_window: { used_percent: 5 } },\n { limit_name: \"not/safe\", primary_window: { used_percent: 6 } },\n { limit_name: \"token-123456\", primary_window: { used_percent: 7 } },\n { limit_name: \"ok\", secondary_window: { used_percent: 8 } },\n ],\n });\n expect(scoped.windows.map((window) => window.id)).toEqual([\n \"extra-3:primary\",\n \"extra-4:primary\",\n \"extra-5:primary\",\n \"ok:secondary\",\n ]);\n });\n\n it(\"parses non-object payloads into an empty snapshot\", () => {\n expect(parseWhamUsage(null)).toEqual({ windows: [], creditsRemaining: null });\n expect(parseWhamUsage(42)).toEqual({ windows: [], creditsRemaining: null });\n });\n\n it(\"never invents usage for windows it cannot parse\", () => {\n const snapshot = parseWhamUsage({\n rate_limit: {\n primary_window: { limit_window_seconds: 18000 },\n secondary_window: null,\n },\n });\n expect(snapshot.windows).toEqual([\n {\n id: \"session\",\n label: \"Session\",\n durationMinutes: 300,\n usedPercent: null,\n resetsAt: null,\n },\n ]);\n expect(parseWhamUsage({}).creditsRemaining).toBeNull();\n expect(parseWhamUsage({ credits: { balance: \"nan\" } }).creditsRemaining).toBeNull();\n });\n});\n"],"names":["readFile","fileURLToPath","describe","expect","it","parseWhamUsage","toRateWindow","fixture","name","URL","url","snapshot","JSON","parse","windows","toEqual","id","label","durationMinutes","usedPercent","resetsAt","creditsRemaining","toBe","used_percent","reset_at","toBeNull","scoped","rate_limit","additional_rate_limits","limit_name","primary_window","limit_window_seconds","secondary_window","map","window","credits","balance"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
import { describe, expect, it, vi } from "vitest";
|
|
4
|
-
import {
|
|
4
|
+
import { parseZaiCapacity } from "../../capacity/providers/zai.js";
|
|
5
|
+
import { probeZaiCapacity } from "../../capacity/sources/pi.js";
|
|
6
|
+
import { resolvePiZaiApiKey as resolveZaiApiKey } from "../../harnesses/pi/credentials.js";
|
|
5
7
|
const checkedAt = "2026-08-20T10:00:00.000Z";
|
|
6
8
|
const fixture = (name)=>readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), "utf8");
|
|
7
9
|
describe("z.ai credential resolution", ()=>{
|
|
@@ -64,11 +66,8 @@ describe("z.ai credential resolution", ()=>{
|
|
|
64
66
|
});
|
|
65
67
|
describe("z.ai quota mapping", ()=>{
|
|
66
68
|
it("maps token, credit, and monthly MCP windows with recomputed usage", async ()=>{
|
|
67
|
-
const report =
|
|
69
|
+
const report = parseZaiCapacity(JSON.parse(await fixture("zai-quota.json")));
|
|
68
70
|
expect(report).toMatchObject({
|
|
69
|
-
harness: "pi",
|
|
70
|
-
provider: "zai",
|
|
71
|
-
generatedAt: checkedAt,
|
|
72
71
|
authenticated: true,
|
|
73
72
|
available: "yes",
|
|
74
73
|
creditsRemaining: null
|
|
@@ -110,7 +109,7 @@ describe("z.ai quota mapping", ()=>{
|
|
|
110
109
|
]);
|
|
111
110
|
});
|
|
112
111
|
it("uses and clamps the server percentage when quota amounts are unavailable", ()=>{
|
|
113
|
-
const report =
|
|
112
|
+
const report = parseZaiCapacity({
|
|
114
113
|
success: true,
|
|
115
114
|
code: 200,
|
|
116
115
|
data: {
|
|
@@ -129,7 +128,7 @@ describe("z.ai quota mapping", ()=>{
|
|
|
129
128
|
}
|
|
130
129
|
]
|
|
131
130
|
}
|
|
132
|
-
}
|
|
131
|
+
});
|
|
133
132
|
expect(report.windows.map((window)=>window.usedPercent)).toEqual([
|
|
134
133
|
100,
|
|
135
134
|
0
|
|
@@ -164,7 +163,7 @@ describe("z.ai quota mapping", ()=>{
|
|
|
164
163
|
]
|
|
165
164
|
])("rejects %s", async (_name, input)=>{
|
|
166
165
|
const value = await input();
|
|
167
|
-
expect(()=>
|
|
166
|
+
expect(()=>parseZaiCapacity(value)).toThrow(/z\.ai quota/);
|
|
168
167
|
});
|
|
169
168
|
});
|
|
170
169
|
describe("z.ai request", ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/__tests__/capacity/zai.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport {\n parseZaiQuota,\n probeZaiCapacity,\n resolveZaiApiKey,\n} from \"../../capacity/zai.js\";\n\nconst checkedAt = \"2026-08-20T10:00:00.000Z\";\nconst fixture = (name: string) =>\n readFile(\n fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)),\n \"utf8\",\n );\n\ndescribe(\"z.ai credential resolution\", () => {\n it(\"prefers Z_AI_API_KEY without reading Pi auth\", async () => {\n const readAuth = vi.fn(async () => fixture(\"zai-auth.json\"));\n await expect(\n resolveZaiApiKey({\n env: { Z_AI_API_KEY: \"env-zai-test-key\" },\n readFile: readAuth,\n }),\n ).resolves.toBe(\"env-zai-test-key\");\n expect(readAuth).not.toHaveBeenCalled();\n });\n\n it(\"reads the Pi zai api_key credential from ~/.pi/agent/auth.json\", async () => {\n const readAuth = vi.fn(async () => fixture(\"zai-auth.json\"));\n await expect(\n resolveZaiApiKey({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).resolves.toBe(\"pi-zai-test-key\");\n expect(readAuth).toHaveBeenCalledWith(\n \"/users/test/.pi/agent/auth.json\",\n \"utf8\",\n );\n });\n\n it.each([\n [\n \"missing\",\n async () =>\n Promise.reject(Object.assign(new Error(\"missing\"), { code: \"ENOENT\" })),\n ],\n [\"invalid JSON\", async () => \"{\"],\n [\n \"wrong credential type\",\n async () => JSON.stringify({ zai: { type: \"oauth\", key: \"x\" } }),\n ],\n [\"missing key\", async () => JSON.stringify({ zai: { type: \"api_key\" } })],\n ])(\n \"fails clearly for %s credentials without exposing file content\",\n async (_name, readAuth) => {\n await expect(\n resolveZaiApiKey({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).rejects.toThrow(/z\\.ai API key|z\\.ai Pi auth file/);\n },\n );\n});\n\ndescribe(\"z.ai quota mapping\", () => {\n it(\"maps token, credit, and monthly MCP windows with recomputed usage\", async () => {\n const report = parseZaiQuota(\n JSON.parse(await fixture(\"zai-quota.json\")),\n checkedAt,\n );\n expect(report).toMatchObject({\n harness: \"pi\",\n provider: \"zai\",\n generatedAt: checkedAt,\n authenticated: true,\n available: \"yes\",\n creditsRemaining: null,\n });\n expect(report.windows).toEqual([\n {\n id: \"zai:tokens:1\",\n label: \"Tokens · 5 hours\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 300,\n usedPercent: 30,\n resetsAt: \"2026-08-20T10:00:00.000Z\",\n total: 1000,\n current: 200,\n remaining: 700,\n },\n {\n id: \"zai:credit:2\",\n label: \"Credit · 1 week\",\n limitType: \"CREDIT_LIMIT\",\n durationMinutes: 10080,\n usedPercent: 40,\n resetsAt: \"2026-08-27T10:00:00.000Z\",\n total: 200,\n current: 80,\n remaining: 150,\n },\n {\n id: \"zai:time:3\",\n label: \"MCP · monthly\",\n limitType: \"TIME_LIMIT\",\n durationMinutes: 43200,\n usedPercent: 20,\n resetsAt: \"2026-09-19T10:00:00.000Z\",\n total: 100,\n current: 20,\n remaining: 90,\n },\n ]);\n });\n\n it(\"uses and clamps the server percentage when quota amounts are unavailable\", () => {\n const report = parseZaiQuota(\n {\n success: true,\n code: 200,\n data: {\n limits: [\n { type: \"TOKENS_LIMIT\", unit: 1, number: 1, percentage: 120 },\n { type: \"CREDIT_LIMIT\", unit: 5, number: 30, percentage: -5 },\n ],\n },\n },\n checkedAt,\n );\n expect(report.windows.map((window) => window.usedPercent)).toEqual([\n 100, 0,\n ]);\n });\n\n it.each([\n [\n \"invalid fixture\",\n async () => JSON.parse(await fixture(\"zai-quota-invalid.json\")),\n ],\n [\n \"unsuccessful envelope\",\n async () => ({ success: false, code: 401, data: { limits: [] } }),\n ],\n [\n \"invalid entry\",\n async () => ({ success: true, code: 200, data: { limits: [{}] } }),\n ],\n ])(\"rejects %s\", async (_name, input) => {\n const value = await input();\n expect(() => parseZaiQuota(value, checkedAt)).toThrow(/z\\.ai quota/);\n });\n});\n\ndescribe(\"z.ai request\", () => {\n it(\"GETs the global quota endpoint with only Bearer authentication\", async () => {\n const body = await fixture(\"zai-quota.json\");\n const fetch = vi.fn(async () => new Response(body, { status: 200 }));\n const report = await probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"request-test-key\" },\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://api.z.ai/api/monitor/usage/quota/limit\",\n expect.objectContaining({\n method: \"GET\",\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(JSON.stringify(report)).not.toContain(\"request-test-key\");\n });\n\n it(\"rejects non-200 and malformed JSON responses with sanitized errors\", async () => {\n await expect(\n probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"private body\", { status: 503 })),\n }),\n ).rejects.toThrow(\"z.ai quota request failed: HTTP 503\");\n await expect(\n probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"not-json\", { status: 200 })),\n }),\n ).rejects.toThrow(\"z.ai quota response is not valid JSON\");\n });\n});\n"],"names":["readFile","fileURLToPath","describe","expect","it","vi","parseZaiQuota","probeZaiCapacity","resolveZaiApiKey","checkedAt","fixture","name","URL","url","readAuth","fn","env","Z_AI_API_KEY","resolves","toBe","not","toHaveBeenCalled","HOME","toHaveBeenCalledWith","each","Promise","reject","Object","assign","Error","code","JSON","stringify","zai","type","key","_name","rejects","toThrow","report","parse","toMatchObject","harness","provider","generatedAt","authenticated","available","creditsRemaining","windows","toEqual","id","label","limitType","durationMinutes","usedPercent","resetsAt","total","current","remaining","success","data","limits","unit","number","percentage","map","window","input","value","body","fetch","Response","status","objectContaining","method","headers","Authorization","toContain"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/__tests__/capacity/zai.test.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport { describe, expect, it, vi } from \"vitest\";\nimport { parseZaiCapacity } from \"../../capacity/providers/zai.js\";\nimport { probeZaiCapacity } from \"../../capacity/sources/pi.js\";\nimport { resolvePiZaiApiKey as resolveZaiApiKey } from \"../../harnesses/pi/credentials.js\";\n\nconst checkedAt = \"2026-08-20T10:00:00.000Z\";\nconst fixture = (name: string) =>\n readFile(fileURLToPath(new URL(`./fixtures/${name}`, import.meta.url)), \"utf8\");\n\ndescribe(\"z.ai credential resolution\", () => {\n it(\"prefers Z_AI_API_KEY without reading Pi auth\", async () => {\n const readAuth = vi.fn(async () => fixture(\"zai-auth.json\"));\n await expect(\n resolveZaiApiKey({\n env: { Z_AI_API_KEY: \"env-zai-test-key\" },\n readFile: readAuth,\n }),\n ).resolves.toBe(\"env-zai-test-key\");\n expect(readAuth).not.toHaveBeenCalled();\n });\n\n it(\"reads the Pi zai api_key credential from ~/.pi/agent/auth.json\", async () => {\n const readAuth = vi.fn(async () => fixture(\"zai-auth.json\"));\n await expect(\n resolveZaiApiKey({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).resolves.toBe(\"pi-zai-test-key\");\n expect(readAuth).toHaveBeenCalledWith(\"/users/test/.pi/agent/auth.json\", \"utf8\");\n });\n\n it.each([\n [\n \"missing\",\n async () => Promise.reject(Object.assign(new Error(\"missing\"), { code: \"ENOENT\" })),\n ],\n [\"invalid JSON\", async () => \"{\"],\n [\"wrong credential type\", async () => JSON.stringify({ zai: { type: \"oauth\", key: \"x\" } })],\n [\"missing key\", async () => JSON.stringify({ zai: { type: \"api_key\" } })],\n ])(\"fails clearly for %s credentials without exposing file content\", async (_name, readAuth) => {\n await expect(\n resolveZaiApiKey({ env: { HOME: \"/users/test\" }, readFile: readAuth }),\n ).rejects.toThrow(/z\\.ai API key|z\\.ai Pi auth file/);\n });\n});\n\ndescribe(\"z.ai quota mapping\", () => {\n it(\"maps token, credit, and monthly MCP windows with recomputed usage\", async () => {\n const report = parseZaiCapacity(JSON.parse(await fixture(\"zai-quota.json\")));\n expect(report).toMatchObject({\n authenticated: true,\n available: \"yes\",\n creditsRemaining: null,\n });\n expect(report.windows).toEqual([\n {\n id: \"zai:tokens:1\",\n label: \"Tokens · 5 hours\",\n limitType: \"TOKENS_LIMIT\",\n durationMinutes: 300,\n usedPercent: 30,\n resetsAt: \"2026-08-20T10:00:00.000Z\",\n total: 1000,\n current: 200,\n remaining: 700,\n },\n {\n id: \"zai:credit:2\",\n label: \"Credit · 1 week\",\n limitType: \"CREDIT_LIMIT\",\n durationMinutes: 10080,\n usedPercent: 40,\n resetsAt: \"2026-08-27T10:00:00.000Z\",\n total: 200,\n current: 80,\n remaining: 150,\n },\n {\n id: \"zai:time:3\",\n label: \"MCP · monthly\",\n limitType: \"TIME_LIMIT\",\n durationMinutes: 43200,\n usedPercent: 20,\n resetsAt: \"2026-09-19T10:00:00.000Z\",\n total: 100,\n current: 20,\n remaining: 90,\n },\n ]);\n });\n\n it(\"uses and clamps the server percentage when quota amounts are unavailable\", () => {\n const report = parseZaiCapacity({\n success: true,\n code: 200,\n data: {\n limits: [\n { type: \"TOKENS_LIMIT\", unit: 1, number: 1, percentage: 120 },\n { type: \"CREDIT_LIMIT\", unit: 5, number: 30, percentage: -5 },\n ],\n },\n });\n expect(report.windows.map((window) => window.usedPercent)).toEqual([100, 0]);\n });\n\n it.each([\n [\"invalid fixture\", async () => JSON.parse(await fixture(\"zai-quota-invalid.json\"))],\n [\"unsuccessful envelope\", async () => ({ success: false, code: 401, data: { limits: [] } })],\n [\"invalid entry\", async () => ({ success: true, code: 200, data: { limits: [{}] } })],\n ])(\"rejects %s\", async (_name, input) => {\n const value = await input();\n expect(() => parseZaiCapacity(value)).toThrow(/z\\.ai quota/);\n });\n});\n\ndescribe(\"z.ai request\", () => {\n it(\"GETs the global quota endpoint with only Bearer authentication\", async () => {\n const body = await fixture(\"zai-quota.json\");\n const fetch = vi.fn(async () => new Response(body, { status: 200 }));\n const report = await probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"request-test-key\" },\n fetch,\n });\n expect(fetch).toHaveBeenCalledWith(\n \"https://api.z.ai/api/monitor/usage/quota/limit\",\n expect.objectContaining({\n method: \"GET\",\n headers: { Authorization: \"Bearer request-test-key\" },\n }),\n );\n expect(JSON.stringify(report)).not.toContain(\"request-test-key\");\n });\n\n it(\"rejects non-200 and malformed JSON responses with sanitized errors\", async () => {\n await expect(\n probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"private body\", { status: 503 })),\n }),\n ).rejects.toThrow(\"z.ai quota request failed: HTTP 503\");\n await expect(\n probeZaiCapacity({\n checkedAt,\n env: { Z_AI_API_KEY: \"never-expose-this-key\" },\n fetch: vi.fn(async () => new Response(\"not-json\", { status: 200 })),\n }),\n ).rejects.toThrow(\"z.ai quota response is not valid JSON\");\n });\n});\n"],"names":["readFile","fileURLToPath","describe","expect","it","vi","parseZaiCapacity","probeZaiCapacity","resolvePiZaiApiKey","resolveZaiApiKey","checkedAt","fixture","name","URL","url","readAuth","fn","env","Z_AI_API_KEY","resolves","toBe","not","toHaveBeenCalled","HOME","toHaveBeenCalledWith","each","Promise","reject","Object","assign","Error","code","JSON","stringify","zai","type","key","_name","rejects","toThrow","report","parse","toMatchObject","authenticated","available","creditsRemaining","windows","toEqual","id","label","limitType","durationMinutes","usedPercent","resetsAt","total","current","remaining","success","data","limits","unit","number","percentage","map","window","input","value","body","fetch","Response","status","objectContaining","method","headers","Authorization","toContain"],"mappings":"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"}
|