@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.
Files changed (1046) hide show
  1. package/dist/AgentManager.d.ts +9 -8
  2. package/dist/AgentManager.d.ts.map +1 -1
  3. package/dist/AgentManager.js +23 -4
  4. package/dist/AgentManager.js.map +1 -1
  5. package/dist/__tests__/AgentManager.test.js +151 -3
  6. package/dist/__tests__/AgentManager.test.js.map +1 -1
  7. package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js +486 -0
  8. package/dist/__tests__/adapters/IncrementalSessionRefresh.test.js.map +1 -0
  9. package/dist/__tests__/adapters/adapterProcessImports.test.js +52 -0
  10. package/dist/__tests__/adapters/adapterProcessImports.test.js.map +1 -0
  11. package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js +247 -0
  12. package/dist/__tests__/adapters/adapterSnapshotCandidates.test.js.map +1 -0
  13. package/dist/__tests__/capacity/anthropic.test.js +115 -0
  14. package/dist/__tests__/capacity/anthropic.test.js.map +1 -0
  15. package/dist/__tests__/capacity/boundaries.test.js +45 -0
  16. package/dist/__tests__/capacity/boundaries.test.js.map +1 -0
  17. package/dist/__tests__/capacity/claude.test.js +3 -3
  18. package/dist/__tests__/capacity/claude.test.js.map +1 -1
  19. package/dist/__tests__/capacity/codex.test.js +3 -1
  20. package/dist/__tests__/capacity/codex.test.js.map +1 -1
  21. package/dist/__tests__/capacity/openai.test.js +32 -25
  22. package/dist/__tests__/capacity/openai.test.js.map +1 -1
  23. package/dist/__tests__/capacity/wham.test.js +1 -1
  24. package/dist/__tests__/capacity/wham.test.js.map +1 -1
  25. package/dist/__tests__/capacity/zai.test.js +7 -8
  26. package/dist/__tests__/capacity/zai.test.js.map +1 -1
  27. package/dist/__tests__/harnesses/BoundedSummarySkip.test.js +568 -0
  28. package/dist/__tests__/harnesses/BoundedSummarySkip.test.js.map +1 -0
  29. package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js +1089 -0
  30. package/dist/__tests__/harnesses/SessionSummaryEquivalence.test.js.map +1 -0
  31. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js +143 -0
  32. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.js.map +1 -0
  33. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js +462 -0
  34. package/dist/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.js.map +1 -0
  35. package/dist/__tests__/harnesses/builtinAdapters.test.js +33 -0
  36. package/dist/__tests__/harnesses/builtinAdapters.test.js.map +1 -0
  37. package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js +79 -0
  38. package/dist/__tests__/harnesses/claude/ClaudeAgentMapper.test.js.map +1 -0
  39. package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js +1881 -0
  40. package/dist/__tests__/harnesses/claude/ClaudeCodeAdapter.test.js.map +1 -0
  41. package/dist/__tests__/harnesses/claude/ClaudeSessionLocator.test.js +425 -0
  42. package/dist/__tests__/harnesses/claude/ClaudeSessionLocator.test.js.map +1 -0
  43. package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js +314 -0
  44. package/dist/__tests__/harnesses/claude/ClaudeSessionParser.test.js.map +1 -0
  45. package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js +49 -0
  46. package/dist/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.js.map +1 -0
  47. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js +76 -0
  48. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.js.map +1 -0
  49. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js +173 -0
  50. package/dist/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.js.map +1 -0
  51. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js +181 -0
  52. package/dist/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.js.map +1 -0
  53. package/dist/__tests__/harnesses/codex/CodexAdapter.test.js +685 -0
  54. package/dist/__tests__/harnesses/codex/CodexAdapter.test.js.map +1 -0
  55. package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js +463 -0
  56. package/dist/__tests__/harnesses/codex/CodexSessionLocator.test.js.map +1 -0
  57. package/dist/__tests__/harnesses/codex/CodexSessionMapping.test.js +86 -0
  58. package/dist/__tests__/harnesses/codex/CodexSessionMapping.test.js.map +1 -0
  59. package/dist/__tests__/harnesses/codex/CodexSessionParser.test.js +254 -0
  60. package/dist/__tests__/harnesses/codex/CodexSessionParser.test.js.map +1 -0
  61. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js +121 -0
  62. package/dist/__tests__/harnesses/codex/durable/CodexCliProbe.test.js.map +1 -0
  63. package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js +84 -0
  64. package/dist/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.js.map +1 -0
  65. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js +128 -0
  66. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.js.map +1 -0
  67. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js +246 -0
  68. package/dist/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.js.map +1 -0
  69. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js +384 -0
  70. package/dist/__tests__/harnesses/codex/durable/CodexPrintRunner.test.js.map +1 -0
  71. package/dist/__tests__/harnesses/copilot/CopilotAdapter.test.js +659 -0
  72. package/dist/__tests__/harnesses/copilot/CopilotAdapter.test.js.map +1 -0
  73. package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js +290 -0
  74. package/dist/__tests__/harnesses/copilot/CopilotRefreshIO.test.js.map +1 -0
  75. package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js +1443 -0
  76. package/dist/__tests__/harnesses/gemini/GeminiCliAdapter.test.js.map +1 -0
  77. package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js +491 -0
  78. package/dist/__tests__/harnesses/gemini/GeminiSessionJsonl.test.js.map +1 -0
  79. package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js +399 -0
  80. package/dist/__tests__/harnesses/gemini/GeminiSessionLocator.test.js.map +1 -0
  81. package/dist/__tests__/harnesses/grok/GrokAgentMapper.test.js +56 -0
  82. package/dist/__tests__/harnesses/grok/GrokAgentMapper.test.js.map +1 -0
  83. package/dist/__tests__/harnesses/grok/GrokCliAdapter.test.js +421 -0
  84. package/dist/__tests__/harnesses/grok/GrokCliAdapter.test.js.map +1 -0
  85. package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js +167 -0
  86. package/dist/__tests__/harnesses/grok/GrokIncrementalRefresh.test.js.map +1 -0
  87. package/dist/__tests__/harnesses/grok/GrokSessionLocator.test.js +133 -0
  88. package/dist/__tests__/harnesses/grok/GrokSessionLocator.test.js.map +1 -0
  89. package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js +301 -0
  90. package/dist/__tests__/harnesses/grok/GrokSessionParser.test.js.map +1 -0
  91. package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js +662 -0
  92. package/dist/__tests__/harnesses/kiro/KiroAdapter.test.js.map +1 -0
  93. package/dist/__tests__/harnesses/opencode/OpenCodeAdapter.test.js +213 -0
  94. package/dist/__tests__/harnesses/opencode/OpenCodeAdapter.test.js.map +1 -0
  95. package/dist/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.js +89 -0
  96. package/dist/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.js.map +1 -0
  97. package/dist/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.js +94 -0
  98. package/dist/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.js.map +1 -0
  99. package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js +147 -0
  100. package/dist/__tests__/harnesses/opencode/OpenCodeSessionParser.test.js.map +1 -0
  101. package/dist/__tests__/harnesses/pi/PiAdapter.test.js +367 -0
  102. package/dist/__tests__/harnesses/pi/PiAdapter.test.js.map +1 -0
  103. package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js +382 -0
  104. package/dist/__tests__/harnesses/pi/PiDiscoveryIO.test.js.map +1 -0
  105. package/dist/__tests__/harnesses/pi/PiSessionParser.test.js +416 -0
  106. package/dist/__tests__/harnesses/pi/PiSessionParser.test.js.map +1 -0
  107. package/dist/__tests__/harnesses/pi/PiSessionTracker.test.js +108 -0
  108. package/dist/__tests__/harnesses/pi/PiSessionTracker.test.js.map +1 -0
  109. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js +70 -0
  110. package/dist/__tests__/harnesses/pi/durable/PiCliProbe.test.js.map +1 -0
  111. package/dist/__tests__/harnesses/pi/durable/PiDurableAgentRepository.test.js.map +1 -0
  112. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js +192 -0
  113. package/dist/__tests__/harnesses/pi/durable/PiPrintAgentService.test.js.map +1 -0
  114. package/dist/__tests__/harnesses/pi/durable/PiPrintProtocol.test.js +119 -0
  115. package/dist/__tests__/harnesses/pi/durable/PiPrintProtocol.test.js.map +1 -0
  116. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js +382 -0
  117. package/dist/__tests__/harnesses/pi/durable/PiPrintRunner.test.js.map +1 -0
  118. package/dist/__tests__/harnesses/pi/durable/PiStreamParser.test.js +34 -0
  119. package/dist/__tests__/harnesses/pi/durable/PiStreamParser.test.js.map +1 -0
  120. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js +342 -0
  121. package/dist/__tests__/harnesses/readiness/AgentReadiness.test.js.map +1 -0
  122. package/dist/__tests__/harnesses/runtimeProfiles.test.js +89 -0
  123. package/dist/__tests__/harnesses/runtimeProfiles.test.js.map +1 -0
  124. package/dist/__tests__/print/DurableAgent.test.js +4 -6
  125. package/dist/__tests__/print/DurableAgent.test.js.map +1 -1
  126. package/dist/__tests__/print/DurableAgentRepository.test.js +1 -12
  127. package/dist/__tests__/print/DurableAgentRepository.test.js.map +1 -1
  128. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js +49 -0
  129. package/dist/__tests__/runtime/ManagedAgentRuntime.test.js.map +1 -1
  130. package/dist/__tests__/terminal/TmuxManager.test.js +1 -1
  131. package/dist/__tests__/terminal/TmuxManager.test.js.map +1 -1
  132. package/dist/__tests__/utils/IncrementalJsonlSummary.test.js +650 -0
  133. package/dist/__tests__/utils/IncrementalJsonlSummary.test.js.map +1 -0
  134. package/dist/__tests__/utils/conversationTail.bench.test.js +258 -0
  135. package/dist/__tests__/utils/conversationTail.bench.test.js.map +1 -0
  136. package/dist/__tests__/utils/conversationTailParity.test.js +588 -0
  137. package/dist/__tests__/utils/conversationTailParity.test.js.map +1 -0
  138. package/dist/__tests__/utils/jsonlTail.test.js +360 -0
  139. package/dist/__tests__/utils/jsonlTail.test.js.map +1 -0
  140. package/dist/__tests__/utils/matchingConstants.test.js +35 -0
  141. package/dist/__tests__/utils/matchingConstants.test.js.map +1 -0
  142. package/dist/__tests__/utils/process.test.js +436 -2
  143. package/dist/__tests__/utils/process.test.js.map +1 -1
  144. package/dist/adapters/AgentAdapter.d.ts +25 -6
  145. package/dist/adapters/AgentAdapter.d.ts.map +1 -1
  146. package/dist/adapters/AgentAdapter.js +12 -3
  147. package/dist/adapters/AgentAdapter.js.map +1 -1
  148. package/dist/capacity/index.d.ts +9 -19
  149. package/dist/capacity/index.d.ts.map +1 -1
  150. package/dist/capacity/index.js +11 -4
  151. package/dist/capacity/index.js.map +1 -1
  152. package/dist/capacity/providers/anthropic.d.ts +9 -0
  153. package/dist/capacity/providers/anthropic.d.ts.map +1 -0
  154. package/dist/capacity/providers/anthropic.js +153 -0
  155. package/dist/capacity/providers/anthropic.js.map +1 -0
  156. package/dist/capacity/providers/openai-platform.d.ts +14 -0
  157. package/dist/capacity/providers/openai-platform.d.ts.map +1 -0
  158. package/dist/capacity/providers/openai-platform.js +120 -0
  159. package/dist/capacity/providers/openai-platform.js.map +1 -0
  160. package/dist/capacity/providers/openai-subscription.d.ts +20 -0
  161. package/dist/capacity/providers/openai-subscription.d.ts.map +1 -0
  162. package/dist/capacity/providers/openai-subscription.js +129 -0
  163. package/dist/capacity/providers/openai-subscription.js.map +1 -0
  164. package/dist/capacity/providers/zai.d.ts +8 -0
  165. package/dist/capacity/providers/zai.d.ts.map +1 -0
  166. package/dist/capacity/providers/zai.js +158 -0
  167. package/dist/capacity/providers/zai.js.map +1 -0
  168. package/dist/capacity/sources/claude.d.ts +9 -0
  169. package/dist/capacity/sources/claude.d.ts.map +1 -0
  170. package/dist/capacity/sources/claude.js +17 -0
  171. package/dist/capacity/sources/claude.js.map +1 -0
  172. package/dist/capacity/sources/codex.d.ts +32 -0
  173. package/dist/capacity/sources/codex.d.ts.map +1 -0
  174. package/dist/capacity/sources/codex.js +227 -0
  175. package/dist/capacity/sources/codex.js.map +1 -0
  176. package/dist/capacity/sources/pi.d.ts +30 -0
  177. package/dist/capacity/sources/pi.d.ts.map +1 -0
  178. package/dist/capacity/sources/pi.js +81 -0
  179. package/dist/capacity/sources/pi.js.map +1 -0
  180. package/dist/capacity/types.d.ts +2 -0
  181. package/dist/capacity/types.d.ts.map +1 -1
  182. package/dist/capacity/types.js +1 -1
  183. package/dist/capacity/types.js.map +1 -1
  184. package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts +13 -0
  185. package/dist/harnesses/antigravity/AntigravityAgentMapper.d.ts.map +1 -0
  186. package/dist/harnesses/antigravity/AntigravityAgentMapper.js +30 -0
  187. package/dist/harnesses/antigravity/AntigravityAgentMapper.js.map +1 -0
  188. package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts +32 -0
  189. package/dist/harnesses/antigravity/AntigravityCliAdapter.d.ts.map +1 -0
  190. package/dist/harnesses/antigravity/AntigravityCliAdapter.js +97 -0
  191. package/dist/harnesses/antigravity/AntigravityCliAdapter.js.map +1 -0
  192. package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts +30 -0
  193. package/dist/harnesses/antigravity/AntigravitySessionLocator.d.ts.map +1 -0
  194. package/dist/harnesses/antigravity/AntigravitySessionLocator.js +56 -0
  195. package/dist/harnesses/antigravity/AntigravitySessionLocator.js.map +1 -0
  196. package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts +75 -0
  197. package/dist/harnesses/antigravity/AntigravitySessionParser.d.ts.map +1 -0
  198. package/dist/harnesses/antigravity/AntigravitySessionParser.js +174 -0
  199. package/dist/harnesses/antigravity/AntigravitySessionParser.js.map +1 -0
  200. package/dist/harnesses/claude/ClaudeAgentMapper.d.ts.map +1 -0
  201. package/dist/harnesses/claude/ClaudeAgentMapper.js +36 -0
  202. package/dist/harnesses/claude/ClaudeAgentMapper.js.map +1 -0
  203. package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts +30 -0
  204. package/dist/harnesses/claude/ClaudeCodeAdapter.d.ts.map +1 -0
  205. package/dist/harnesses/claude/ClaudeCodeAdapter.js +134 -0
  206. package/dist/harnesses/claude/ClaudeCodeAdapter.js.map +1 -0
  207. package/dist/harnesses/claude/ClaudeSessionLocator.d.ts.map +1 -0
  208. package/dist/harnesses/claude/ClaudeSessionLocator.js +260 -0
  209. package/dist/harnesses/claude/ClaudeSessionLocator.js.map +1 -0
  210. package/dist/harnesses/claude/ClaudeSessionParser.d.ts +148 -0
  211. package/dist/harnesses/claude/ClaudeSessionParser.d.ts.map +1 -0
  212. package/dist/harnesses/claude/ClaudeSessionParser.js +365 -0
  213. package/dist/harnesses/claude/ClaudeSessionParser.js.map +1 -0
  214. package/dist/harnesses/claude/credentials.d.ts +10 -0
  215. package/dist/harnesses/claude/credentials.d.ts.map +1 -0
  216. package/dist/harnesses/claude/credentials.js +112 -0
  217. package/dist/harnesses/claude/credentials.js.map +1 -0
  218. package/dist/harnesses/claude/durable/ClaudeCliProbe.d.ts.map +1 -0
  219. package/dist/harnesses/claude/durable/ClaudeCliProbe.js.map +1 -0
  220. package/dist/harnesses/claude/durable/ClaudePrintAgentService.d.ts.map +1 -0
  221. package/dist/harnesses/claude/durable/ClaudePrintAgentService.js.map +1 -0
  222. package/dist/harnesses/claude/durable/ClaudePrintRunner.d.ts.map +1 -0
  223. package/dist/harnesses/claude/durable/ClaudePrintRunner.js.map +1 -0
  224. package/dist/harnesses/claude/durable/ClaudeStreamParser.d.ts.map +1 -0
  225. package/dist/harnesses/claude/durable/ClaudeStreamParser.js.map +1 -0
  226. package/dist/harnesses/claude/readiness.d.ts +3 -0
  227. package/dist/harnesses/claude/readiness.d.ts.map +1 -0
  228. package/dist/harnesses/claude/readiness.js +63 -0
  229. package/dist/harnesses/claude/readiness.js.map +1 -0
  230. package/dist/harnesses/codex/CodexAdapter.d.ts +29 -0
  231. package/dist/harnesses/codex/CodexAdapter.d.ts.map +1 -0
  232. package/dist/harnesses/codex/CodexAdapter.js +290 -0
  233. package/dist/harnesses/codex/CodexAdapter.js.map +1 -0
  234. package/dist/harnesses/codex/CodexAgentMapper.d.ts.map +1 -0
  235. package/dist/harnesses/codex/CodexAgentMapper.js +28 -0
  236. package/dist/harnesses/codex/CodexAgentMapper.js.map +1 -0
  237. package/dist/harnesses/codex/CodexSessionLocator.d.ts +74 -0
  238. package/dist/harnesses/codex/CodexSessionLocator.d.ts.map +1 -0
  239. package/dist/harnesses/codex/CodexSessionLocator.js +359 -0
  240. package/dist/harnesses/codex/CodexSessionLocator.js.map +1 -0
  241. package/dist/harnesses/codex/CodexSessionMapping.d.ts.map +1 -0
  242. package/dist/harnesses/codex/CodexSessionMapping.js +68 -0
  243. package/dist/harnesses/codex/CodexSessionMapping.js.map +1 -0
  244. package/dist/harnesses/codex/CodexSessionParser.d.ts +89 -0
  245. package/dist/harnesses/codex/CodexSessionParser.d.ts.map +1 -0
  246. package/dist/harnesses/codex/CodexSessionParser.js +308 -0
  247. package/dist/harnesses/codex/CodexSessionParser.js.map +1 -0
  248. package/dist/harnesses/codex/credentials.d.ts +15 -0
  249. package/dist/harnesses/codex/credentials.d.ts.map +1 -0
  250. package/dist/harnesses/codex/credentials.js +58 -0
  251. package/dist/harnesses/codex/credentials.js.map +1 -0
  252. package/dist/harnesses/codex/durable/CodexCliProbe.d.ts.map +1 -0
  253. package/dist/harnesses/codex/durable/CodexCliProbe.js.map +1 -0
  254. package/dist/harnesses/codex/durable/CodexPrintAgentService.d.ts.map +1 -0
  255. package/dist/harnesses/codex/durable/CodexPrintAgentService.js.map +1 -0
  256. package/dist/harnesses/codex/durable/CodexPrintRunner.d.ts.map +1 -0
  257. package/dist/harnesses/codex/durable/CodexPrintRunner.js.map +1 -0
  258. package/dist/harnesses/codex/durable/CodexStreamParser.d.ts.map +1 -0
  259. package/dist/harnesses/codex/durable/CodexStreamParser.js.map +1 -0
  260. package/dist/harnesses/codex/readiness.d.ts +3 -0
  261. package/dist/harnesses/codex/readiness.d.ts.map +1 -0
  262. package/dist/harnesses/codex/readiness.js +60 -0
  263. package/dist/harnesses/codex/readiness.js.map +1 -0
  264. package/dist/harnesses/copilot/CopilotAdapter.d.ts +36 -0
  265. package/dist/harnesses/copilot/CopilotAdapter.d.ts.map +1 -0
  266. package/dist/harnesses/copilot/CopilotAdapter.js +128 -0
  267. package/dist/harnesses/copilot/CopilotAdapter.js.map +1 -0
  268. package/dist/harnesses/copilot/CopilotAgentMapper.d.ts.map +1 -0
  269. package/dist/harnesses/copilot/CopilotAgentMapper.js +30 -0
  270. package/dist/harnesses/copilot/CopilotAgentMapper.js.map +1 -0
  271. package/dist/harnesses/copilot/CopilotSessionLocator.d.ts +42 -0
  272. package/dist/harnesses/copilot/CopilotSessionLocator.d.ts.map +1 -0
  273. package/dist/harnesses/copilot/CopilotSessionLocator.js +126 -0
  274. package/dist/harnesses/copilot/CopilotSessionLocator.js.map +1 -0
  275. package/dist/harnesses/copilot/CopilotSessionParser.d.ts +62 -0
  276. package/dist/harnesses/copilot/CopilotSessionParser.d.ts.map +1 -0
  277. package/dist/harnesses/copilot/CopilotSessionParser.js +236 -0
  278. package/dist/harnesses/copilot/CopilotSessionParser.js.map +1 -0
  279. package/dist/harnesses/copilot/readiness.d.ts +3 -0
  280. package/dist/harnesses/copilot/readiness.d.ts.map +1 -0
  281. package/dist/harnesses/copilot/readiness.js +39 -0
  282. package/dist/harnesses/copilot/readiness.js.map +1 -0
  283. package/dist/harnesses/gemini/GeminiAgentMapper.d.ts.map +1 -0
  284. package/dist/harnesses/gemini/GeminiAgentMapper.js +30 -0
  285. package/dist/harnesses/gemini/GeminiAgentMapper.js.map +1 -0
  286. package/dist/harnesses/gemini/GeminiCliAdapter.d.ts +52 -0
  287. package/dist/harnesses/gemini/GeminiCliAdapter.d.ts.map +1 -0
  288. package/dist/harnesses/gemini/GeminiCliAdapter.js +196 -0
  289. package/dist/harnesses/gemini/GeminiCliAdapter.js.map +1 -0
  290. package/dist/harnesses/gemini/GeminiSessionLocator.d.ts +72 -0
  291. package/dist/harnesses/gemini/GeminiSessionLocator.d.ts.map +1 -0
  292. package/dist/harnesses/gemini/GeminiSessionLocator.js +300 -0
  293. package/dist/harnesses/gemini/GeminiSessionLocator.js.map +1 -0
  294. package/dist/harnesses/gemini/GeminiSessionParser.d.ts +121 -0
  295. package/dist/harnesses/gemini/GeminiSessionParser.d.ts.map +1 -0
  296. package/dist/harnesses/gemini/GeminiSessionParser.js +272 -0
  297. package/dist/harnesses/gemini/GeminiSessionParser.js.map +1 -0
  298. package/dist/harnesses/gemini/fileSignature.d.ts +8 -0
  299. package/dist/harnesses/gemini/fileSignature.d.ts.map +1 -0
  300. package/dist/harnesses/gemini/fileSignature.js +9 -0
  301. package/dist/harnesses/gemini/fileSignature.js.map +1 -0
  302. package/dist/harnesses/grok/GrokAgentMapper.d.ts.map +1 -0
  303. package/dist/harnesses/grok/GrokAgentMapper.js +30 -0
  304. package/dist/harnesses/grok/GrokAgentMapper.js.map +1 -0
  305. package/dist/harnesses/grok/GrokCliAdapter.d.ts +36 -0
  306. package/dist/harnesses/grok/GrokCliAdapter.d.ts.map +1 -0
  307. package/dist/harnesses/grok/GrokCliAdapter.js +102 -0
  308. package/dist/harnesses/grok/GrokCliAdapter.js.map +1 -0
  309. package/dist/harnesses/grok/GrokSessionLocator.d.ts.map +1 -0
  310. package/dist/harnesses/grok/GrokSessionLocator.js +140 -0
  311. package/dist/harnesses/grok/GrokSessionLocator.js.map +1 -0
  312. package/dist/harnesses/grok/GrokSessionParser.d.ts +87 -0
  313. package/dist/harnesses/grok/GrokSessionParser.d.ts.map +1 -0
  314. package/dist/harnesses/grok/GrokSessionParser.js +185 -0
  315. package/dist/harnesses/grok/GrokSessionParser.js.map +1 -0
  316. package/dist/harnesses/index.d.ts +7 -0
  317. package/dist/harnesses/index.d.ts.map +1 -0
  318. package/dist/harnesses/index.js +27 -0
  319. package/dist/harnesses/index.js.map +1 -0
  320. package/dist/harnesses/kiro/KiroAdapter.d.ts +31 -0
  321. package/dist/harnesses/kiro/KiroAdapter.d.ts.map +1 -0
  322. package/dist/harnesses/kiro/KiroAdapter.js +125 -0
  323. package/dist/harnesses/kiro/KiroAdapter.js.map +1 -0
  324. package/dist/harnesses/kiro/KiroAgentMapper.d.ts +13 -0
  325. package/dist/harnesses/kiro/KiroAgentMapper.d.ts.map +1 -0
  326. package/dist/harnesses/kiro/KiroAgentMapper.js +29 -0
  327. package/dist/harnesses/kiro/KiroAgentMapper.js.map +1 -0
  328. package/dist/harnesses/kiro/KiroSessionLocator.d.ts +38 -0
  329. package/dist/harnesses/kiro/KiroSessionLocator.d.ts.map +1 -0
  330. package/dist/harnesses/kiro/KiroSessionLocator.js +95 -0
  331. package/dist/harnesses/kiro/KiroSessionLocator.js.map +1 -0
  332. package/dist/harnesses/kiro/KiroSessionParser.d.ts +81 -0
  333. package/dist/harnesses/kiro/KiroSessionParser.d.ts.map +1 -0
  334. package/dist/harnesses/kiro/KiroSessionParser.js +251 -0
  335. package/dist/harnesses/kiro/KiroSessionParser.js.map +1 -0
  336. package/dist/harnesses/opencode/OpenCodeAdapter.d.ts +29 -0
  337. package/dist/harnesses/opencode/OpenCodeAdapter.d.ts.map +1 -0
  338. package/dist/harnesses/opencode/OpenCodeAdapter.js +86 -0
  339. package/dist/harnesses/opencode/OpenCodeAdapter.js.map +1 -0
  340. package/dist/harnesses/opencode/OpenCodeAgentMapper.d.ts.map +1 -0
  341. package/dist/harnesses/opencode/OpenCodeAgentMapper.js +42 -0
  342. package/dist/harnesses/opencode/OpenCodeAgentMapper.js.map +1 -0
  343. package/dist/harnesses/opencode/OpenCodeSessionLocator.d.ts.map +1 -0
  344. package/dist/harnesses/opencode/OpenCodeSessionLocator.js +118 -0
  345. package/dist/harnesses/opencode/OpenCodeSessionLocator.js.map +1 -0
  346. package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts +16 -0
  347. package/dist/harnesses/opencode/OpenCodeSessionParser.d.ts.map +1 -0
  348. package/dist/harnesses/opencode/OpenCodeSessionParser.js +105 -0
  349. package/dist/harnesses/opencode/OpenCodeSessionParser.js.map +1 -0
  350. package/dist/harnesses/opencode/readiness.d.ts +3 -0
  351. package/dist/harnesses/opencode/readiness.d.ts.map +1 -0
  352. package/dist/harnesses/opencode/readiness.js +50 -0
  353. package/dist/harnesses/opencode/readiness.js.map +1 -0
  354. package/dist/harnesses/pi/PiAdapter.d.ts +30 -0
  355. package/dist/harnesses/pi/PiAdapter.d.ts.map +1 -0
  356. package/dist/harnesses/pi/PiAdapter.js +167 -0
  357. package/dist/harnesses/pi/PiAdapter.js.map +1 -0
  358. package/dist/harnesses/pi/PiAgentMapper.d.ts.map +1 -0
  359. package/dist/harnesses/pi/PiAgentMapper.js +30 -0
  360. package/dist/harnesses/pi/PiAgentMapper.js.map +1 -0
  361. package/dist/harnesses/pi/PiSessionLocator.d.ts +61 -0
  362. package/dist/harnesses/pi/PiSessionLocator.d.ts.map +1 -0
  363. package/dist/harnesses/pi/PiSessionLocator.js +212 -0
  364. package/dist/harnesses/pi/PiSessionLocator.js.map +1 -0
  365. package/dist/harnesses/pi/PiSessionParser.d.ts +88 -0
  366. package/dist/harnesses/pi/PiSessionParser.d.ts.map +1 -0
  367. package/dist/harnesses/pi/PiSessionParser.js +318 -0
  368. package/dist/harnesses/pi/PiSessionParser.js.map +1 -0
  369. package/dist/harnesses/pi/PiSessionTracker.d.ts.map +1 -0
  370. package/dist/harnesses/pi/PiSessionTracker.js +69 -0
  371. package/dist/harnesses/pi/PiSessionTracker.js.map +1 -0
  372. package/dist/harnesses/pi/credentials.d.ts +22 -0
  373. package/dist/harnesses/pi/credentials.d.ts.map +1 -0
  374. package/dist/harnesses/pi/credentials.js +98 -0
  375. package/dist/harnesses/pi/credentials.js.map +1 -0
  376. package/dist/harnesses/pi/durable/PiCliProbe.d.ts.map +1 -0
  377. package/dist/harnesses/pi/durable/PiCliProbe.js.map +1 -0
  378. package/dist/harnesses/pi/durable/PiPrintAgentService.d.ts.map +1 -0
  379. package/dist/harnesses/pi/durable/PiPrintAgentService.js.map +1 -0
  380. package/dist/harnesses/pi/durable/PiPrintProtocol.d.ts.map +1 -0
  381. package/dist/harnesses/pi/durable/PiPrintProtocol.js.map +1 -0
  382. package/dist/harnesses/pi/durable/PiPrintRunner.d.ts.map +1 -0
  383. package/dist/harnesses/pi/durable/PiPrintRunner.js.map +1 -0
  384. package/dist/harnesses/pi/durable/PiStreamParser.d.ts.map +1 -0
  385. package/dist/harnesses/pi/durable/PiStreamParser.js.map +1 -0
  386. package/dist/harnesses/pi/readiness.d.ts +3 -0
  387. package/dist/harnesses/pi/readiness.d.ts.map +1 -0
  388. package/dist/harnesses/pi/readiness.js +96 -0
  389. package/dist/harnesses/pi/readiness.js.map +1 -0
  390. package/dist/harnesses/readiness/AgentReadiness.d.ts +6 -0
  391. package/dist/harnesses/readiness/AgentReadiness.d.ts.map +1 -0
  392. package/dist/harnesses/readiness/AgentReadiness.js +68 -0
  393. package/dist/harnesses/readiness/AgentReadiness.js.map +1 -0
  394. package/dist/harnesses/readiness/checks.d.ts +31 -0
  395. package/dist/harnesses/readiness/checks.d.ts.map +1 -0
  396. package/dist/harnesses/readiness/checks.js +270 -0
  397. package/dist/harnesses/readiness/checks.js.map +1 -0
  398. package/dist/harnesses/readiness/types.d.ts +76 -0
  399. package/dist/harnesses/readiness/types.d.ts.map +1 -0
  400. package/dist/harnesses/readiness/types.js +4 -0
  401. package/dist/harnesses/readiness/types.js.map +1 -0
  402. package/dist/harnesses/runtimeProfiles.d.ts +11 -0
  403. package/dist/harnesses/runtimeProfiles.d.ts.map +1 -0
  404. package/dist/harnesses/runtimeProfiles.js +99 -0
  405. package/dist/harnesses/runtimeProfiles.js.map +1 -0
  406. package/dist/harnesses/shared.d.ts +41 -0
  407. package/dist/harnesses/shared.d.ts.map +1 -0
  408. package/dist/harnesses/shared.js +71 -0
  409. package/dist/harnesses/shared.js.map +1 -0
  410. package/dist/index.d.ts +21 -46
  411. package/dist/index.d.ts.map +1 -1
  412. package/dist/index.js +14 -27
  413. package/dist/index.js.map +1 -1
  414. package/dist/runtime/ManagedAgentRuntime.d.ts +3 -3
  415. package/dist/runtime/ManagedAgentRuntime.d.ts.map +1 -1
  416. package/dist/runtime/ManagedAgentRuntime.js +6 -20
  417. package/dist/runtime/ManagedAgentRuntime.js.map +1 -1
  418. package/dist/runtime/herdr/HerdrAgentDiscovery.d.ts.map +1 -1
  419. package/dist/runtime/herdr/HerdrAgentDiscovery.js +2 -43
  420. package/dist/runtime/herdr/HerdrAgentDiscovery.js.map +1 -1
  421. package/dist/runtime/tmux/PidPolling.d.ts +1 -1
  422. package/dist/runtime/tmux/PidPolling.d.ts.map +1 -1
  423. package/dist/runtime/tmux/PidPolling.js.map +1 -1
  424. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts +1 -1
  425. package/dist/runtime/tmux/TmuxAgentRuntime.d.ts.map +1 -1
  426. package/dist/runtime/tmux/TmuxAgentRuntime.js +1 -1
  427. package/dist/runtime/tmux/TmuxAgentRuntime.js.map +1 -1
  428. package/dist/runtime/tmux/TmuxManager.d.ts +12 -0
  429. package/dist/runtime/tmux/TmuxManager.d.ts.map +1 -0
  430. package/dist/runtime/tmux/TmuxManager.js +116 -0
  431. package/dist/runtime/tmux/TmuxManager.js.map +1 -0
  432. package/dist/runtime/types.d.ts +1 -1
  433. package/dist/runtime/types.d.ts.map +1 -1
  434. package/dist/runtime/types.js.map +1 -1
  435. package/dist/terminal/TerminalFocusManager.d.ts +4 -32
  436. package/dist/terminal/TerminalFocusManager.d.ts.map +1 -1
  437. package/dist/terminal/TerminalFocusManager.js +17 -267
  438. package/dist/terminal/TerminalFocusManager.js.map +1 -1
  439. package/dist/terminal/TtyWriter.d.ts +1 -44
  440. package/dist/terminal/TtyWriter.d.ts.map +1 -1
  441. package/dist/terminal/TtyWriter.js +11 -347
  442. package/dist/terminal/TtyWriter.js.map +1 -1
  443. package/dist/terminal/backends/index.d.ts +5 -0
  444. package/dist/terminal/backends/index.d.ts.map +1 -0
  445. package/dist/terminal/backends/index.js +19 -0
  446. package/dist/terminal/backends/index.js.map +1 -0
  447. package/dist/terminal/backends/iterm2.d.ts +3 -0
  448. package/dist/terminal/backends/iterm2.d.ts.map +1 -0
  449. package/dist/terminal/backends/iterm2.js +135 -0
  450. package/dist/terminal/backends/iterm2.js.map +1 -0
  451. package/dist/terminal/backends/shared.d.ts +7 -0
  452. package/dist/terminal/backends/shared.d.ts.map +1 -0
  453. package/dist/terminal/backends/shared.js +35 -0
  454. package/dist/terminal/backends/shared.js.map +1 -0
  455. package/dist/terminal/backends/terminal-app.d.ts +3 -0
  456. package/dist/terminal/backends/terminal-app.d.ts.map +1 -0
  457. package/dist/terminal/backends/terminal-app.js +129 -0
  458. package/dist/terminal/backends/terminal-app.js.map +1 -0
  459. package/dist/terminal/backends/tmux.d.ts +3 -0
  460. package/dist/terminal/backends/tmux.d.ts.map +1 -0
  461. package/dist/terminal/backends/tmux.js +76 -0
  462. package/dist/terminal/backends/tmux.js.map +1 -0
  463. package/dist/terminal/backends/wezterm.d.ts +3 -0
  464. package/dist/terminal/backends/wezterm.d.ts.map +1 -0
  465. package/dist/terminal/backends/wezterm.js +71 -0
  466. package/dist/terminal/backends/wezterm.js.map +1 -0
  467. package/dist/terminal/types.d.ts +21 -0
  468. package/dist/terminal/types.d.ts.map +1 -0
  469. package/dist/terminal/types.js +10 -0
  470. package/dist/terminal/types.js.map +1 -0
  471. package/dist/utils/IncrementalJsonlSummary.d.ts +100 -0
  472. package/dist/utils/IncrementalJsonlSummary.d.ts.map +1 -0
  473. package/dist/utils/IncrementalJsonlSummary.js +209 -0
  474. package/dist/utils/IncrementalJsonlSummary.js.map +1 -0
  475. package/dist/utils/jsonlTail.d.ts +73 -0
  476. package/dist/utils/jsonlTail.d.ts.map +1 -0
  477. package/dist/utils/jsonlTail.js +238 -0
  478. package/dist/utils/jsonlTail.js.map +1 -0
  479. package/dist/utils/matching.d.ts +2 -0
  480. package/dist/utils/matching.d.ts.map +1 -1
  481. package/dist/utils/matching.js +3 -2
  482. package/dist/utils/matching.js.map +1 -1
  483. package/dist/utils/matchingConstants.d.ts +15 -0
  484. package/dist/utils/matchingConstants.d.ts.map +1 -0
  485. package/dist/utils/matchingConstants.js +14 -0
  486. package/dist/utils/matchingConstants.js.map +1 -0
  487. package/dist/utils/process.d.ts +38 -2
  488. package/dist/utils/process.d.ts.map +1 -1
  489. package/dist/utils/process.js +131 -43
  490. package/dist/utils/process.js.map +1 -1
  491. package/package.json +2 -1
  492. package/scripts/benchmark-cold-start.mjs +350 -0
  493. package/src/AgentManager.ts +27 -6
  494. package/src/__tests__/AgentManager.test.ts +141 -3
  495. package/src/__tests__/adapters/IncrementalSessionRefresh.test.ts +437 -0
  496. package/src/__tests__/adapters/adapterProcessImports.test.ts +58 -0
  497. package/src/__tests__/adapters/adapterSnapshotCandidates.test.ts +243 -0
  498. package/src/__tests__/capacity/anthropic.test.ts +105 -0
  499. package/src/__tests__/capacity/boundaries.test.ts +36 -0
  500. package/src/__tests__/capacity/claude.test.ts +3 -8
  501. package/src/__tests__/capacity/codex.test.ts +12 -35
  502. package/src/__tests__/capacity/fixtures/openai-codex-auth.json +1 -1
  503. package/src/__tests__/capacity/openai.test.ts +20 -30
  504. package/src/__tests__/capacity/wham.test.ts +1 -1
  505. package/src/__tests__/capacity/zai.test.ts +27 -62
  506. package/src/__tests__/harnesses/BoundedSummarySkip.test.ts +496 -0
  507. package/src/__tests__/harnesses/SessionSummaryEquivalence.test.ts +726 -0
  508. package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.subprocess.test.ts +133 -0
  509. package/src/__tests__/harnesses/antigravity/AntigravityCliAdapter.test.ts +396 -0
  510. package/src/__tests__/harnesses/builtinAdapters.test.ts +33 -0
  511. package/src/__tests__/harnesses/claude/ClaudeAgentMapper.test.ts +84 -0
  512. package/src/__tests__/harnesses/claude/ClaudeCodeAdapter.test.ts +1793 -0
  513. package/src/__tests__/harnesses/claude/ClaudeSessionLocator.test.ts +423 -0
  514. package/src/__tests__/harnesses/claude/ClaudeSessionParser.test.ts +300 -0
  515. package/src/__tests__/harnesses/claude/durable/ClaudeCliProbe.test.ts +34 -0
  516. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgent.integration.test.ts +61 -0
  517. package/src/__tests__/harnesses/claude/durable/ClaudePrintAgentService.test.ts +129 -0
  518. package/src/__tests__/harnesses/claude/durable/ClaudePrintRunner.test.ts +152 -0
  519. package/src/__tests__/harnesses/codex/CodexAdapter.test.ts +652 -0
  520. package/src/__tests__/harnesses/codex/CodexSessionLocator.test.ts +419 -0
  521. package/src/__tests__/harnesses/codex/CodexSessionMapping.test.ts +63 -0
  522. package/src/__tests__/harnesses/codex/CodexSessionParser.test.ts +192 -0
  523. package/src/__tests__/harnesses/codex/durable/CodexCliProbe.test.ts +80 -0
  524. package/src/__tests__/harnesses/codex/durable/CodexDurableAgentRepository.test.ts +65 -0
  525. package/src/__tests__/harnesses/codex/durable/CodexPrintAgent.integration.test.ts +104 -0
  526. package/src/__tests__/harnesses/codex/durable/CodexPrintAgentService.test.ts +201 -0
  527. package/src/__tests__/harnesses/codex/durable/CodexPrintRunner.test.ts +299 -0
  528. package/src/__tests__/harnesses/copilot/CopilotAdapter.test.ts +614 -0
  529. package/src/__tests__/harnesses/copilot/CopilotRefreshIO.test.ts +270 -0
  530. package/src/__tests__/harnesses/gemini/GeminiCliAdapter.test.ts +1324 -0
  531. package/src/__tests__/harnesses/gemini/GeminiSessionJsonl.test.ts +402 -0
  532. package/src/__tests__/harnesses/gemini/GeminiSessionLocator.test.ts +396 -0
  533. package/src/__tests__/harnesses/grok/GrokAgentMapper.test.ts +57 -0
  534. package/src/__tests__/harnesses/grok/GrokCliAdapter.test.ts +376 -0
  535. package/src/__tests__/harnesses/grok/GrokIncrementalRefresh.test.ts +170 -0
  536. package/src/__tests__/harnesses/grok/GrokSessionLocator.test.ts +106 -0
  537. package/src/__tests__/harnesses/grok/GrokSessionParser.test.ts +230 -0
  538. package/src/__tests__/harnesses/kiro/KiroAdapter.test.ts +552 -0
  539. package/src/__tests__/harnesses/opencode/OpenCodeAdapter.test.ts +215 -0
  540. package/src/__tests__/harnesses/opencode/OpenCodeAgentMapper.test.ts +83 -0
  541. package/src/__tests__/harnesses/opencode/OpenCodeSessionLocator.test.ts +84 -0
  542. package/src/__tests__/harnesses/opencode/OpenCodeSessionParser.test.ts +148 -0
  543. package/src/__tests__/harnesses/pi/PiAdapter.test.ts +325 -0
  544. package/src/__tests__/harnesses/pi/PiDiscoveryIO.test.ts +337 -0
  545. package/src/__tests__/harnesses/pi/PiSessionParser.test.ts +280 -0
  546. package/src/__tests__/harnesses/pi/PiSessionTracker.test.ts +79 -0
  547. package/src/__tests__/harnesses/pi/durable/PiCliProbe.test.ts +50 -0
  548. package/src/__tests__/harnesses/pi/durable/PiPrintAgentService.test.ts +138 -0
  549. package/src/__tests__/harnesses/pi/durable/PiPrintProtocol.test.ts +71 -0
  550. package/src/__tests__/harnesses/pi/durable/PiPrintRunner.test.ts +252 -0
  551. package/src/__tests__/harnesses/pi/durable/PiStreamParser.test.ts +26 -0
  552. package/src/__tests__/harnesses/readiness/AgentReadiness.test.ts +285 -0
  553. package/src/__tests__/harnesses/runtimeProfiles.test.ts +110 -0
  554. package/src/__tests__/print/DurableAgent.test.ts +4 -13
  555. package/src/__tests__/print/DurableAgentRepository.test.ts +1 -13
  556. package/src/__tests__/runtime/ManagedAgentRuntime.test.ts +31 -1
  557. package/src/__tests__/terminal/TmuxManager.test.ts +1 -1
  558. package/src/__tests__/utils/IncrementalJsonlSummary.test.ts +414 -0
  559. package/src/__tests__/utils/conversationTail.bench.test.ts +193 -0
  560. package/src/__tests__/utils/conversationTailParity.test.ts +365 -0
  561. package/src/__tests__/utils/jsonlTail.test.ts +317 -0
  562. package/src/__tests__/utils/matchingConstants.test.ts +40 -0
  563. package/src/__tests__/utils/process.test.ts +254 -0
  564. package/src/adapters/AgentAdapter.ts +37 -14
  565. package/src/capacity/index.ts +29 -23
  566. package/src/capacity/providers/anthropic.ts +198 -0
  567. package/src/capacity/providers/openai-platform.ts +150 -0
  568. package/src/capacity/providers/openai-subscription.ts +162 -0
  569. package/src/capacity/providers/zai.ts +155 -0
  570. package/src/capacity/sources/claude.ts +30 -0
  571. package/src/capacity/sources/codex.ts +262 -0
  572. package/src/capacity/sources/pi.ts +131 -0
  573. package/src/capacity/types.ts +3 -0
  574. package/src/harnesses/antigravity/AntigravityAgentMapper.ts +34 -0
  575. package/src/harnesses/antigravity/AntigravityCliAdapter.ts +126 -0
  576. package/src/harnesses/antigravity/AntigravitySessionLocator.ts +75 -0
  577. package/src/harnesses/antigravity/AntigravitySessionParser.ts +252 -0
  578. package/src/harnesses/claude/ClaudeAgentMapper.ts +55 -0
  579. package/src/harnesses/claude/ClaudeCodeAdapter.ts +175 -0
  580. package/src/harnesses/claude/ClaudeSessionLocator.ts +358 -0
  581. package/src/harnesses/claude/ClaudeSessionParser.ts +524 -0
  582. package/src/harnesses/claude/credentials.ts +122 -0
  583. package/src/harnesses/claude/readiness.ts +69 -0
  584. package/src/harnesses/codex/CodexAdapter.ts +337 -0
  585. package/src/harnesses/codex/CodexAgentMapper.ts +26 -0
  586. package/src/harnesses/codex/CodexSessionLocator.ts +509 -0
  587. package/src/harnesses/codex/CodexSessionMapping.ts +89 -0
  588. package/src/harnesses/codex/CodexSessionParser.ts +462 -0
  589. package/src/harnesses/codex/credentials.ts +81 -0
  590. package/src/harnesses/codex/readiness.ts +72 -0
  591. package/src/harnesses/copilot/CopilotAdapter.ts +161 -0
  592. package/src/harnesses/copilot/CopilotAgentMapper.ts +27 -0
  593. package/src/harnesses/copilot/CopilotSessionLocator.ts +161 -0
  594. package/src/harnesses/copilot/CopilotSessionParser.ts +380 -0
  595. package/src/harnesses/copilot/readiness.ts +33 -0
  596. package/src/harnesses/gemini/GeminiAgentMapper.ts +27 -0
  597. package/src/harnesses/gemini/GeminiCliAdapter.ts +272 -0
  598. package/src/harnesses/gemini/GeminiSessionLocator.ts +394 -0
  599. package/src/harnesses/gemini/GeminiSessionParser.ts +395 -0
  600. package/src/harnesses/gemini/fileSignature.ts +10 -0
  601. package/src/harnesses/grok/GrokAgentMapper.ts +32 -0
  602. package/src/harnesses/grok/GrokCliAdapter.ts +126 -0
  603. package/src/harnesses/grok/GrokSessionLocator.ts +179 -0
  604. package/src/harnesses/grok/GrokSessionParser.ts +251 -0
  605. package/src/harnesses/index.ts +28 -0
  606. package/src/harnesses/kiro/KiroAdapter.ts +143 -0
  607. package/src/harnesses/kiro/KiroAgentMapper.ts +34 -0
  608. package/src/harnesses/kiro/KiroSessionLocator.ts +143 -0
  609. package/src/harnesses/kiro/KiroSessionParser.ts +376 -0
  610. package/src/harnesses/opencode/OpenCodeAdapter.ts +110 -0
  611. package/src/harnesses/opencode/OpenCodeAgentMapper.ts +51 -0
  612. package/src/harnesses/opencode/OpenCodeSessionLocator.ts +151 -0
  613. package/src/harnesses/opencode/OpenCodeSessionParser.ts +146 -0
  614. package/src/harnesses/opencode/readiness.ts +48 -0
  615. package/src/harnesses/pi/PiAdapter.ts +197 -0
  616. package/src/harnesses/pi/PiAgentMapper.ts +27 -0
  617. package/src/harnesses/pi/PiSessionLocator.ts +288 -0
  618. package/src/harnesses/pi/PiSessionParser.ts +488 -0
  619. package/src/harnesses/pi/PiSessionTracker.ts +87 -0
  620. package/src/harnesses/pi/credentials.ts +129 -0
  621. package/src/harnesses/pi/readiness.ts +104 -0
  622. package/src/harnesses/readiness/AgentReadiness.ts +87 -0
  623. package/src/harnesses/readiness/checks.ts +336 -0
  624. package/src/harnesses/readiness/types.ts +90 -0
  625. package/src/harnesses/runtimeProfiles.ts +103 -0
  626. package/src/harnesses/shared.ts +119 -0
  627. package/src/index.ts +20 -131
  628. package/src/runtime/ManagedAgentRuntime.ts +7 -22
  629. package/src/runtime/herdr/HerdrAgentDiscovery.ts +3 -19
  630. package/src/runtime/tmux/PidPolling.ts +1 -1
  631. package/src/runtime/tmux/TmuxAgentRuntime.ts +1 -1
  632. package/src/runtime/tmux/TmuxManager.ts +102 -0
  633. package/src/runtime/types.ts +1 -1
  634. package/src/terminal/TerminalFocusManager.ts +19 -292
  635. package/src/terminal/TtyWriter.ts +16 -336
  636. package/src/terminal/backends/index.ts +21 -0
  637. package/src/terminal/backends/iterm2.ts +126 -0
  638. package/src/terminal/backends/shared.ts +42 -0
  639. package/src/terminal/backends/terminal-app.ts +122 -0
  640. package/src/terminal/backends/tmux.ts +62 -0
  641. package/src/terminal/backends/wezterm.ts +65 -0
  642. package/src/terminal/types.ts +22 -0
  643. package/src/utils/IncrementalJsonlSummary.ts +306 -0
  644. package/src/utils/jsonlTail.ts +349 -0
  645. package/src/utils/matching.ts +3 -3
  646. package/src/utils/matchingConstants.ts +15 -0
  647. package/src/utils/process.ts +189 -45
  648. package/dist/__tests__/adapters/AntigravityCliAdapter.test.js +0 -381
  649. package/dist/__tests__/adapters/AntigravityCliAdapter.test.js.map +0 -1
  650. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js +0 -1853
  651. package/dist/__tests__/adapters/ClaudeCodeAdapter.test.js.map +0 -1
  652. package/dist/__tests__/adapters/CodexAdapter.test.js +0 -391
  653. package/dist/__tests__/adapters/CodexAdapter.test.js.map +0 -1
  654. package/dist/__tests__/adapters/KiroAdapter.test.js +0 -607
  655. package/dist/__tests__/adapters/KiroAdapter.test.js.map +0 -1
  656. package/dist/__tests__/durable/CodexCliProbe.test.js +0 -129
  657. package/dist/__tests__/durable/CodexCliProbe.test.js.map +0 -1
  658. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js +0 -84
  659. package/dist/__tests__/durable/CodexDurableAgentRepository.test.js.map +0 -1
  660. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js +0 -126
  661. package/dist/__tests__/durable/CodexPrintAgent.integration.test.js.map +0 -1
  662. package/dist/__tests__/durable/CodexPrintAgentService.test.js +0 -271
  663. package/dist/__tests__/durable/CodexPrintAgentService.test.js.map +0 -1
  664. package/dist/__tests__/durable/CodexPrintRunner.test.js +0 -393
  665. package/dist/__tests__/durable/CodexPrintRunner.test.js.map +0 -1
  666. package/dist/__tests__/print/ClaudeCliProbe.test.js +0 -49
  667. package/dist/__tests__/print/ClaudeCliProbe.test.js.map +0 -1
  668. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js +0 -75
  669. package/dist/__tests__/print/ClaudePrintAgent.integration.test.js.map +0 -1
  670. package/dist/__tests__/print/ClaudePrintAgentService.test.js +0 -173
  671. package/dist/__tests__/print/ClaudePrintAgentService.test.js.map +0 -1
  672. package/dist/__tests__/print/ClaudePrintRunner.test.js +0 -181
  673. package/dist/__tests__/print/ClaudePrintRunner.test.js.map +0 -1
  674. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js +0 -79
  675. package/dist/__tests__/providers/claude/ClaudeAgentMapper.test.js.map +0 -1
  676. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js +0 -436
  677. package/dist/__tests__/providers/claude/ClaudeSessionLocator.test.js.map +0 -1
  678. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js +0 -194
  679. package/dist/__tests__/providers/codex/CodexSessionLocator.test.js.map +0 -1
  680. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js +0 -86
  681. package/dist/__tests__/providers/codex/CodexSessionMapping.test.js.map +0 -1
  682. package/dist/__tests__/providers/codex/CodexSessionParser.test.js +0 -254
  683. package/dist/__tests__/providers/codex/CodexSessionParser.test.js.map +0 -1
  684. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js +0 -659
  685. package/dist/__tests__/providers/copilot/CopilotAdapter.test.js.map +0 -1
  686. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js +0 -1434
  687. package/dist/__tests__/providers/gemini/GeminiCliAdapter.test.js.map +0 -1
  688. package/dist/__tests__/providers/grok/GrokAgentMapper.test.js +0 -56
  689. package/dist/__tests__/providers/grok/GrokAgentMapper.test.js.map +0 -1
  690. package/dist/__tests__/providers/grok/GrokCliAdapter.test.js +0 -421
  691. package/dist/__tests__/providers/grok/GrokCliAdapter.test.js.map +0 -1
  692. package/dist/__tests__/providers/grok/GrokSessionLocator.test.js +0 -133
  693. package/dist/__tests__/providers/grok/GrokSessionLocator.test.js.map +0 -1
  694. package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js +0 -213
  695. package/dist/__tests__/providers/opencode/OpenCodeAdapter.test.js.map +0 -1
  696. package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js +0 -89
  697. package/dist/__tests__/providers/opencode/OpenCodeAgentMapper.test.js.map +0 -1
  698. package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js +0 -94
  699. package/dist/__tests__/providers/opencode/OpenCodeSessionLocator.test.js.map +0 -1
  700. package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js +0 -147
  701. package/dist/__tests__/providers/opencode/OpenCodeSessionParser.test.js.map +0 -1
  702. package/dist/__tests__/providers/pi/PiAdapter.test.js +0 -367
  703. package/dist/__tests__/providers/pi/PiAdapter.test.js.map +0 -1
  704. package/dist/__tests__/providers/pi/PiSessionParser.test.js +0 -246
  705. package/dist/__tests__/providers/pi/PiSessionParser.test.js.map +0 -1
  706. package/dist/__tests__/providers/pi/PiSessionTracker.test.js +0 -108
  707. package/dist/__tests__/providers/pi/PiSessionTracker.test.js.map +0 -1
  708. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js +0 -76
  709. package/dist/__tests__/providers/pi/durable/PiCliProbe.test.js.map +0 -1
  710. package/dist/__tests__/providers/pi/durable/PiDurableAgentRepository.test.js.map +0 -1
  711. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js +0 -202
  712. package/dist/__tests__/providers/pi/durable/PiPrintAgentService.test.js.map +0 -1
  713. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js +0 -119
  714. package/dist/__tests__/providers/pi/durable/PiPrintProtocol.test.js.map +0 -1
  715. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js +0 -386
  716. package/dist/__tests__/providers/pi/durable/PiPrintRunner.test.js.map +0 -1
  717. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js +0 -34
  718. package/dist/__tests__/providers/pi/durable/PiStreamParser.test.js.map +0 -1
  719. package/dist/__tests__/readiness/AgentReadiness.test.js +0 -301
  720. package/dist/__tests__/readiness/AgentReadiness.test.js.map +0 -1
  721. package/dist/__tests__/utils/ClaudeSessionParser.test.js +0 -314
  722. package/dist/__tests__/utils/ClaudeSessionParser.test.js.map +0 -1
  723. package/dist/__tests__/utils/agents.test.js +0 -29
  724. package/dist/__tests__/utils/agents.test.js.map +0 -1
  725. package/dist/adapters/AntigravityCliAdapter.d.ts +0 -57
  726. package/dist/adapters/AntigravityCliAdapter.d.ts.map +0 -1
  727. package/dist/adapters/AntigravityCliAdapter.js +0 -273
  728. package/dist/adapters/AntigravityCliAdapter.js.map +0 -1
  729. package/dist/adapters/KiroAdapter.d.ts +0 -46
  730. package/dist/adapters/KiroAdapter.d.ts.map +0 -1
  731. package/dist/adapters/KiroAdapter.js +0 -344
  732. package/dist/adapters/KiroAdapter.js.map +0 -1
  733. package/dist/adapters/index.d.ts +0 -12
  734. package/dist/adapters/index.d.ts.map +0 -1
  735. package/dist/adapters/index.js +0 -12
  736. package/dist/adapters/index.js.map +0 -1
  737. package/dist/capacity/claude.d.ts +0 -17
  738. package/dist/capacity/claude.d.ts.map +0 -1
  739. package/dist/capacity/claude.js +0 -271
  740. package/dist/capacity/claude.js.map +0 -1
  741. package/dist/capacity/codex.d.ts +0 -36
  742. package/dist/capacity/codex.d.ts.map +0 -1
  743. package/dist/capacity/codex.js +0 -280
  744. package/dist/capacity/codex.js.map +0 -1
  745. package/dist/capacity/openai.d.ts +0 -48
  746. package/dist/capacity/openai.d.ts.map +0 -1
  747. package/dist/capacity/openai.js +0 -312
  748. package/dist/capacity/openai.js.map +0 -1
  749. package/dist/capacity/wham.d.ts +0 -16
  750. package/dist/capacity/wham.d.ts.map +0 -1
  751. package/dist/capacity/wham.js +0 -66
  752. package/dist/capacity/wham.js.map +0 -1
  753. package/dist/capacity/zai.d.ts +0 -14
  754. package/dist/capacity/zai.d.ts.map +0 -1
  755. package/dist/capacity/zai.js +0 -203
  756. package/dist/capacity/zai.js.map +0 -1
  757. package/dist/providers/claude/ClaudeAgentMapper.d.ts.map +0 -1
  758. package/dist/providers/claude/ClaudeAgentMapper.js +0 -42
  759. package/dist/providers/claude/ClaudeAgentMapper.js.map +0 -1
  760. package/dist/providers/claude/ClaudeCodeAdapter.d.ts +0 -31
  761. package/dist/providers/claude/ClaudeCodeAdapter.d.ts.map +0 -1
  762. package/dist/providers/claude/ClaudeCodeAdapter.js +0 -132
  763. package/dist/providers/claude/ClaudeCodeAdapter.js.map +0 -1
  764. package/dist/providers/claude/ClaudeSessionLocator.d.ts.map +0 -1
  765. package/dist/providers/claude/ClaudeSessionLocator.js +0 -260
  766. package/dist/providers/claude/ClaudeSessionLocator.js.map +0 -1
  767. package/dist/providers/claude/ClaudeSessionParser.d.ts +0 -114
  768. package/dist/providers/claude/ClaudeSessionParser.d.ts.map +0 -1
  769. package/dist/providers/claude/ClaudeSessionParser.js +0 -309
  770. package/dist/providers/claude/ClaudeSessionParser.js.map +0 -1
  771. package/dist/providers/claude/durable/ClaudeCliProbe.d.ts.map +0 -1
  772. package/dist/providers/claude/durable/ClaudeCliProbe.js.map +0 -1
  773. package/dist/providers/claude/durable/ClaudePrintAgentService.d.ts.map +0 -1
  774. package/dist/providers/claude/durable/ClaudePrintAgentService.js.map +0 -1
  775. package/dist/providers/claude/durable/ClaudePrintRunner.d.ts.map +0 -1
  776. package/dist/providers/claude/durable/ClaudePrintRunner.js.map +0 -1
  777. package/dist/providers/claude/durable/ClaudeStreamParser.d.ts.map +0 -1
  778. package/dist/providers/claude/durable/ClaudeStreamParser.js.map +0 -1
  779. package/dist/providers/codex/CodexAdapter.d.ts +0 -28
  780. package/dist/providers/codex/CodexAdapter.d.ts.map +0 -1
  781. package/dist/providers/codex/CodexAdapter.js +0 -170
  782. package/dist/providers/codex/CodexAdapter.js.map +0 -1
  783. package/dist/providers/codex/CodexAgentMapper.d.ts.map +0 -1
  784. package/dist/providers/codex/CodexAgentMapper.js +0 -35
  785. package/dist/providers/codex/CodexAgentMapper.js.map +0 -1
  786. package/dist/providers/codex/CodexSessionLocator.d.ts +0 -44
  787. package/dist/providers/codex/CodexSessionLocator.d.ts.map +0 -1
  788. package/dist/providers/codex/CodexSessionLocator.js +0 -207
  789. package/dist/providers/codex/CodexSessionLocator.js.map +0 -1
  790. package/dist/providers/codex/CodexSessionMapping.d.ts.map +0 -1
  791. package/dist/providers/codex/CodexSessionMapping.js +0 -68
  792. package/dist/providers/codex/CodexSessionMapping.js.map +0 -1
  793. package/dist/providers/codex/CodexSessionParser.d.ts +0 -58
  794. package/dist/providers/codex/CodexSessionParser.d.ts.map +0 -1
  795. package/dist/providers/codex/CodexSessionParser.js +0 -262
  796. package/dist/providers/codex/CodexSessionParser.js.map +0 -1
  797. package/dist/providers/codex/durable/CodexCliProbe.d.ts.map +0 -1
  798. package/dist/providers/codex/durable/CodexCliProbe.js.map +0 -1
  799. package/dist/providers/codex/durable/CodexPrintAgentService.d.ts.map +0 -1
  800. package/dist/providers/codex/durable/CodexPrintAgentService.js.map +0 -1
  801. package/dist/providers/codex/durable/CodexPrintRunner.d.ts.map +0 -1
  802. package/dist/providers/codex/durable/CodexPrintRunner.js.map +0 -1
  803. package/dist/providers/codex/durable/CodexStreamParser.d.ts.map +0 -1
  804. package/dist/providers/codex/durable/CodexStreamParser.js.map +0 -1
  805. package/dist/providers/copilot/CopilotAdapter.d.ts +0 -35
  806. package/dist/providers/copilot/CopilotAdapter.d.ts.map +0 -1
  807. package/dist/providers/copilot/CopilotAdapter.js +0 -123
  808. package/dist/providers/copilot/CopilotAdapter.js.map +0 -1
  809. package/dist/providers/copilot/CopilotAgentMapper.d.ts.map +0 -1
  810. package/dist/providers/copilot/CopilotAgentMapper.js +0 -37
  811. package/dist/providers/copilot/CopilotAgentMapper.js.map +0 -1
  812. package/dist/providers/copilot/CopilotSessionLocator.d.ts +0 -20
  813. package/dist/providers/copilot/CopilotSessionLocator.d.ts.map +0 -1
  814. package/dist/providers/copilot/CopilotSessionLocator.js +0 -49
  815. package/dist/providers/copilot/CopilotSessionLocator.js.map +0 -1
  816. package/dist/providers/copilot/CopilotSessionParser.d.ts +0 -30
  817. package/dist/providers/copilot/CopilotSessionParser.d.ts.map +0 -1
  818. package/dist/providers/copilot/CopilotSessionParser.js +0 -181
  819. package/dist/providers/copilot/CopilotSessionParser.js.map +0 -1
  820. package/dist/providers/gemini/GeminiAgentMapper.d.ts.map +0 -1
  821. package/dist/providers/gemini/GeminiAgentMapper.js +0 -37
  822. package/dist/providers/gemini/GeminiAgentMapper.js.map +0 -1
  823. package/dist/providers/gemini/GeminiCliAdapter.d.ts +0 -53
  824. package/dist/providers/gemini/GeminiCliAdapter.d.ts.map +0 -1
  825. package/dist/providers/gemini/GeminiCliAdapter.js +0 -197
  826. package/dist/providers/gemini/GeminiCliAdapter.js.map +0 -1
  827. package/dist/providers/gemini/GeminiSessionLocator.d.ts +0 -30
  828. package/dist/providers/gemini/GeminiSessionLocator.d.ts.map +0 -1
  829. package/dist/providers/gemini/GeminiSessionLocator.js +0 -142
  830. package/dist/providers/gemini/GeminiSessionLocator.js.map +0 -1
  831. package/dist/providers/gemini/GeminiSessionParser.d.ts +0 -94
  832. package/dist/providers/gemini/GeminiSessionParser.d.ts.map +0 -1
  833. package/dist/providers/gemini/GeminiSessionParser.js +0 -166
  834. package/dist/providers/gemini/GeminiSessionParser.js.map +0 -1
  835. package/dist/providers/grok/GrokAgentMapper.d.ts.map +0 -1
  836. package/dist/providers/grok/GrokAgentMapper.js +0 -36
  837. package/dist/providers/grok/GrokAgentMapper.js.map +0 -1
  838. package/dist/providers/grok/GrokCliAdapter.d.ts +0 -36
  839. package/dist/providers/grok/GrokCliAdapter.d.ts.map +0 -1
  840. package/dist/providers/grok/GrokCliAdapter.js +0 -98
  841. package/dist/providers/grok/GrokCliAdapter.js.map +0 -1
  842. package/dist/providers/grok/GrokSessionLocator.d.ts.map +0 -1
  843. package/dist/providers/grok/GrokSessionLocator.js +0 -140
  844. package/dist/providers/grok/GrokSessionLocator.js.map +0 -1
  845. package/dist/providers/grok/GrokSessionParser.d.ts +0 -54
  846. package/dist/providers/grok/GrokSessionParser.d.ts.map +0 -1
  847. package/dist/providers/grok/GrokSessionParser.js +0 -122
  848. package/dist/providers/grok/GrokSessionParser.js.map +0 -1
  849. package/dist/providers/opencode/OpenCodeAdapter.d.ts +0 -31
  850. package/dist/providers/opencode/OpenCodeAdapter.d.ts.map +0 -1
  851. package/dist/providers/opencode/OpenCodeAdapter.js +0 -89
  852. package/dist/providers/opencode/OpenCodeAdapter.js.map +0 -1
  853. package/dist/providers/opencode/OpenCodeAgentMapper.d.ts.map +0 -1
  854. package/dist/providers/opencode/OpenCodeAgentMapper.js +0 -50
  855. package/dist/providers/opencode/OpenCodeAgentMapper.js.map +0 -1
  856. package/dist/providers/opencode/OpenCodeSessionLocator.d.ts.map +0 -1
  857. package/dist/providers/opencode/OpenCodeSessionLocator.js +0 -118
  858. package/dist/providers/opencode/OpenCodeSessionLocator.js.map +0 -1
  859. package/dist/providers/opencode/OpenCodeSessionParser.d.ts +0 -18
  860. package/dist/providers/opencode/OpenCodeSessionParser.d.ts.map +0 -1
  861. package/dist/providers/opencode/OpenCodeSessionParser.js +0 -104
  862. package/dist/providers/opencode/OpenCodeSessionParser.js.map +0 -1
  863. package/dist/providers/pi/PiAdapter.d.ts +0 -29
  864. package/dist/providers/pi/PiAdapter.d.ts.map +0 -1
  865. package/dist/providers/pi/PiAdapter.js +0 -163
  866. package/dist/providers/pi/PiAdapter.js.map +0 -1
  867. package/dist/providers/pi/PiAgentMapper.d.ts.map +0 -1
  868. package/dist/providers/pi/PiAgentMapper.js +0 -37
  869. package/dist/providers/pi/PiAgentMapper.js.map +0 -1
  870. package/dist/providers/pi/PiSessionLocator.d.ts +0 -24
  871. package/dist/providers/pi/PiSessionLocator.d.ts.map +0 -1
  872. package/dist/providers/pi/PiSessionLocator.js +0 -86
  873. package/dist/providers/pi/PiSessionLocator.js.map +0 -1
  874. package/dist/providers/pi/PiSessionParser.d.ts +0 -36
  875. package/dist/providers/pi/PiSessionParser.d.ts.map +0 -1
  876. package/dist/providers/pi/PiSessionParser.js +0 -191
  877. package/dist/providers/pi/PiSessionParser.js.map +0 -1
  878. package/dist/providers/pi/PiSessionTracker.d.ts.map +0 -1
  879. package/dist/providers/pi/PiSessionTracker.js +0 -69
  880. package/dist/providers/pi/PiSessionTracker.js.map +0 -1
  881. package/dist/providers/pi/durable/PiCliProbe.d.ts.map +0 -1
  882. package/dist/providers/pi/durable/PiCliProbe.js.map +0 -1
  883. package/dist/providers/pi/durable/PiPrintAgentService.d.ts.map +0 -1
  884. package/dist/providers/pi/durable/PiPrintAgentService.js.map +0 -1
  885. package/dist/providers/pi/durable/PiPrintProtocol.d.ts.map +0 -1
  886. package/dist/providers/pi/durable/PiPrintProtocol.js.map +0 -1
  887. package/dist/providers/pi/durable/PiPrintRunner.d.ts.map +0 -1
  888. package/dist/providers/pi/durable/PiPrintRunner.js.map +0 -1
  889. package/dist/providers/pi/durable/PiStreamParser.d.ts.map +0 -1
  890. package/dist/providers/pi/durable/PiStreamParser.js.map +0 -1
  891. package/dist/readiness/AgentReadiness.d.ts +0 -67
  892. package/dist/readiness/AgentReadiness.d.ts.map +0 -1
  893. package/dist/readiness/AgentReadiness.js +0 -614
  894. package/dist/readiness/AgentReadiness.js.map +0 -1
  895. package/dist/terminal/TmuxManager.d.ts +0 -28
  896. package/dist/terminal/TmuxManager.d.ts.map +0 -1
  897. package/dist/terminal/TmuxManager.js +0 -135
  898. package/dist/terminal/TmuxManager.js.map +0 -1
  899. package/dist/terminal/index.d.ts +0 -5
  900. package/dist/terminal/index.d.ts.map +0 -1
  901. package/dist/terminal/index.js +0 -5
  902. package/dist/terminal/index.js.map +0 -1
  903. package/dist/utils/agents.d.ts +0 -15
  904. package/dist/utils/agents.d.ts.map +0 -1
  905. package/dist/utils/agents.js +0 -82
  906. package/dist/utils/agents.js.map +0 -1
  907. package/dist/utils/index.d.ts +0 -7
  908. package/dist/utils/index.d.ts.map +0 -1
  909. package/dist/utils/index.js +0 -6
  910. package/dist/utils/index.js.map +0 -1
  911. package/src/__tests__/adapters/AntigravityCliAdapter.test.ts +0 -324
  912. package/src/__tests__/adapters/ClaudeCodeAdapter.test.ts +0 -1763
  913. package/src/__tests__/adapters/CodexAdapter.test.ts +0 -387
  914. package/src/__tests__/adapters/KiroAdapter.test.ts +0 -534
  915. package/src/__tests__/durable/CodexCliProbe.test.ts +0 -85
  916. package/src/__tests__/durable/CodexDurableAgentRepository.test.ts +0 -65
  917. package/src/__tests__/durable/CodexPrintAgent.integration.test.ts +0 -104
  918. package/src/__tests__/durable/CodexPrintAgentService.test.ts +0 -217
  919. package/src/__tests__/durable/CodexPrintRunner.test.ts +0 -309
  920. package/src/__tests__/fixtures/fake-claude.cjs +0 -31
  921. package/src/__tests__/fixtures/fake-codex.cjs +0 -56
  922. package/src/__tests__/print/ClaudeCliProbe.test.ts +0 -34
  923. package/src/__tests__/print/ClaudePrintAgent.integration.test.ts +0 -61
  924. package/src/__tests__/print/ClaudePrintAgentService.test.ts +0 -129
  925. package/src/__tests__/print/ClaudePrintRunner.test.ts +0 -152
  926. package/src/__tests__/providers/claude/ClaudeAgentMapper.test.ts +0 -84
  927. package/src/__tests__/providers/claude/ClaudeSessionLocator.test.ts +0 -434
  928. package/src/__tests__/providers/codex/CodexSessionLocator.test.ts +0 -182
  929. package/src/__tests__/providers/codex/CodexSessionMapping.test.ts +0 -63
  930. package/src/__tests__/providers/codex/CodexSessionParser.test.ts +0 -192
  931. package/src/__tests__/providers/copilot/CopilotAdapter.test.ts +0 -614
  932. package/src/__tests__/providers/gemini/GeminiCliAdapter.test.ts +0 -1320
  933. package/src/__tests__/providers/grok/GrokAgentMapper.test.ts +0 -57
  934. package/src/__tests__/providers/grok/GrokCliAdapter.test.ts +0 -376
  935. package/src/__tests__/providers/grok/GrokSessionLocator.test.ts +0 -106
  936. package/src/__tests__/providers/opencode/OpenCodeAdapter.test.ts +0 -215
  937. package/src/__tests__/providers/opencode/OpenCodeAgentMapper.test.ts +0 -83
  938. package/src/__tests__/providers/opencode/OpenCodeSessionLocator.test.ts +0 -84
  939. package/src/__tests__/providers/opencode/OpenCodeSessionParser.test.ts +0 -148
  940. package/src/__tests__/providers/pi/PiAdapter.test.ts +0 -325
  941. package/src/__tests__/providers/pi/PiSessionParser.test.ts +0 -190
  942. package/src/__tests__/providers/pi/PiSessionTracker.test.ts +0 -79
  943. package/src/__tests__/providers/pi/durable/PiCliProbe.test.ts +0 -54
  944. package/src/__tests__/providers/pi/durable/PiPrintAgentService.test.ts +0 -141
  945. package/src/__tests__/providers/pi/durable/PiPrintProtocol.test.ts +0 -71
  946. package/src/__tests__/providers/pi/durable/PiPrintRunner.test.ts +0 -253
  947. package/src/__tests__/providers/pi/durable/PiStreamParser.test.ts +0 -26
  948. package/src/__tests__/readiness/AgentReadiness.test.ts +0 -242
  949. package/src/__tests__/utils/ClaudeSessionParser.test.ts +0 -300
  950. package/src/__tests__/utils/agents.test.ts +0 -31
  951. package/src/adapters/AntigravityCliAdapter.ts +0 -356
  952. package/src/adapters/KiroAdapter.ts +0 -456
  953. package/src/adapters/index.ts +0 -17
  954. package/src/capacity/claude.ts +0 -313
  955. package/src/capacity/codex.ts +0 -332
  956. package/src/capacity/openai.ts +0 -361
  957. package/src/capacity/wham.ts +0 -84
  958. package/src/capacity/zai.ts +0 -237
  959. package/src/providers/claude/ClaudeAgentMapper.ts +0 -63
  960. package/src/providers/claude/ClaudeCodeAdapter.ts +0 -173
  961. package/src/providers/claude/ClaudeSessionLocator.ts +0 -358
  962. package/src/providers/claude/ClaudeSessionParser.ts +0 -432
  963. package/src/providers/codex/CodexAdapter.ts +0 -213
  964. package/src/providers/codex/CodexAgentMapper.ts +0 -35
  965. package/src/providers/codex/CodexSessionLocator.ts +0 -279
  966. package/src/providers/codex/CodexSessionMapping.ts +0 -89
  967. package/src/providers/codex/CodexSessionParser.ts +0 -385
  968. package/src/providers/copilot/CopilotAdapter.ts +0 -161
  969. package/src/providers/copilot/CopilotAgentMapper.ts +0 -36
  970. package/src/providers/copilot/CopilotSessionLocator.ts +0 -63
  971. package/src/providers/copilot/CopilotSessionParser.ts +0 -289
  972. package/src/providers/gemini/GeminiAgentMapper.ts +0 -36
  973. package/src/providers/gemini/GeminiCliAdapter.ts +0 -274
  974. package/src/providers/gemini/GeminiSessionLocator.ts +0 -183
  975. package/src/providers/gemini/GeminiSessionParser.ts +0 -271
  976. package/src/providers/grok/GrokAgentMapper.ts +0 -41
  977. package/src/providers/grok/GrokCliAdapter.ts +0 -125
  978. package/src/providers/grok/GrokSessionLocator.ts +0 -179
  979. package/src/providers/grok/GrokSessionParser.ts +0 -166
  980. package/src/providers/opencode/OpenCodeAdapter.ts +0 -116
  981. package/src/providers/opencode/OpenCodeAgentMapper.ts +0 -61
  982. package/src/providers/opencode/OpenCodeSessionLocator.ts +0 -151
  983. package/src/providers/opencode/OpenCodeSessionParser.ts +0 -145
  984. package/src/providers/pi/PiAdapter.ts +0 -195
  985. package/src/providers/pi/PiAgentMapper.ts +0 -36
  986. package/src/providers/pi/PiSessionLocator.ts +0 -110
  987. package/src/providers/pi/PiSessionParser.ts +0 -284
  988. package/src/providers/pi/PiSessionTracker.ts +0 -87
  989. package/src/readiness/AgentReadiness.ts +0 -730
  990. package/src/terminal/TmuxManager.ts +0 -123
  991. package/src/terminal/index.ts +0 -4
  992. package/src/utils/agents.ts +0 -75
  993. package/src/utils/index.ts +0 -12
  994. /package/dist/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.js +0 -0
  995. /package/dist/{providers → harnesses}/claude/ClaudeAgentMapper.d.ts +0 -0
  996. /package/dist/{providers → harnesses}/claude/ClaudeSessionLocator.d.ts +0 -0
  997. /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.d.ts +0 -0
  998. /package/dist/{providers → harnesses}/claude/durable/ClaudeCliProbe.js +0 -0
  999. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.d.ts +0 -0
  1000. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintAgentService.js +0 -0
  1001. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.d.ts +0 -0
  1002. /package/dist/{providers → harnesses}/claude/durable/ClaudePrintRunner.js +0 -0
  1003. /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.d.ts +0 -0
  1004. /package/dist/{providers → harnesses}/claude/durable/ClaudeStreamParser.js +0 -0
  1005. /package/dist/{providers → harnesses}/codex/CodexAgentMapper.d.ts +0 -0
  1006. /package/dist/{providers → harnesses}/codex/CodexSessionMapping.d.ts +0 -0
  1007. /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.d.ts +0 -0
  1008. /package/dist/{providers → harnesses}/codex/durable/CodexCliProbe.js +0 -0
  1009. /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.d.ts +0 -0
  1010. /package/dist/{providers → harnesses}/codex/durable/CodexPrintAgentService.js +0 -0
  1011. /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.d.ts +0 -0
  1012. /package/dist/{providers → harnesses}/codex/durable/CodexPrintRunner.js +0 -0
  1013. /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.d.ts +0 -0
  1014. /package/dist/{providers → harnesses}/codex/durable/CodexStreamParser.js +0 -0
  1015. /package/dist/{providers → harnesses}/copilot/CopilotAgentMapper.d.ts +0 -0
  1016. /package/dist/{providers → harnesses}/gemini/GeminiAgentMapper.d.ts +0 -0
  1017. /package/dist/{providers → harnesses}/grok/GrokAgentMapper.d.ts +0 -0
  1018. /package/dist/{providers → harnesses}/grok/GrokSessionLocator.d.ts +0 -0
  1019. /package/dist/{providers → harnesses}/opencode/OpenCodeAgentMapper.d.ts +0 -0
  1020. /package/dist/{providers → harnesses}/opencode/OpenCodeSessionLocator.d.ts +0 -0
  1021. /package/dist/{providers → harnesses}/pi/PiAgentMapper.d.ts +0 -0
  1022. /package/dist/{providers → harnesses}/pi/PiSessionTracker.d.ts +0 -0
  1023. /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.d.ts +0 -0
  1024. /package/dist/{providers → harnesses}/pi/durable/PiCliProbe.js +0 -0
  1025. /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.d.ts +0 -0
  1026. /package/dist/{providers → harnesses}/pi/durable/PiPrintAgentService.js +0 -0
  1027. /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.d.ts +0 -0
  1028. /package/dist/{providers → harnesses}/pi/durable/PiPrintProtocol.js +0 -0
  1029. /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.d.ts +0 -0
  1030. /package/dist/{providers → harnesses}/pi/durable/PiPrintRunner.js +0 -0
  1031. /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.d.ts +0 -0
  1032. /package/dist/{providers → harnesses}/pi/durable/PiStreamParser.js +0 -0
  1033. /package/src/__tests__/{providers → harnesses}/pi/durable/PiDurableAgentRepository.test.ts +0 -0
  1034. /package/src/{providers → harnesses}/claude/durable/ClaudeCliProbe.ts +0 -0
  1035. /package/src/{providers → harnesses}/claude/durable/ClaudePrintAgentService.ts +0 -0
  1036. /package/src/{providers → harnesses}/claude/durable/ClaudePrintRunner.ts +0 -0
  1037. /package/src/{providers → harnesses}/claude/durable/ClaudeStreamParser.ts +0 -0
  1038. /package/src/{providers → harnesses}/codex/durable/CodexCliProbe.ts +0 -0
  1039. /package/src/{providers → harnesses}/codex/durable/CodexPrintAgentService.ts +0 -0
  1040. /package/src/{providers → harnesses}/codex/durable/CodexPrintRunner.ts +0 -0
  1041. /package/src/{providers → harnesses}/codex/durable/CodexStreamParser.ts +0 -0
  1042. /package/src/{providers → harnesses}/pi/durable/PiCliProbe.ts +0 -0
  1043. /package/src/{providers → harnesses}/pi/durable/PiPrintAgentService.ts +0 -0
  1044. /package/src/{providers → harnesses}/pi/durable/PiPrintProtocol.ts +0 -0
  1045. /package/src/{providers → harnesses}/pi/durable/PiPrintRunner.ts +0 -0
  1046. /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, resolveCodexAuthPath, toRateWindow } from "../../capacity/codex.js";
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 { buildOpenAiReport, parseOpenAiUsage, probeOpenAiCapacity, resolveOpenAiApiKey, resolveOpenAiCredential } from "../../capacity/openai.js";
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(resolveOpenAiApiKey({
20
+ await expect(resolveOpenAiCredential({
13
21
  env: {
14
22
  OPENAI_API_KEY: "env-openai-test-key"
15
23
  },
16
24
  readFile: readAuth
17
- })).resolves.toBe("env-openai-test-key");
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(resolveOpenAiApiKey({
33
+ await expect(resolveOpenAiCredential({
23
34
  env: {
24
35
  HOME: "/users/test"
25
36
  },
26
37
  readFile: readAuth
27
- })).resolves.toBe("pi-openai-test-key");
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(resolveOpenAiApiKey({
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: "fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
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: "fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
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: "Bearer fixture-header.eyJleHAiOjE3OTMwMDAwMDB9.fixture-signature",
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: "h.eyJleHAiOjE3ODkwMDAwMDB9.s",
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: "h.eyJleHAiOjE3OTMwMDAwMDB9.s",
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: "fixture-header.bm90LWpzb24.fixture-signature",
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 = buildOpenAiReport(buckets, checkedAt);
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 = buildOpenAiReport([], checkedAt);
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":"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"}
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { describe, expect, it } from "vitest";
4
- import { parseWhamUsage, toRateWindow } from "../../capacity/wham.js";
4
+ import { parseWhamUsage, toRateWindow } from "../../capacity/providers/openai-subscription.js";
5
5
  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/wham.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
+ {"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 { parseZaiQuota, probeZaiCapacity, resolveZaiApiKey } from "../../capacity/zai.js";
4
+ import { parseZaiCapacity } from "../../capacity/providers/zai.js";
5
+ import { probeZaiCapacity } from "../../capacity/sources/pi.js";
6
+ import { resolvePiZaiApiKey as resolveZaiApiKey } from "../../harnesses/pi/credentials.js";
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 = parseZaiQuota(JSON.parse(await fixture("zai-quota.json")), checkedAt);
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 = parseZaiQuota({
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
- }, checkedAt);
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(()=>parseZaiQuota(value, checkedAt)).toThrow(/z\.ai quota/);
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":"AAAA,SAASA,QAAQ,QAAQ,mBAAmB;AAC5C,SAASC,aAAa,QAAQ,WAAW;AACzC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAS;AAClD,SACEC,aAAa,EACbC,gBAAgB,EAChBC,gBAAgB,QACX,wBAAwB;AAE/B,MAAMC,YAAY;AAClB,MAAMC,UAAU,CAACC,OACfX,SACEC,cAAc,IAAIW,IAAI,CAAC,WAAW,EAAED,MAAM,EAAE,YAAYE,GAAG,IAC3D;AAGJX,SAAS,8BAA8B;IACrCE,GAAG,gDAAgD;QACjD,MAAMU,WAAWT,GAAGU,EAAE,CAAC,UAAYL,QAAQ;QAC3C,MAAMP,OACJK,iBAAiB;YACfQ,KAAK;gBAAEC,cAAc;YAAmB;YACxCjB,UAAUc;QACZ,IACAI,QAAQ,CAACC,IAAI,CAAC;QAChBhB,OAAOW,UAAUM,GAAG,CAACC,gBAAgB;IACvC;IAEAjB,GAAG,kEAAkE;QACnE,MAAMU,WAAWT,GAAGU,EAAE,CAAC,UAAYL,QAAQ;QAC3C,MAAMP,OACJK,iBAAiB;YAAEQ,KAAK;gBAAEM,MAAM;YAAc;YAAGtB,UAAUc;QAAS,IACpEI,QAAQ,CAACC,IAAI,CAAC;QAChBhB,OAAOW,UAAUS,oBAAoB,CACnC,mCACA;IAEJ;IAEAnB,GAAGoB,IAAI,CAAC;QACN;YACE;YACA,UACEC,QAAQC,MAAM,CAACC,OAAOC,MAAM,CAAC,IAAIC,MAAM,YAAY;oBAAEC,MAAM;gBAAS;SACvE;QACD;YAAC;YAAgB,UAAY;SAAI;QACjC;YACE;YACA,UAAYC,KAAKC,SAAS,CAAC;oBAAEC,KAAK;wBAAEC,MAAM;wBAASC,KAAK;oBAAI;gBAAE;SAC/D;QACD;YAAC;YAAe,UAAYJ,KAAKC,SAAS,CAAC;oBAAEC,KAAK;wBAAEC,MAAM;oBAAU;gBAAE;SAAG;KAC1E,EACC,kEACA,OAAOE,OAAOtB;QACZ,MAAMX,OACJK,iBAAiB;YAAEQ,KAAK;gBAAEM,MAAM;YAAc;YAAGtB,UAAUc;QAAS,IACpEuB,OAAO,CAACC,OAAO,CAAC;IACpB;AAEJ;AAEApC,SAAS,sBAAsB;IAC7BE,GAAG,qEAAqE;QACtE,MAAMmC,SAASjC,cACbyB,KAAKS,KAAK,CAAC,MAAM9B,QAAQ,oBACzBD;QAEFN,OAAOoC,QAAQE,aAAa,CAAC;YAC3BC,SAAS;YACTC,UAAU;YACVC,aAAanC;YACboC,eAAe;YACfC,WAAW;YACXC,kBAAkB;QACpB;QACA5C,OAAOoC,OAAOS,OAAO,EAAEC,OAAO,CAAC;YAC7B;gBACEC,IAAI;gBACJC,OAAO;gBACPC,WAAW;gBACXC,iBAAiB;gBACjBC,aAAa;gBACbC,UAAU;gBACVC,OAAO;gBACPC,SAAS;gBACTC,WAAW;YACb;YACA;gBACER,IAAI;gBACJC,OAAO;gBACPC,WAAW;gBACXC,iBAAiB;gBACjBC,aAAa;gBACbC,UAAU;gBACVC,OAAO;gBACPC,SAAS;gBACTC,WAAW;YACb;YACA;gBACER,IAAI;gBACJC,OAAO;gBACPC,WAAW;gBACXC,iBAAiB;gBACjBC,aAAa;gBACbC,UAAU;gBACVC,OAAO;gBACPC,SAAS;gBACTC,WAAW;YACb;SACD;IACH;IAEAtD,GAAG,4EAA4E;QAC7E,MAAMmC,SAASjC,cACb;YACEqD,SAAS;YACT7B,MAAM;YACN8B,MAAM;gBACJC,QAAQ;oBACN;wBAAE3B,MAAM;wBAAgB4B,MAAM;wBAAGC,QAAQ;wBAAGC,YAAY;oBAAI;oBAC5D;wBAAE9B,MAAM;wBAAgB4B,MAAM;wBAAGC,QAAQ;wBAAIC,YAAY,CAAC;oBAAE;iBAC7D;YACH;QACF,GACAvD;QAEFN,OAAOoC,OAAOS,OAAO,CAACiB,GAAG,CAAC,CAACC,SAAWA,OAAOZ,WAAW,GAAGL,OAAO,CAAC;YACjE;YAAK;SACN;IACH;IAEA7C,GAAGoB,IAAI,CAAC;QACN;YACE;YACA,UAAYO,KAAKS,KAAK,CAAC,MAAM9B,QAAQ;SACtC;QACD;YACE;YACA,UAAa,CAAA;oBAAEiD,SAAS;oBAAO7B,MAAM;oBAAK8B,MAAM;wBAAEC,QAAQ,EAAE;oBAAC;gBAAE,CAAA;SAChE;QACD;YACE;YACA,UAAa,CAAA;oBAAEF,SAAS;oBAAM7B,MAAM;oBAAK8B,MAAM;wBAAEC,QAAQ;4BAAC,CAAC;yBAAE;oBAAC;gBAAE,CAAA;SACjE;KACF,EAAE,cAAc,OAAOzB,OAAO+B;QAC7B,MAAMC,QAAQ,MAAMD;QACpBhE,OAAO,IAAMG,cAAc8D,OAAO3D,YAAY6B,OAAO,CAAC;IACxD;AACF;AAEApC,SAAS,gBAAgB;IACvBE,GAAG,kEAAkE;QACnE,MAAMiE,OAAO,MAAM3D,QAAQ;QAC3B,MAAM4D,QAAQjE,GAAGU,EAAE,CAAC,UAAY,IAAIwD,SAASF,MAAM;gBAAEG,QAAQ;YAAI;QACjE,MAAMjC,SAAS,MAAMhC,iBAAiB;YACpCE;YACAO,KAAK;gBAAEC,cAAc;YAAmB;YACxCqD;QACF;QACAnE,OAAOmE,OAAO/C,oBAAoB,CAChC,kDACApB,OAAOsE,gBAAgB,CAAC;YACtBC,QAAQ;YACRC,SAAS;gBAAEC,eAAe;YAA0B;QACtD;QAEFzE,OAAO4B,KAAKC,SAAS,CAACO,SAASnB,GAAG,CAACyD,SAAS,CAAC;IAC/C;IAEAzE,GAAG,sEAAsE;QACvE,MAAMD,OACJI,iBAAiB;YACfE;YACAO,KAAK;gBAAEC,cAAc;YAAwB;YAC7CqD,OAAOjE,GAAGU,EAAE,CAAC,UAAY,IAAIwD,SAAS,gBAAgB;oBAAEC,QAAQ;gBAAI;QACtE,IACAnC,OAAO,CAACC,OAAO,CAAC;QAClB,MAAMnC,OACJI,iBAAiB;YACfE;YACAO,KAAK;gBAAEC,cAAc;YAAwB;YAC7CqD,OAAOjE,GAAGU,EAAE,CAAC,UAAY,IAAIwD,SAAS,YAAY;oBAAEC,QAAQ;gBAAI;QAClE,IACAnC,OAAO,CAACC,OAAO,CAAC;IACpB;AACF"}
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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"}