@slkiser/opencode-quota 5.0.2 → 6.0.0-beta.1

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 (794) hide show
  1. package/README.md +32 -46
  2. package/dist/agent-tools.d.ts +24 -0
  3. package/dist/agent-tools.d.ts.map +1 -0
  4. package/dist/agent-tools.js +578 -0
  5. package/dist/agent-tools.js.map +1 -0
  6. package/dist/bin/opencode-quota.d.ts.map +1 -1
  7. package/dist/bin/opencode-quota.js +1 -32
  8. package/dist/bin/opencode-quota.js.map +1 -1
  9. package/dist/core/errors.d.ts +12 -0
  10. package/dist/core/errors.d.ts.map +1 -0
  11. package/dist/core/errors.js +141 -0
  12. package/dist/core/errors.js.map +1 -0
  13. package/dist/core/pace.d.ts +13 -0
  14. package/dist/core/pace.d.ts.map +1 -0
  15. package/dist/core/pace.js +52 -0
  16. package/dist/core/pace.js.map +1 -0
  17. package/dist/core/persist.d.ts +44 -0
  18. package/dist/core/persist.d.ts.map +1 -0
  19. package/dist/core/persist.js +210 -0
  20. package/dist/core/persist.js.map +1 -0
  21. package/dist/core/provider-source.d.ts +40 -0
  22. package/dist/core/provider-source.d.ts.map +1 -0
  23. package/dist/core/provider-source.js +210 -0
  24. package/dist/core/provider-source.js.map +1 -0
  25. package/dist/core/redact.d.ts +17 -0
  26. package/dist/core/redact.d.ts.map +1 -0
  27. package/dist/core/redact.js +217 -0
  28. package/dist/core/redact.js.map +1 -0
  29. package/dist/core/rows.d.ts +20 -0
  30. package/dist/core/rows.d.ts.map +1 -0
  31. package/dist/core/rows.js +142 -0
  32. package/dist/core/rows.js.map +1 -0
  33. package/dist/core/selection.d.ts +15 -0
  34. package/dist/core/selection.d.ts.map +1 -0
  35. package/dist/core/selection.js +43 -0
  36. package/dist/core/selection.js.map +1 -0
  37. package/dist/core/snapshot-publisher.d.ts +15 -0
  38. package/dist/core/snapshot-publisher.d.ts.map +1 -0
  39. package/dist/core/snapshot-publisher.js +57 -0
  40. package/dist/core/snapshot-publisher.js.map +1 -0
  41. package/dist/core/store.d.ts +93 -0
  42. package/dist/core/store.d.ts.map +1 -0
  43. package/dist/core/store.js +563 -0
  44. package/dist/core/store.js.map +1 -0
  45. package/dist/core/types.d.ts +186 -0
  46. package/dist/core/types.d.ts.map +1 -0
  47. package/dist/core/types.js +2 -0
  48. package/dist/core/types.js.map +1 -0
  49. package/dist/core/usage-ranges.d.ts +46 -0
  50. package/dist/core/usage-ranges.d.ts.map +1 -0
  51. package/dist/core/usage-ranges.js +72 -0
  52. package/dist/core/usage-ranges.js.map +1 -0
  53. package/dist/core/usage.d.ts +100 -0
  54. package/dist/core/usage.d.ts.map +1 -0
  55. package/dist/core/usage.js +373 -0
  56. package/dist/core/usage.js.map +1 -0
  57. package/dist/core/validate.d.ts +8 -0
  58. package/dist/core/validate.d.ts.map +1 -0
  59. package/dist/core/validate.js +167 -0
  60. package/dist/core/validate.js.map +1 -0
  61. package/dist/core/windows.d.ts +24 -0
  62. package/dist/core/windows.d.ts.map +1 -0
  63. package/dist/core/windows.js +43 -0
  64. package/dist/core/windows.js.map +1 -0
  65. package/dist/data/modelsdev-pricing.min.json +248 -22
  66. package/dist/index.d.ts +2 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/lib/accounting-format.d.ts +2 -52
  70. package/dist/lib/accounting-format.d.ts.map +1 -1
  71. package/dist/lib/accounting-format.js +6 -255
  72. package/dist/lib/accounting-format.js.map +1 -1
  73. package/dist/lib/alibaba-auth.d.ts +14 -21
  74. package/dist/lib/alibaba-auth.d.ts.map +1 -1
  75. package/dist/lib/alibaba-auth.js +36 -149
  76. package/dist/lib/alibaba-auth.js.map +1 -1
  77. package/dist/lib/alibaba-coding-plan-local-quota.d.ts +1 -6
  78. package/dist/lib/alibaba-coding-plan-local-quota.d.ts.map +1 -1
  79. package/dist/lib/alibaba-coding-plan-local-quota.js +1 -1
  80. package/dist/lib/alibaba-coding-plan-local-quota.js.map +1 -1
  81. package/dist/lib/alibaba-token-plan.d.ts +18 -27
  82. package/dist/lib/alibaba-token-plan.d.ts.map +1 -1
  83. package/dist/lib/alibaba-token-plan.js +121 -285
  84. package/dist/lib/alibaba-token-plan.js.map +1 -1
  85. package/dist/lib/anthropic-auth.d.ts +3 -5
  86. package/dist/lib/anthropic-auth.d.ts.map +1 -1
  87. package/dist/lib/anthropic-auth.js +6 -9
  88. package/dist/lib/anthropic-auth.js.map +1 -1
  89. package/dist/lib/anthropic.d.ts +12 -37
  90. package/dist/lib/anthropic.d.ts.map +1 -1
  91. package/dist/lib/anthropic.js +348 -698
  92. package/dist/lib/anthropic.js.map +1 -1
  93. package/dist/lib/api-key-resolver.d.ts +165 -192
  94. package/dist/lib/api-key-resolver.d.ts.map +1 -1
  95. package/dist/lib/api-key-resolver.js +208 -234
  96. package/dist/lib/api-key-resolver.js.map +1 -1
  97. package/dist/lib/atomic-json.d.ts +4 -1
  98. package/dist/lib/atomic-json.d.ts.map +1 -1
  99. package/dist/lib/atomic-json.js +2 -3
  100. package/dist/lib/atomic-json.js.map +1 -1
  101. package/dist/lib/calendar-date.d.ts +15 -0
  102. package/dist/lib/calendar-date.d.ts.map +1 -0
  103. package/dist/lib/calendar-date.js +21 -0
  104. package/dist/lib/calendar-date.js.map +1 -0
  105. package/dist/lib/chutes.d.ts +0 -1
  106. package/dist/lib/chutes.d.ts.map +1 -1
  107. package/dist/lib/chutes.js +2 -4
  108. package/dist/lib/chutes.js.map +1 -1
  109. package/dist/lib/cli-reports.d.ts +15 -11
  110. package/dist/lib/cli-reports.d.ts.map +1 -1
  111. package/dist/lib/cli-reports.js +34 -107
  112. package/dist/lib/cli-reports.js.map +1 -1
  113. package/dist/lib/cli-show.d.ts +9 -22
  114. package/dist/lib/cli-show.d.ts.map +1 -1
  115. package/dist/lib/cli-show.js +104 -75
  116. package/dist/lib/cli-show.js.map +1 -1
  117. package/dist/lib/config-file-utils.d.ts +3 -15
  118. package/dist/lib/config-file-utils.d.ts.map +1 -1
  119. package/dist/lib/config-file-utils.js +4 -63
  120. package/dist/lib/config-file-utils.js.map +1 -1
  121. package/dist/lib/config-write-target.d.ts +4 -7
  122. package/dist/lib/config-write-target.d.ts.map +1 -1
  123. package/dist/lib/config-write-target.js +4 -18
  124. package/dist/lib/config-write-target.js.map +1 -1
  125. package/dist/lib/copilot.d.ts +29 -20
  126. package/dist/lib/copilot.d.ts.map +1 -1
  127. package/dist/lib/copilot.js +392 -649
  128. package/dist/lib/copilot.js.map +1 -1
  129. package/dist/lib/cursor-detection.d.ts +3 -3
  130. package/dist/lib/cursor-detection.d.ts.map +1 -1
  131. package/dist/lib/cursor-detection.js +44 -88
  132. package/dist/lib/cursor-detection.js.map +1 -1
  133. package/dist/lib/cursor-pricing.d.ts +71 -8
  134. package/dist/lib/cursor-pricing.d.ts.map +1 -1
  135. package/dist/lib/cursor-pricing.js +34 -125
  136. package/dist/lib/cursor-pricing.js.map +1 -1
  137. package/dist/lib/cursor-usage.d.ts +6 -4
  138. package/dist/lib/cursor-usage.d.ts.map +1 -1
  139. package/dist/lib/cursor-usage.js +27 -40
  140. package/dist/lib/cursor-usage.js.map +1 -1
  141. package/dist/lib/deepseek.d.ts +9 -17
  142. package/dist/lib/deepseek.d.ts.map +1 -1
  143. package/dist/lib/deepseek.js +24 -54
  144. package/dist/lib/deepseek.js.map +1 -1
  145. package/dist/lib/display-sanitize.d.ts +0 -8
  146. package/dist/lib/display-sanitize.d.ts.map +1 -1
  147. package/dist/lib/display-sanitize.js +0 -139
  148. package/dist/lib/display-sanitize.js.map +1 -1
  149. package/dist/lib/entries.d.ts +13 -239
  150. package/dist/lib/entries.d.ts.map +1 -1
  151. package/dist/lib/entries.js +1 -46
  152. package/dist/lib/entries.js.map +1 -1
  153. package/dist/lib/file-lock.d.ts +23 -0
  154. package/dist/lib/file-lock.d.ts.map +1 -0
  155. package/dist/lib/file-lock.js +122 -0
  156. package/dist/lib/file-lock.js.map +1 -0
  157. package/dist/lib/format-utils.d.ts +2 -82
  158. package/dist/lib/format-utils.d.ts.map +1 -1
  159. package/dist/lib/format-utils.js +2 -191
  160. package/dist/lib/format-utils.js.map +1 -1
  161. package/dist/lib/glm-coding-plan.d.ts +6 -5
  162. package/dist/lib/glm-coding-plan.d.ts.map +1 -1
  163. package/dist/lib/glm-coding-plan.js +19 -1
  164. package/dist/lib/glm-coding-plan.js.map +1 -1
  165. package/dist/lib/google-agy.d.ts +8 -40
  166. package/dist/lib/google-agy.d.ts.map +1 -1
  167. package/dist/lib/google-agy.js +88 -519
  168. package/dist/lib/google-agy.js.map +1 -1
  169. package/dist/lib/google-companion-credentials.d.ts +9 -40
  170. package/dist/lib/google-companion-credentials.d.ts.map +1 -1
  171. package/dist/lib/google-companion-credentials.js +167 -224
  172. package/dist/lib/google-companion-credentials.js.map +1 -1
  173. package/dist/lib/google-gemini-cli.d.ts +5 -38
  174. package/dist/lib/google-gemini-cli.d.ts.map +1 -1
  175. package/dist/lib/google-gemini-cli.js +71 -442
  176. package/dist/lib/google-gemini-cli.js.map +1 -1
  177. package/dist/lib/google-oauth-quota.d.ts +76 -0
  178. package/dist/lib/google-oauth-quota.d.ts.map +1 -0
  179. package/dist/lib/google-oauth-quota.js +297 -0
  180. package/dist/lib/google-oauth-quota.js.map +1 -0
  181. package/dist/lib/google-token-cache.d.ts +3 -5
  182. package/dist/lib/google-token-cache.d.ts.map +1 -1
  183. package/dist/lib/google-token-cache.js +2 -14
  184. package/dist/lib/google-token-cache.js.map +1 -1
  185. package/dist/lib/home-dir-display.d.ts.map +1 -1
  186. package/dist/lib/home-dir-display.js +21 -39
  187. package/dist/lib/home-dir-display.js.map +1 -1
  188. package/dist/lib/http.d.ts +4 -1
  189. package/dist/lib/http.d.ts.map +1 -1
  190. package/dist/lib/http.js +2 -1
  191. package/dist/lib/http.js.map +1 -1
  192. package/dist/lib/json-guards.d.ts +11 -0
  193. package/dist/lib/json-guards.d.ts.map +1 -0
  194. package/dist/lib/json-guards.js +25 -0
  195. package/dist/lib/json-guards.js.map +1 -0
  196. package/dist/lib/kilo.d.ts +0 -2
  197. package/dist/lib/kilo.d.ts.map +1 -1
  198. package/dist/lib/kilo.js +33 -116
  199. package/dist/lib/kilo.js.map +1 -1
  200. package/dist/lib/kimi-endpoints.d.ts +2 -2
  201. package/dist/lib/kimi-endpoints.d.ts.map +1 -1
  202. package/dist/lib/kimi-endpoints.js +1 -1
  203. package/dist/lib/kimi-endpoints.js.map +1 -1
  204. package/dist/lib/kimi.d.ts.map +1 -1
  205. package/dist/lib/kimi.js +40 -86
  206. package/dist/lib/kimi.js.map +1 -1
  207. package/dist/lib/maintainer-announcements.d.ts +4 -17
  208. package/dist/lib/maintainer-announcements.d.ts.map +1 -1
  209. package/dist/lib/maintainer-announcements.js +7 -44
  210. package/dist/lib/maintainer-announcements.js.map +1 -1
  211. package/dist/lib/maintainer-home-notice.d.ts +19 -0
  212. package/dist/lib/maintainer-home-notice.d.ts.map +1 -0
  213. package/dist/lib/maintainer-home-notice.js +92 -0
  214. package/dist/lib/maintainer-home-notice.js.map +1 -0
  215. package/dist/lib/mimo-config.d.ts +6 -9
  216. package/dist/lib/mimo-config.d.ts.map +1 -1
  217. package/dist/lib/mimo-config.js +43 -74
  218. package/dist/lib/mimo-config.js.map +1 -1
  219. package/dist/lib/mimo.d.ts +2 -5
  220. package/dist/lib/mimo.d.ts.map +1 -1
  221. package/dist/lib/mimo.js +57 -109
  222. package/dist/lib/mimo.js.map +1 -1
  223. package/dist/lib/minimax-endpoints.d.ts +2 -2
  224. package/dist/lib/minimax-endpoints.d.ts.map +1 -1
  225. package/dist/lib/minimax-endpoints.js +1 -1
  226. package/dist/lib/minimax-endpoints.js.map +1 -1
  227. package/dist/lib/modelsdev-pricing.d.ts +22 -16
  228. package/dist/lib/modelsdev-pricing.d.ts.map +1 -1
  229. package/dist/lib/modelsdev-pricing.js +279 -510
  230. package/dist/lib/modelsdev-pricing.js.map +1 -1
  231. package/dist/lib/nanogpt.d.ts +6 -6
  232. package/dist/lib/nanogpt.d.ts.map +1 -1
  233. package/dist/lib/nanogpt.js +19 -72
  234. package/dist/lib/nanogpt.js.map +1 -1
  235. package/dist/lib/ollama-cloud.d.ts +3 -5
  236. package/dist/lib/ollama-cloud.d.ts.map +1 -1
  237. package/dist/lib/ollama-cloud.js +77 -46
  238. package/dist/lib/ollama-cloud.js.map +1 -1
  239. package/dist/lib/openai.d.ts +19 -29
  240. package/dist/lib/openai.d.ts.map +1 -1
  241. package/dist/lib/openai.js +134 -182
  242. package/dist/lib/openai.js.map +1 -1
  243. package/dist/lib/opencode-auth-sqlite.d.ts.map +1 -1
  244. package/dist/lib/opencode-auth-sqlite.js +22 -23
  245. package/dist/lib/opencode-auth-sqlite.js.map +1 -1
  246. package/dist/lib/opencode-auth.d.ts +17 -11
  247. package/dist/lib/opencode-auth.d.ts.map +1 -1
  248. package/dist/lib/opencode-auth.js +39 -46
  249. package/dist/lib/opencode-auth.js.map +1 -1
  250. package/dist/lib/opencode-config-editor.d.ts +3 -34
  251. package/dist/lib/opencode-config-editor.d.ts.map +1 -1
  252. package/dist/lib/opencode-config-editor.js +23 -142
  253. package/dist/lib/opencode-config-editor.js.map +1 -1
  254. package/dist/lib/opencode-config-providers.d.ts +4 -3
  255. package/dist/lib/opencode-config-providers.d.ts.map +1 -1
  256. package/dist/lib/opencode-config-providers.js +7 -11
  257. package/dist/lib/opencode-config-providers.js.map +1 -1
  258. package/dist/lib/opencode-config-read.d.ts +2 -1
  259. package/dist/lib/opencode-config-read.d.ts.map +1 -1
  260. package/dist/lib/opencode-config-read.js +3 -2
  261. package/dist/lib/opencode-config-read.js.map +1 -1
  262. package/dist/lib/opencode-console-auth.d.ts +2 -3
  263. package/dist/lib/opencode-console-auth.d.ts.map +1 -1
  264. package/dist/lib/opencode-console-auth.js +2 -2
  265. package/dist/lib/opencode-console-auth.js.map +1 -1
  266. package/dist/lib/opencode-go.d.ts.map +1 -1
  267. package/dist/lib/opencode-go.js +51 -79
  268. package/dist/lib/opencode-go.js.map +1 -1
  269. package/dist/lib/opencode-storage.d.ts +18 -3
  270. package/dist/lib/opencode-storage.d.ts.map +1 -1
  271. package/dist/lib/opencode-storage.js +134 -2
  272. package/dist/lib/opencode-storage.js.map +1 -1
  273. package/dist/lib/opencode-zen.d.ts +23 -7
  274. package/dist/lib/opencode-zen.d.ts.map +1 -1
  275. package/dist/lib/opencode-zen.js +175 -62
  276. package/dist/lib/opencode-zen.js.map +1 -1
  277. package/dist/lib/openrouter.d.ts.map +1 -1
  278. package/dist/lib/openrouter.js +1 -13
  279. package/dist/lib/openrouter.js.map +1 -1
  280. package/dist/lib/pricing-key.d.ts +48 -0
  281. package/dist/lib/pricing-key.d.ts.map +1 -0
  282. package/dist/lib/pricing-key.js +371 -0
  283. package/dist/lib/pricing-key.js.map +1 -0
  284. package/dist/lib/provider-metadata.d.ts +16 -20
  285. package/dist/lib/provider-metadata.d.ts.map +1 -1
  286. package/dist/lib/provider-metadata.js +69 -69
  287. package/dist/lib/provider-metadata.js.map +1 -1
  288. package/dist/lib/provider-model-matching.d.ts +2 -1
  289. package/dist/lib/provider-model-matching.d.ts.map +1 -1
  290. package/dist/lib/provider-registration.d.ts +1 -177
  291. package/dist/lib/provider-registration.d.ts.map +1 -1
  292. package/dist/lib/provider-registration.js +1 -163
  293. package/dist/lib/provider-registration.js.map +1 -1
  294. package/dist/lib/quota-dialog-commands.d.ts +87 -53
  295. package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
  296. package/dist/lib/quota-dialog-commands.js +259 -519
  297. package/dist/lib/quota-dialog-commands.js.map +1 -1
  298. package/dist/lib/quota-export-types.d.ts +29 -23
  299. package/dist/lib/quota-export-types.d.ts.map +1 -1
  300. package/dist/lib/quota-export.d.ts +16 -26
  301. package/dist/lib/quota-export.d.ts.map +1 -1
  302. package/dist/lib/quota-export.js +105 -147
  303. package/dist/lib/quota-export.js.map +1 -1
  304. package/dist/lib/quota-providers-local.d.ts +12 -8
  305. package/dist/lib/quota-providers-local.d.ts.map +1 -1
  306. package/dist/lib/quota-providers-local.js +150 -223
  307. package/dist/lib/quota-providers-local.js.map +1 -1
  308. package/dist/lib/quota-providers-remote.d.ts +3 -8
  309. package/dist/lib/quota-providers-remote.d.ts.map +1 -1
  310. package/dist/lib/quota-providers-remote.js +309 -449
  311. package/dist/lib/quota-providers-remote.js.map +1 -1
  312. package/dist/lib/quota-providers.d.ts +57 -15
  313. package/dist/lib/quota-providers.d.ts.map +1 -1
  314. package/dist/lib/quota-providers.js +157 -64
  315. package/dist/lib/quota-providers.js.map +1 -1
  316. package/dist/lib/quota-report-message.d.ts +23 -10
  317. package/dist/lib/quota-report-message.d.ts.map +1 -1
  318. package/dist/lib/quota-report-message.js +37 -13
  319. package/dist/lib/quota-report-message.js.map +1 -1
  320. package/dist/lib/quota-retry-wait.d.ts +14 -6
  321. package/dist/lib/quota-retry-wait.d.ts.map +1 -1
  322. package/dist/lib/quota-retry-wait.js +37 -39
  323. package/dist/lib/quota-retry-wait.js.map +1 -1
  324. package/dist/lib/quota-status.d.ts +50 -33
  325. package/dist/lib/quota-status.d.ts.map +1 -1
  326. package/dist/lib/quota-status.js +1113 -772
  327. package/dist/lib/quota-status.js.map +1 -1
  328. package/dist/lib/quota-telemetry.d.ts +7 -14
  329. package/dist/lib/quota-telemetry.d.ts.map +1 -1
  330. package/dist/lib/quota-telemetry.js +46 -97
  331. package/dist/lib/quota-telemetry.js.map +1 -1
  332. package/dist/lib/report-document.d.ts +5 -65
  333. package/dist/lib/report-document.d.ts.map +1 -1
  334. package/dist/lib/report-document.js +14 -167
  335. package/dist/lib/report-document.js.map +1 -1
  336. package/dist/lib/resolved-auth-identity.d.ts +1 -2
  337. package/dist/lib/resolved-auth-identity.d.ts.map +1 -1
  338. package/dist/lib/resolved-auth-identity.js +0 -4
  339. package/dist/lib/resolved-auth-identity.js.map +1 -1
  340. package/dist/lib/session-tokens.d.ts +19 -19
  341. package/dist/lib/session-tokens.d.ts.map +1 -1
  342. package/dist/lib/session-tokens.js +58 -44
  343. package/dist/lib/session-tokens.js.map +1 -1
  344. package/dist/lib/synthetic.d.ts +0 -1
  345. package/dist/lib/synthetic.d.ts.map +1 -1
  346. package/dist/lib/synthetic.js +43 -94
  347. package/dist/lib/synthetic.js.map +1 -1
  348. package/dist/lib/token-buckets.d.ts +0 -1
  349. package/dist/lib/token-buckets.d.ts.map +1 -1
  350. package/dist/lib/token-buckets.js +0 -3
  351. package/dist/lib/token-buckets.js.map +1 -1
  352. package/dist/lib/token-cost.d.ts +2 -1
  353. package/dist/lib/token-cost.d.ts.map +1 -1
  354. package/dist/lib/types.d.ts +46 -340
  355. package/dist/lib/types.d.ts.map +1 -1
  356. package/dist/lib/types.js +2 -69
  357. package/dist/lib/types.js.map +1 -1
  358. package/dist/lib/xai.d.ts +6 -6
  359. package/dist/lib/xai.d.ts.map +1 -1
  360. package/dist/lib/xai.js +51 -90
  361. package/dist/lib/xai.js.map +1 -1
  362. package/dist/plugin.d.ts +6 -3
  363. package/dist/plugin.d.ts.map +1 -1
  364. package/dist/plugin.js +315 -90
  365. package/dist/plugin.js.map +1 -1
  366. package/dist/providers/alibaba-coding-plan.d.ts +4 -0
  367. package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
  368. package/dist/providers/alibaba-coding-plan.js +47 -77
  369. package/dist/providers/alibaba-coding-plan.js.map +1 -1
  370. package/dist/providers/alibaba-token-plan.d.ts.map +1 -1
  371. package/dist/providers/alibaba-token-plan.js +34 -46
  372. package/dist/providers/alibaba-token-plan.js.map +1 -1
  373. package/dist/providers/anthropic.d.ts +2 -4
  374. package/dist/providers/anthropic.d.ts.map +1 -1
  375. package/dist/providers/anthropic.js +80 -162
  376. package/dist/providers/anthropic.js.map +1 -1
  377. package/dist/providers/cache-policies.d.ts +0 -2
  378. package/dist/providers/cache-policies.d.ts.map +1 -1
  379. package/dist/providers/cache-policies.js +45 -91
  380. package/dist/providers/cache-policies.js.map +1 -1
  381. package/dist/providers/chutes.d.ts +0 -3
  382. package/dist/providers/chutes.d.ts.map +1 -1
  383. package/dist/providers/chutes.js +16 -28
  384. package/dist/providers/chutes.js.map +1 -1
  385. package/dist/providers/contract.d.ts +128 -0
  386. package/dist/providers/contract.d.ts.map +1 -0
  387. package/dist/providers/contract.js +101 -0
  388. package/dist/providers/contract.js.map +1 -0
  389. package/dist/providers/copilot.d.ts.map +1 -1
  390. package/dist/providers/copilot.js +171 -175
  391. package/dist/providers/copilot.js.map +1 -1
  392. package/dist/providers/cursor.d.ts.map +1 -1
  393. package/dist/providers/cursor.js +56 -109
  394. package/dist/providers/cursor.js.map +1 -1
  395. package/dist/providers/deepseek.d.ts +1 -6
  396. package/dist/providers/deepseek.d.ts.map +1 -1
  397. package/dist/providers/deepseek.js +46 -81
  398. package/dist/providers/deepseek.js.map +1 -1
  399. package/dist/providers/glm-coding-plan.d.ts +8 -0
  400. package/dist/providers/glm-coding-plan.d.ts.map +1 -0
  401. package/dist/providers/glm-coding-plan.js +106 -0
  402. package/dist/providers/glm-coding-plan.js.map +1 -0
  403. package/dist/providers/google-agy.d.ts.map +1 -1
  404. package/dist/providers/google-agy.js +41 -179
  405. package/dist/providers/google-agy.js.map +1 -1
  406. package/dist/providers/google-gemini-cli.d.ts.map +1 -1
  407. package/dist/providers/google-gemini-cli.js +51 -151
  408. package/dist/providers/google-gemini-cli.js.map +1 -1
  409. package/dist/providers/google-oauth-provider.d.ts +39 -0
  410. package/dist/providers/google-oauth-provider.d.ts.map +1 -0
  411. package/dist/providers/google-oauth-provider.js +161 -0
  412. package/dist/providers/google-oauth-provider.js.map +1 -0
  413. package/dist/providers/kilo.d.ts +0 -3
  414. package/dist/providers/kilo.d.ts.map +1 -1
  415. package/dist/providers/kilo.js +69 -123
  416. package/dist/providers/kilo.js.map +1 -1
  417. package/dist/providers/kimi-code.d.ts +5 -0
  418. package/dist/providers/kimi-code.d.ts.map +1 -1
  419. package/dist/providers/kimi-code.js +91 -136
  420. package/dist/providers/kimi-code.js.map +1 -1
  421. package/dist/providers/mimo.d.ts.map +1 -1
  422. package/dist/providers/mimo.js +55 -94
  423. package/dist/providers/mimo.js.map +1 -1
  424. package/dist/providers/minimax-coding-plan.d.ts +2 -23
  425. package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
  426. package/dist/providers/minimax-coding-plan.js +161 -277
  427. package/dist/providers/minimax-coding-plan.js.map +1 -1
  428. package/dist/providers/nanogpt.d.ts +0 -3
  429. package/dist/providers/nanogpt.d.ts.map +1 -1
  430. package/dist/providers/nanogpt.js +61 -95
  431. package/dist/providers/nanogpt.js.map +1 -1
  432. package/dist/providers/ollama-cloud.d.ts +0 -5
  433. package/dist/providers/ollama-cloud.d.ts.map +1 -1
  434. package/dist/providers/ollama-cloud.js +86 -87
  435. package/dist/providers/ollama-cloud.js.map +1 -1
  436. package/dist/providers/openai.d.ts.map +1 -1
  437. package/dist/providers/openai.js +157 -150
  438. package/dist/providers/openai.js.map +1 -1
  439. package/dist/providers/opencode-go.d.ts.map +1 -1
  440. package/dist/providers/opencode-go.js +157 -199
  441. package/dist/providers/opencode-go.js.map +1 -1
  442. package/dist/providers/opencode-zen.d.ts.map +1 -1
  443. package/dist/providers/opencode-zen.js +104 -141
  444. package/dist/providers/opencode-zen.js.map +1 -1
  445. package/dist/providers/openrouter.d.ts +0 -3
  446. package/dist/providers/openrouter.d.ts.map +1 -1
  447. package/dist/providers/openrouter.js +26 -13
  448. package/dist/providers/openrouter.js.map +1 -1
  449. package/dist/providers/quota-providers.d.ts +7 -3
  450. package/dist/providers/quota-providers.d.ts.map +1 -1
  451. package/dist/providers/quota-providers.js +111 -217
  452. package/dist/providers/quota-providers.js.map +1 -1
  453. package/dist/providers/registry.d.ts.map +1 -1
  454. package/dist/providers/registry.js +1 -2
  455. package/dist/providers/registry.js.map +1 -1
  456. package/dist/providers/result-helpers.d.ts +10 -37
  457. package/dist/providers/result-helpers.d.ts.map +1 -1
  458. package/dist/providers/result-helpers.js +23 -56
  459. package/dist/providers/result-helpers.js.map +1 -1
  460. package/dist/providers/synthetic.d.ts +0 -3
  461. package/dist/providers/synthetic.d.ts.map +1 -1
  462. package/dist/providers/synthetic.js +16 -58
  463. package/dist/providers/synthetic.js.map +1 -1
  464. package/dist/providers/xai.d.ts +2 -1
  465. package/dist/providers/xai.d.ts.map +1 -1
  466. package/dist/providers/xai.js +49 -71
  467. package/dist/providers/xai.js.map +1 -1
  468. package/dist/rpc.d.ts +110 -38
  469. package/dist/rpc.d.ts.map +1 -1
  470. package/dist/rpc.js +125 -37
  471. package/dist/rpc.js.map +1 -1
  472. package/dist/settings/convert.d.ts +60 -0
  473. package/dist/settings/convert.d.ts.map +1 -0
  474. package/dist/settings/convert.js +473 -0
  475. package/dist/settings/convert.js.map +1 -0
  476. package/dist/settings/file.d.ts +89 -0
  477. package/dist/settings/file.d.ts.map +1 -0
  478. package/dist/settings/file.js +452 -0
  479. package/dist/settings/file.js.map +1 -0
  480. package/dist/settings/index.d.ts +10 -0
  481. package/dist/settings/index.d.ts.map +1 -0
  482. package/dist/settings/index.js +3 -0
  483. package/dist/settings/index.js.map +1 -0
  484. package/dist/settings/schema.d.ts +607 -0
  485. package/dist/settings/schema.d.ts.map +1 -0
  486. package/dist/settings/schema.js +479 -0
  487. package/dist/settings/schema.js.map +1 -0
  488. package/dist/tui/client.d.ts +86 -0
  489. package/dist/tui/client.d.ts.map +1 -0
  490. package/dist/tui/client.js +229 -0
  491. package/dist/tui/client.js.map +1 -0
  492. package/dist/tui/display.d.ts +127 -0
  493. package/dist/tui/display.d.ts.map +1 -0
  494. package/dist/tui/display.js +474 -0
  495. package/dist/tui/display.js.map +1 -0
  496. package/dist/tui/index.d.ts +21 -0
  497. package/dist/tui/index.d.ts.map +1 -0
  498. package/dist/tui/index.js +305 -0
  499. package/dist/tui/server-settings.d.ts +43 -0
  500. package/dist/tui/server-settings.d.ts.map +1 -0
  501. package/dist/tui/server-settings.js +233 -0
  502. package/dist/tui/server-settings.js.map +1 -0
  503. package/dist/tui/sidebar.d.ts +41 -0
  504. package/dist/tui/sidebar.d.ts.map +1 -0
  505. package/dist/tui/sidebar.js +148 -0
  506. package/dist/tui/status-line.d.ts +14 -0
  507. package/dist/tui/status-line.d.ts.map +1 -0
  508. package/dist/tui/status-line.js +225 -0
  509. package/dist/tui/theme.d.ts +41 -0
  510. package/dist/tui/theme.d.ts.map +1 -0
  511. package/dist/tui/theme.js +52 -0
  512. package/dist/tui/theme.js.map +1 -0
  513. package/dist/tui/toast-colors.d.ts +37 -0
  514. package/dist/tui/toast-colors.d.ts.map +1 -0
  515. package/dist/tui/toast-colors.js +77 -0
  516. package/dist/tui/toasts.d.ts +59 -0
  517. package/dist/tui/toasts.d.ts.map +1 -0
  518. package/dist/tui/toasts.js +148 -0
  519. package/dist/tui/toasts.js.map +1 -0
  520. package/dist/tui/window/drag.d.ts +26 -0
  521. package/dist/tui/window/drag.d.ts.map +1 -0
  522. package/dist/tui/window/drag.js +80 -0
  523. package/dist/tui/window/drag.js.map +1 -0
  524. package/dist/tui/window/limits.d.ts +15 -0
  525. package/dist/tui/window/limits.d.ts.map +1 -0
  526. package/dist/tui/window/limits.js +227 -0
  527. package/dist/tui/window/limits.js.map +1 -0
  528. package/dist/tui/window/rail.d.ts +21 -0
  529. package/dist/tui/window/rail.d.ts.map +1 -0
  530. package/dist/tui/window/rail.js +81 -0
  531. package/dist/tui/window/settings.d.ts +164 -0
  532. package/dist/tui/window/settings.d.ts.map +1 -0
  533. package/dist/tui/window/settings.js +1679 -0
  534. package/dist/tui/window/shell.d.ts +108 -0
  535. package/dist/tui/window/shell.d.ts.map +1 -0
  536. package/dist/tui/window/shell.js +1003 -0
  537. package/dist/tui/window/usage.d.ts +75 -0
  538. package/dist/tui/window/usage.d.ts.map +1 -0
  539. package/dist/tui/window/usage.js +928 -0
  540. package/dist/tui/window/views.d.ts +61 -0
  541. package/dist/tui/window/views.d.ts.map +1 -0
  542. package/dist/tui/window/views.js +242 -0
  543. package/dist/tui.d.ts +1 -5
  544. package/dist/tui.js +1 -894
  545. package/dist/view/columns.d.ts +15 -0
  546. package/dist/view/columns.d.ts.map +1 -0
  547. package/dist/view/columns.js +48 -0
  548. package/dist/view/columns.js.map +1 -0
  549. package/dist/view/format.d.ts +82 -0
  550. package/dist/view/format.d.ts.map +1 -0
  551. package/dist/view/format.js +201 -0
  552. package/dist/view/format.js.map +1 -0
  553. package/dist/view/quick-look.d.ts +28 -0
  554. package/dist/view/quick-look.d.ts.map +1 -0
  555. package/dist/view/quick-look.js +150 -0
  556. package/dist/view/quick-look.js.map +1 -0
  557. package/dist/view/select.d.ts +67 -0
  558. package/dist/view/select.d.ts.map +1 -0
  559. package/dist/view/select.js +87 -0
  560. package/dist/view/select.js.map +1 -0
  561. package/dist/view/text.d.ts +153 -0
  562. package/dist/view/text.d.ts.map +1 -0
  563. package/dist/view/text.js +642 -0
  564. package/dist/view/text.js.map +1 -0
  565. package/dist/view/usage.d.ts +86 -0
  566. package/dist/view/usage.d.ts.map +1 -0
  567. package/dist/view/usage.js +724 -0
  568. package/dist/view/usage.js.map +1 -0
  569. package/package.json +4 -6
  570. package/dist/lib/chutes-config.d.ts +0 -15
  571. package/dist/lib/chutes-config.d.ts.map +0 -1
  572. package/dist/lib/chutes-config.js +0 -28
  573. package/dist/lib/chutes-config.js.map +0 -1
  574. package/dist/lib/cli-status.d.ts +0 -8
  575. package/dist/lib/cli-status.d.ts.map +0 -1
  576. package/dist/lib/cli-status.js +0 -98
  577. package/dist/lib/cli-status.js.map +0 -1
  578. package/dist/lib/command-parsing.d.ts +0 -43
  579. package/dist/lib/command-parsing.d.ts.map +0 -1
  580. package/dist/lib/command-parsing.js +0 -103
  581. package/dist/lib/command-parsing.js.map +0 -1
  582. package/dist/lib/config.d.ts +0 -63
  583. package/dist/lib/config.d.ts.map +0 -1
  584. package/dist/lib/config.js +0 -1083
  585. package/dist/lib/config.js.map +0 -1
  586. package/dist/lib/deepseek-auth.d.ts +0 -15
  587. package/dist/lib/deepseek-auth.d.ts.map +0 -1
  588. package/dist/lib/deepseek-auth.js +0 -28
  589. package/dist/lib/deepseek-auth.js.map +0 -1
  590. package/dist/lib/format.d.ts +0 -25
  591. package/dist/lib/format.d.ts.map +0 -1
  592. package/dist/lib/format.js +0 -300
  593. package/dist/lib/format.js.map +0 -1
  594. package/dist/lib/google-agy-companion.d.ts +0 -8
  595. package/dist/lib/google-agy-companion.d.ts.map +0 -1
  596. package/dist/lib/google-agy-companion.js +0 -64
  597. package/dist/lib/google-agy-companion.js.map +0 -1
  598. package/dist/lib/google-gemini-cli-companion.d.ts +0 -8
  599. package/dist/lib/google-gemini-cli-companion.d.ts.map +0 -1
  600. package/dist/lib/google-gemini-cli-companion.js +0 -64
  601. package/dist/lib/google-gemini-cli-companion.js.map +0 -1
  602. package/dist/lib/grouped-entry-normalization.d.ts +0 -12
  603. package/dist/lib/grouped-entry-normalization.d.ts.map +0 -1
  604. package/dist/lib/grouped-entry-normalization.js +0 -124
  605. package/dist/lib/grouped-entry-normalization.js.map +0 -1
  606. package/dist/lib/grouped-header-format.d.ts +0 -5
  607. package/dist/lib/grouped-header-format.d.ts.map +0 -1
  608. package/dist/lib/grouped-header-format.js +0 -16
  609. package/dist/lib/grouped-header-format.js.map +0 -1
  610. package/dist/lib/init-installer.d.ts +0 -123
  611. package/dist/lib/init-installer.d.ts.map +0 -1
  612. package/dist/lib/init-installer.js +0 -1111
  613. package/dist/lib/init-installer.js.map +0 -1
  614. package/dist/lib/jsonc.d.ts +0 -17
  615. package/dist/lib/jsonc.d.ts.map +0 -1
  616. package/dist/lib/jsonc.js +0 -23
  617. package/dist/lib/jsonc.js.map +0 -1
  618. package/dist/lib/kilo-config.d.ts +0 -15
  619. package/dist/lib/kilo-config.d.ts.map +0 -1
  620. package/dist/lib/kilo-config.js +0 -27
  621. package/dist/lib/kilo-config.js.map +0 -1
  622. package/dist/lib/kimi-auth.d.ts +0 -49
  623. package/dist/lib/kimi-auth.d.ts.map +0 -1
  624. package/dist/lib/kimi-auth.js +0 -82
  625. package/dist/lib/kimi-auth.js.map +0 -1
  626. package/dist/lib/markdown-table.d.ts +0 -51
  627. package/dist/lib/markdown-table.d.ts.map +0 -1
  628. package/dist/lib/markdown-table.js +0 -179
  629. package/dist/lib/markdown-table.js.map +0 -1
  630. package/dist/lib/minimax-auth.d.ts +0 -62
  631. package/dist/lib/minimax-auth.d.ts.map +0 -1
  632. package/dist/lib/minimax-auth.js +0 -206
  633. package/dist/lib/minimax-auth.js.map +0 -1
  634. package/dist/lib/nanogpt-config.d.ts +0 -15
  635. package/dist/lib/nanogpt-config.d.ts.map +0 -1
  636. package/dist/lib/nanogpt-config.js +0 -31
  637. package/dist/lib/nanogpt-config.js.map +0 -1
  638. package/dist/lib/ollama-cloud-config.d.ts +0 -15
  639. package/dist/lib/ollama-cloud-config.d.ts.map +0 -1
  640. package/dist/lib/ollama-cloud-config.js +0 -27
  641. package/dist/lib/ollama-cloud-config.js.map +0 -1
  642. package/dist/lib/opencode-go-auth.d.ts +0 -16
  643. package/dist/lib/opencode-go-auth.d.ts.map +0 -1
  644. package/dist/lib/opencode-go-auth.js +0 -42
  645. package/dist/lib/opencode-go-auth.js.map +0 -1
  646. package/dist/lib/opencode-version.d.ts +0 -6
  647. package/dist/lib/opencode-version.d.ts.map +0 -1
  648. package/dist/lib/opencode-version.js +0 -26
  649. package/dist/lib/opencode-version.js.map +0 -1
  650. package/dist/lib/provider-add-command.d.ts +0 -35
  651. package/dist/lib/provider-add-command.d.ts.map +0 -1
  652. package/dist/lib/provider-add-command.js +0 -204
  653. package/dist/lib/provider-add-command.js.map +0 -1
  654. package/dist/lib/provider-add-json-v1-questionnaire.d.ts +0 -32
  655. package/dist/lib/provider-add-json-v1-questionnaire.d.ts.map +0 -1
  656. package/dist/lib/provider-add-json-v1-questionnaire.js +0 -336
  657. package/dist/lib/provider-add-json-v1-questionnaire.js.map +0 -1
  658. package/dist/lib/provider-add.d.ts +0 -21
  659. package/dist/lib/provider-add.d.ts.map +0 -1
  660. package/dist/lib/provider-add.js +0 -219
  661. package/dist/lib/provider-add.js.map +0 -1
  662. package/dist/lib/quota-accounting-projection.d.ts +0 -9
  663. package/dist/lib/quota-accounting-projection.d.ts.map +0 -1
  664. package/dist/lib/quota-accounting-projection.js +0 -254
  665. package/dist/lib/quota-accounting-projection.js.map +0 -1
  666. package/dist/lib/quota-columns.d.ts +0 -38
  667. package/dist/lib/quota-columns.d.ts.map +0 -1
  668. package/dist/lib/quota-columns.js +0 -129
  669. package/dist/lib/quota-columns.js.map +0 -1
  670. package/dist/lib/quota-command-format.d.ts +0 -34
  671. package/dist/lib/quota-command-format.d.ts.map +0 -1
  672. package/dist/lib/quota-command-format.js +0 -240
  673. package/dist/lib/quota-command-format.js.map +0 -1
  674. package/dist/lib/quota-dialog-command-specs.d.ts +0 -63
  675. package/dist/lib/quota-dialog-command-specs.d.ts.map +0 -1
  676. package/dist/lib/quota-dialog-command-specs.js +0 -145
  677. package/dist/lib/quota-dialog-command-specs.js.map +0 -1
  678. package/dist/lib/quota-entry-display.d.ts +0 -7
  679. package/dist/lib/quota-entry-display.d.ts.map +0 -1
  680. package/dist/lib/quota-entry-display.js +0 -59
  681. package/dist/lib/quota-entry-display.js.map +0 -1
  682. package/dist/lib/quota-exhaustion-projection.d.ts +0 -11
  683. package/dist/lib/quota-exhaustion-projection.d.ts.map +0 -1
  684. package/dist/lib/quota-exhaustion-projection.js +0 -105
  685. package/dist/lib/quota-exhaustion-projection.js.map +0 -1
  686. package/dist/lib/quota-format-style.d.ts +0 -21
  687. package/dist/lib/quota-format-style.d.ts.map +0 -1
  688. package/dist/lib/quota-format-style.js +0 -38
  689. package/dist/lib/quota-format-style.js.map +0 -1
  690. package/dist/lib/quota-render-data.d.ts +0 -102
  691. package/dist/lib/quota-render-data.d.ts.map +0 -1
  692. package/dist/lib/quota-render-data.js +0 -419
  693. package/dist/lib/quota-render-data.js.map +0 -1
  694. package/dist/lib/quota-reset-notifications.d.ts +0 -20
  695. package/dist/lib/quota-reset-notifications.d.ts.map +0 -1
  696. package/dist/lib/quota-reset-notifications.js +0 -331
  697. package/dist/lib/quota-reset-notifications.js.map +0 -1
  698. package/dist/lib/quota-runtime-context.d.ts +0 -54
  699. package/dist/lib/quota-runtime-context.d.ts.map +0 -1
  700. package/dist/lib/quota-runtime-context.js +0 -110
  701. package/dist/lib/quota-runtime-context.js.map +0 -1
  702. package/dist/lib/quota-state-codec.d.ts +0 -16
  703. package/dist/lib/quota-state-codec.d.ts.map +0 -1
  704. package/dist/lib/quota-state-codec.js +0 -412
  705. package/dist/lib/quota-state-codec.js.map +0 -1
  706. package/dist/lib/quota-state.d.ts +0 -28
  707. package/dist/lib/quota-state.d.ts.map +0 -1
  708. package/dist/lib/quota-state.js +0 -473
  709. package/dist/lib/quota-state.js.map +0 -1
  710. package/dist/lib/quota-stats-format.d.ts +0 -29
  711. package/dist/lib/quota-stats-format.d.ts.map +0 -1
  712. package/dist/lib/quota-stats-format.js +0 -459
  713. package/dist/lib/quota-stats-format.js.map +0 -1
  714. package/dist/lib/quota-stats.d.ts +0 -126
  715. package/dist/lib/quota-stats.d.ts.map +0 -1
  716. package/dist/lib/quota-stats.js +0 -695
  717. package/dist/lib/quota-stats.js.map +0 -1
  718. package/dist/lib/quota-surface-data.d.ts +0 -26
  719. package/dist/lib/quota-surface-data.d.ts.map +0 -1
  720. package/dist/lib/quota-surface-data.js +0 -299
  721. package/dist/lib/quota-surface-data.js.map +0 -1
  722. package/dist/lib/scoped-update-migration.d.ts +0 -103
  723. package/dist/lib/scoped-update-migration.d.ts.map +0 -1
  724. package/dist/lib/scoped-update-migration.js +0 -344
  725. package/dist/lib/scoped-update-migration.js.map +0 -1
  726. package/dist/lib/scoped-update.d.ts +0 -77
  727. package/dist/lib/scoped-update.d.ts.map +0 -1
  728. package/dist/lib/scoped-update.js +0 -590
  729. package/dist/lib/scoped-update.js.map +0 -1
  730. package/dist/lib/session-tokens-format.d.ts +0 -36
  731. package/dist/lib/session-tokens-format.d.ts.map +0 -1
  732. package/dist/lib/session-tokens-format.js +0 -111
  733. package/dist/lib/session-tokens-format.js.map +0 -1
  734. package/dist/lib/synthetic-config.d.ts +0 -15
  735. package/dist/lib/synthetic-config.d.ts.map +0 -1
  736. package/dist/lib/synthetic-config.js +0 -28
  737. package/dist/lib/synthetic-config.js.map +0 -1
  738. package/dist/lib/toast-format-grouped.d.ts +0 -25
  739. package/dist/lib/toast-format-grouped.d.ts.map +0 -1
  740. package/dist/lib/toast-format-grouped.js +0 -296
  741. package/dist/lib/toast-format-grouped.js.map +0 -1
  742. package/dist/lib/tui-compact-format.d.ts +0 -10
  743. package/dist/lib/tui-compact-format.d.ts.map +0 -1
  744. package/dist/lib/tui-compact-format.js +0 -460
  745. package/dist/lib/tui-compact-format.js.map +0 -1
  746. package/dist/lib/tui-panel-state.d.ts +0 -15
  747. package/dist/lib/tui-panel-state.d.ts.map +0 -1
  748. package/dist/lib/tui-panel-state.js +0 -2
  749. package/dist/lib/tui-panel-state.js.map +0 -1
  750. package/dist/lib/tui-prompt-bar-format.d.ts +0 -25
  751. package/dist/lib/tui-prompt-bar-format.d.ts.map +0 -1
  752. package/dist/lib/tui-prompt-bar-format.js +0 -206
  753. package/dist/lib/tui-prompt-bar-format.js.map +0 -1
  754. package/dist/lib/tui-sidebar-format.d.ts +0 -13
  755. package/dist/lib/tui-sidebar-format.d.ts.map +0 -1
  756. package/dist/lib/tui-sidebar-format.js +0 -34
  757. package/dist/lib/tui-sidebar-format.js.map +0 -1
  758. package/dist/lib/zai-auth.d.ts +0 -15
  759. package/dist/lib/zai-auth.d.ts.map +0 -1
  760. package/dist/lib/zai-auth.js +0 -37
  761. package/dist/lib/zai-auth.js.map +0 -1
  762. package/dist/lib/zai.d.ts +0 -5
  763. package/dist/lib/zai.d.ts.map +0 -1
  764. package/dist/lib/zai.js +0 -14
  765. package/dist/lib/zai.js.map +0 -1
  766. package/dist/lib/zhipu-auth.d.ts +0 -15
  767. package/dist/lib/zhipu-auth.d.ts.map +0 -1
  768. package/dist/lib/zhipu-auth.js +0 -42
  769. package/dist/lib/zhipu-auth.js.map +0 -1
  770. package/dist/lib/zhipu.d.ts +0 -5
  771. package/dist/lib/zhipu.d.ts.map +0 -1
  772. package/dist/lib/zhipu.js +0 -13
  773. package/dist/lib/zhipu.js.map +0 -1
  774. package/dist/providers/glm-coding-plan-provider.d.ts +0 -56
  775. package/dist/providers/glm-coding-plan-provider.d.ts.map +0 -1
  776. package/dist/providers/glm-coding-plan-provider.js +0 -115
  777. package/dist/providers/glm-coding-plan-provider.js.map +0 -1
  778. package/dist/providers/google-account-format.d.ts +0 -7
  779. package/dist/providers/google-account-format.d.ts.map +0 -1
  780. package/dist/providers/google-account-format.js +0 -52
  781. package/dist/providers/google-account-format.js.map +0 -1
  782. package/dist/providers/zai.d.ts +0 -2
  783. package/dist/providers/zai.d.ts.map +0 -1
  784. package/dist/providers/zai.js +0 -24
  785. package/dist/providers/zai.js.map +0 -1
  786. package/dist/providers/zhipu.d.ts +0 -2
  787. package/dist/providers/zhipu.d.ts.map +0 -1
  788. package/dist/providers/zhipu.js +0 -21
  789. package/dist/providers/zhipu.js.map +0 -1
  790. package/dist/tui-v2.d.ts +0 -5
  791. package/dist/tui-v2.d.ts.map +0 -1
  792. package/dist/tui-v2.jsx +0 -624
  793. package/dist/tui-v2.jsx.map +0 -1
  794. package/dist/tui.d.ts.map +0 -1
@@ -16,6 +16,7 @@ import { join } from "path";
16
16
  import { resolveAnthropicOAuthCached } from "./anthropic-auth.js";
17
17
  import { sanitizeDisplaySnippet, sanitizeDisplayText } from "./display-sanitize.js";
18
18
  import { fetchWithTimeout } from "./http.js";
19
+ import { asRecord, finiteNumber, nonEmptyString } from "./json-guards.js";
19
20
  import { composeResolvedAuthIdentities, deriveResolvedAuthIdentity, } from "./resolved-auth-identity.js";
20
21
  const DEFAULT_CLAUDE_BINARY = "claude";
21
22
  /** How `binaryPath` reads when the default `claude` ran from PATH. */
@@ -28,15 +29,51 @@ const ANTHROPIC_OAUTH_COOLDOWN_MAX_ENTRIES = 16;
28
29
  const ANTHROPIC_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
29
30
  const ANTHROPIC_BETA_HEADER = "oauth-2025-04-20";
30
31
  const CLAUDE_CODE_CREDENTIALS_SERVICE = "Claude Code-credentials";
32
+ const CLAUDE_KEYCHAIN_LOCATION = `macOS Keychain service ${CLAUDE_CODE_CREDENTIALS_SERVICE}`;
33
+ const CLAUDE_NOT_AUTHENTICATED_MESSAGE = "Claude is not authenticated. Run `claude auth login` and try again.";
31
34
  const CLAUDE_NO_LOCAL_QUOTA_MESSAGE = "Claude CLI auth detected, but local quota windows were not exposed.";
32
35
  const ANTHROPIC_NO_QUOTA_MESSAGE = "Claude CLI auth detected, but quota was unavailable from the local CLI and OAuth credential sources.";
36
+ const USED_PERCENT_KEYS = [
37
+ "utilization",
38
+ "used_percentage",
39
+ "usedPercentage",
40
+ "used_percent",
41
+ "usedPercent",
42
+ "percent_used",
43
+ "percentUsed",
44
+ ];
45
+ const NESTED_USAGE_KEYS = [
46
+ "quota",
47
+ "usage",
48
+ "rate_limits",
49
+ "rateLimits",
50
+ "oauth_usage",
51
+ "oauthUsage",
52
+ ];
53
+ const UNSUPPORTED_COMMAND_TEXT = ["unknown command", "unrecognized command", "unexpected argument"];
54
+ const UNAUTHENTICATED_TEXT = [
55
+ "not logged in",
56
+ "login required",
57
+ "authentication required",
58
+ "run `claude login`",
59
+ "run `claude auth login`",
60
+ "run claude login",
61
+ "run claude auth login",
62
+ ];
63
+ const COMMAND_MISSING_TEXT = [
64
+ "command not found",
65
+ "not recognized as an internal or external command",
66
+ "no such file or directory",
67
+ ];
33
68
  const diagnosticsCache = new Map();
34
69
  const localDiagnosticsCache = new Map();
35
70
  const anthropicOAuthCooldowns = new Map();
36
71
  const anthropicOAuthInFlight = new Map();
37
- export function resolveAnthropicBinaryPath(binaryPath) {
38
- const trimmed = binaryPath?.trim();
39
- return trimmed ? trimmed : DEFAULT_CLAUDE_BINARY;
72
+ function errorText(error) {
73
+ return error instanceof Error ? error.message : String(error);
74
+ }
75
+ function resolveAnthropicBinaryPath(binaryPath) {
76
+ return binaryPath?.trim() || DEFAULT_CLAUDE_BINARY;
40
77
  }
41
78
  /**
42
79
  * Usual Claude CLI install locations, tried in order when `anthropicBinaryPath`
@@ -57,219 +94,114 @@ function formatCommandDisplayArg(value) {
57
94
  const sanitized = sanitizeDisplayText(value);
58
95
  return /[\s"]/u.test(sanitized) ? JSON.stringify(sanitized) : sanitized;
59
96
  }
60
- function formatCommandDisplay(parts) {
61
- return parts.map(formatCommandDisplayArg).join(" ");
62
- }
63
97
  function quoteWindowsCmdArg(value) {
64
98
  const escaped = value.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\+)$/g, "$1$1");
65
99
  return `"${escaped}"`;
66
100
  }
67
- function shouldBridgeClaudeCommandThroughWindowsShell(binaryPath) {
68
- const normalized = binaryPath.trim().toLowerCase();
69
- if (!/[\\/]/u.test(normalized)) {
70
- return true;
71
- }
72
- return /\.(?:cmd|bat)$/u.test(normalized);
73
- }
74
101
  export function buildClaudeCommandInvocation(binaryPath, args, runtime = {}) {
75
102
  const resolvedBinaryPath = resolveAnthropicBinaryPath(binaryPath);
76
- const display = formatCommandDisplay([resolvedBinaryPath, ...args]);
77
- if ((runtime.platform ?? process.platform) === "win32" &&
78
- shouldBridgeClaudeCommandThroughWindowsShell(resolvedBinaryPath)) {
103
+ const display = [resolvedBinaryPath, ...args].map(formatCommandDisplayArg).join(" ");
104
+ // On Windows, PATH lookups and .cmd/.bat shims only run through cmd.exe.
105
+ const needsWindowsShell = !/[\\/]/u.test(resolvedBinaryPath) || /\.(?:cmd|bat)$/iu.test(resolvedBinaryPath);
106
+ if ((runtime.platform ?? process.platform) === "win32" && needsWindowsShell) {
79
107
  return {
80
108
  file: runtime.comspec?.trim() || process.env["ComSpec"]?.trim() || "cmd.exe",
81
109
  args: ["/d", "/s", "/c", [resolvedBinaryPath, ...args].map(quoteWindowsCmdArg).join(" ")],
82
110
  display,
83
111
  };
84
112
  }
85
- return {
86
- file: resolvedBinaryPath,
87
- args: [...args],
88
- display,
89
- };
90
- }
91
- function asRecord(value) {
92
- return value && typeof value === "object" && !Array.isArray(value)
93
- ? value
94
- : null;
113
+ return { file: resolvedBinaryPath, args: [...args], display };
95
114
  }
96
115
  function normalizeResetTimeIso(value) {
97
- if (typeof value !== "string") {
98
- return undefined;
99
- }
100
- const trimmed = value.trim();
101
- if (!trimmed) {
102
- return undefined;
103
- }
104
- const parsed = Date.parse(trimmed);
105
- if (!Number.isFinite(parsed)) {
116
+ const text = nonEmptyString(value);
117
+ if (!text)
106
118
  return undefined;
107
- }
108
- return new Date(parsed).toISOString();
119
+ const parsed = Date.parse(text);
120
+ return Number.isFinite(parsed) ? new Date(parsed).toISOString() : undefined;
109
121
  }
122
+ /** A finite number, or a numeric string such as "35". */
110
123
  function normalizeUsagePercent(value) {
111
- if (typeof value === "number" && Number.isFinite(value)) {
112
- return value;
113
- }
114
- if (typeof value === "string") {
115
- const trimmed = value.trim();
116
- if (!trimmed) {
117
- return undefined;
118
- }
119
- const parsed = Number(trimmed);
120
- return Number.isFinite(parsed) ? parsed : undefined;
121
- }
122
- return undefined;
123
- }
124
- function getWindowUsedPercent(window) {
125
- const candidates = [
126
- window["utilization"],
127
- window["used_percentage"],
128
- window["usedPercentage"],
129
- window["used_percent"],
130
- window["usedPercent"],
131
- window["percent_used"],
132
- window["percentUsed"],
133
- ];
134
- for (const candidate of candidates) {
135
- const normalized = normalizeUsagePercent(candidate);
136
- if (normalized !== undefined) {
137
- return normalized;
138
- }
139
- }
140
- return undefined;
141
- }
142
- function getWindowResetTimeIso(window) {
143
- return normalizeResetTimeIso(window["resets_at"] ?? window["resetsAt"] ?? window["reset_at"] ?? window["resetAt"]);
124
+ if (typeof value !== "string")
125
+ return finiteNumber(value);
126
+ const text = nonEmptyString(value);
127
+ return text === undefined ? undefined : finiteNumber(Number(text));
144
128
  }
145
129
  function parseQuotaWindow(window) {
146
130
  const record = asRecord(window);
147
- if (!record) {
131
+ if (!record)
148
132
  return null;
149
- }
150
- const used = getWindowUsedPercent(record);
151
- if (used === undefined) {
133
+ const used = USED_PERCENT_KEYS.map((key) => normalizeUsagePercent(record[key])).find((percent) => percent !== undefined);
134
+ if (used === undefined)
152
135
  return null;
153
- }
154
136
  return {
155
137
  percentRemaining: Math.min(100, Math.round(100 - used)),
156
- resetTimeIso: getWindowResetTimeIso(record),
138
+ resetTimeIso: normalizeResetTimeIso(record["resets_at"] ?? record["resetsAt"] ?? record["reset_at"] ?? record["resetAt"]),
157
139
  };
158
140
  }
159
141
  function parseExtraUsageQuota(extraUsage) {
160
142
  const record = asRecord(extraUsage);
161
- if (!record || record["is_enabled"] !== true) {
162
- return undefined;
163
- }
164
- const used = record["utilization"];
165
- if (typeof used !== "number" || !Number.isFinite(used) || used < 0 || used > 100) {
143
+ const used = finiteNumber(record?.["utilization"]);
144
+ if (record?.["is_enabled"] !== true || used === undefined || used < 0 || used > 100) {
166
145
  return undefined;
167
146
  }
168
147
  return { percentRemaining: Math.round(100 - used) };
169
148
  }
170
- function getUsageRoots(data) {
171
- const root = asRecord(data);
172
- if (!root) {
173
- return [];
174
- }
175
- const candidates = [
176
- root,
177
- asRecord(root["quota"]),
178
- asRecord(root["usage"]),
179
- asRecord(root["rate_limits"]),
180
- asRecord(root["rateLimits"]),
181
- asRecord(root["oauth_usage"]),
182
- asRecord(root["oauthUsage"]),
183
- ];
184
- const seen = new Set();
185
- const roots = [];
186
- for (const candidate of candidates) {
187
- if (!candidate || seen.has(candidate)) {
188
- continue;
189
- }
190
- seen.add(candidate);
191
- roots.push(candidate);
192
- }
193
- return roots;
194
- }
149
+ /** The `weekly_scoped` limit for the Fable model in the OAuth usage `limits` list. */
195
150
  function parseFableWeeklyWindow(limits) {
196
- if (!Array.isArray(limits)) {
151
+ if (!Array.isArray(limits))
197
152
  return undefined;
198
- }
199
153
  for (const value of limits) {
200
154
  const limit = asRecord(value);
201
- if (!limit || limit["kind"] !== "weekly_scoped") {
202
- continue;
203
- }
204
- const scope = asRecord(limit["scope"]);
205
- const model = asRecord(scope?.["model"]);
206
- const displayName = model?.["display_name"];
207
- if (displayName !== "Fable") {
155
+ const model = asRecord(asRecord(limit?.["scope"])?.["model"]);
156
+ if (!limit || limit["kind"] !== "weekly_scoped" || model?.["display_name"] !== "Fable") {
208
157
  continue;
209
158
  }
210
159
  const window = parseQuotaWindow({
211
160
  utilization: limit["percent"],
212
161
  resets_at: limit["resets_at"],
213
162
  });
214
- if (window) {
163
+ if (window)
215
164
  return window;
216
- }
217
165
  }
218
166
  return undefined;
219
167
  }
220
- function parseUsageResponse(data, options = {}) {
221
- for (const root of getUsageRoots(data)) {
222
- const fiveHour = parseQuotaWindow(root["five_hour"] ?? root["fiveHour"]);
223
- const sevenDay = parseQuotaWindow(root["seven_day"] ?? root["sevenDay"]);
224
- if (!fiveHour || !sevenDay) {
225
- continue;
226
- }
227
- const extraUsage = options.includeExtraUsage
228
- ? parseExtraUsageQuota(root["extra_usage"])
229
- : undefined;
230
- return {
231
- success: true,
232
- five_hour: fiveHour,
233
- seven_day: sevenDay,
234
- ...(extraUsage ? { extra_usage: extraUsage } : {}),
235
- };
236
- }
237
- return null;
238
- }
239
- function parseOAuthUsageResponse(data) {
240
- for (const root of getUsageRoots(data)) {
241
- const fiveHour = parseQuotaWindow(root["five_hour"] ?? root["fiveHour"]);
242
- const sevenDay = parseQuotaWindow(root["seven_day"] ?? root["sevenDay"]);
243
- if (!fiveHour || !sevenDay) {
168
+ /** The first of the response root and its nested usage objects that has both the 5h and 7d windows. */
169
+ function findUsageWindows(data) {
170
+ const root = asRecord(data);
171
+ if (!root)
172
+ return null;
173
+ const candidates = [root, ...NESTED_USAGE_KEYS.map((key) => asRecord(root[key]))];
174
+ for (const candidate of candidates) {
175
+ if (!candidate)
244
176
  continue;
245
- }
246
- const extraUsage = parseExtraUsageQuota(root["extra_usage"]);
247
- const fableWeekly = parseFableWeeklyWindow(root["limits"]);
248
- return {
249
- success: true,
250
- five_hour: fiveHour,
251
- seven_day: sevenDay,
252
- ...(extraUsage ? { extra_usage: extraUsage } : {}),
253
- ...(fableWeekly ? { fable_weekly: fableWeekly } : {}),
254
- };
177
+ const fiveHour = parseQuotaWindow(candidate["five_hour"] ?? candidate["fiveHour"]);
178
+ const sevenDay = parseQuotaWindow(candidate["seven_day"] ?? candidate["sevenDay"]);
179
+ if (fiveHour && sevenDay)
180
+ return { root: candidate, fiveHour, sevenDay };
255
181
  }
256
182
  return null;
257
183
  }
258
- function getClaudeCredentialsPath() {
259
- return join(homedir(), ".claude", ".credentials.json");
260
- }
261
- function getClaudeKeychainLocation() {
262
- return `macOS Keychain service ${sanitizeDisplayText(CLAUDE_CODE_CREDENTIALS_SERVICE)}`;
184
+ /** Quota from Claude CLI `auth status --json`: only the 5h and 7d windows. */
185
+ function parseUsageResponse(data) {
186
+ const windows = findUsageWindows(data);
187
+ return windows
188
+ ? { success: true, five_hour: windows.fiveHour, seven_day: windows.sevenDay }
189
+ : null;
263
190
  }
264
- function getClaudeCredentialsNotFoundDetail(locations) {
265
- if (locations.length === 0) {
266
- return "Claude OAuth credentials were not found.";
267
- }
268
- if (locations.length === 1) {
269
- return `Claude OAuth credentials not found in ${locations[0]}.`;
270
- }
271
- const [head, ...tail] = locations;
272
- return `Claude OAuth credentials not found in ${head} or ${tail.join(" or ")}.`;
191
+ /** Quota from the OAuth usage endpoint: the 5h and 7d windows, Usage Credits and Fable weekly. */
192
+ function parseOAuthUsageResponse(data) {
193
+ const windows = findUsageWindows(data);
194
+ if (!windows)
195
+ return null;
196
+ const extraUsage = parseExtraUsageQuota(windows.root["extra_usage"]);
197
+ const fableWeekly = parseFableWeeklyWindow(windows.root["limits"]);
198
+ return {
199
+ success: true,
200
+ five_hour: windows.fiveHour,
201
+ seven_day: windows.sevenDay,
202
+ ...(extraUsage ? { extra_usage: extraUsage } : {}),
203
+ ...(fableWeekly ? { fable_weekly: fableWeekly } : {}),
204
+ };
273
205
  }
274
206
  function buildAnthropicNoQuotaDiagnosticsMessage(detail) {
275
207
  const normalizedDetail = detail?.trim();
@@ -279,168 +211,118 @@ function buildAnthropicNoQuotaDiagnosticsMessage(detail) {
279
211
  }
280
212
  function extractClaudeCredentialsAccessToken(data) {
281
213
  const root = asRecord(data);
282
- if (!root) {
283
- return "";
284
- }
285
- for (const candidate of [asRecord(root["claudeAiOauth"]), asRecord(root["oauth"]), root]) {
286
- if (!candidate) {
287
- continue;
288
- }
214
+ for (const candidate of [asRecord(root?.["claudeAiOauth"]), asRecord(root?.["oauth"]), root]) {
289
215
  for (const key of ["accessToken", "access_token", "token"]) {
290
- const token = candidate[key];
291
- if (typeof token === "string" && token.trim()) {
292
- return token.trim();
293
- }
216
+ const token = nonEmptyString(candidate?.[key]);
217
+ if (token)
218
+ return token;
294
219
  }
295
220
  }
296
- return "";
221
+ return undefined;
297
222
  }
298
- function parseClaudeCredentialsAccessToken(content, options) {
223
+ /** Reads the access token from stored Claude credentials; the Keychain may hold the bare token. */
224
+ function parseClaudeCredentials(content, source) {
225
+ const missing = {
226
+ state: "unavailable",
227
+ detail: `Claude OAuth access token missing in ${source.location}.`,
228
+ };
299
229
  const trimmed = content.trim();
300
- if (!trimmed) {
301
- return { error: "missing" };
302
- }
303
230
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) {
304
- return options.allowPlainText ? { accessToken: trimmed } : { error: "missing" };
231
+ return source.allowPlainText && trimmed
232
+ ? { state: "configured", accessToken: trimmed }
233
+ : missing;
305
234
  }
306
235
  try {
307
- const parsed = JSON.parse(trimmed);
308
- const accessToken = extractClaudeCredentialsAccessToken(parsed);
309
- return accessToken ? { accessToken } : { error: "missing" };
236
+ const accessToken = extractClaudeCredentialsAccessToken(JSON.parse(trimmed));
237
+ return accessToken ? { state: "configured", accessToken } : missing;
310
238
  }
311
239
  catch (error) {
312
240
  return {
313
- error: sanitizeDisplayText(error instanceof Error ? error.message : String(error)),
241
+ state: "unavailable",
242
+ detail: `Could not parse ${source.parseFailureLabel}: ${sanitizeDisplayText(errorText(error))}.`,
314
243
  };
315
244
  }
316
245
  }
317
- async function runCredentialCommand(file, args) {
318
- return await new Promise((resolve, reject) => {
319
- try {
320
- execFile(file, args, {
321
- encoding: "utf8",
322
- timeout: CLAUDE_COMMAND_TIMEOUT_MS,
323
- maxBuffer: 1024 * 1024,
324
- }, (error, stdout, stderr) => {
325
- const stdoutText = typeof stdout === "string" ? stdout : stdout.toString("utf8");
326
- const stderrText = typeof stderr === "string" ? stderr : stderr.toString("utf8");
327
- if (!error) {
328
- resolve({
329
- code: 0,
330
- stdout: stdoutText,
331
- stderr: stderrText,
332
- timedOut: false,
333
- });
334
- return;
335
- }
336
- const execError = error;
337
- resolve({
338
- code: typeof execError.code === "number" ? execError.code : null,
339
- stdout: stdoutText,
340
- stderr: stderrText,
341
- timedOut: isTimedOutError(execError),
342
- spawnErrorCode: execError.code,
343
- errorMessage: execError.message,
344
- });
246
+ async function runCommand(file, args) {
247
+ return await new Promise((resolve) => {
248
+ execFile(file, args, { encoding: "utf8", timeout: CLAUDE_COMMAND_TIMEOUT_MS, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
249
+ if (!error) {
250
+ resolve({ code: 0, stdout, stderr, timedOut: false });
251
+ return;
252
+ }
253
+ const execError = error;
254
+ resolve({
255
+ code: typeof execError.code === "number" ? execError.code : null,
256
+ stdout,
257
+ stderr,
258
+ timedOut: execError.code === "ETIMEDOUT" ||
259
+ execError.killed === true ||
260
+ execError.message.toLowerCase().includes("timed out"),
261
+ spawnErrorCode: execError.code,
262
+ errorMessage: execError.message,
345
263
  });
346
- }
347
- catch (error) {
348
- reject(error);
349
- }
264
+ });
350
265
  });
351
266
  }
352
- async function readClaudeCredentialsAccessTokenFromMacOSKeychain() {
353
- if (process.platform !== "darwin") {
267
+ async function readClaudeCredentialsFromMacOSKeychain() {
268
+ if (process.platform !== "darwin")
354
269
  return null;
355
- }
356
- const location = getClaudeKeychainLocation();
357
- const result = await runCredentialCommand("security", [
270
+ const result = await runCommand("security", [
358
271
  "find-generic-password",
359
272
  "-s",
360
273
  CLAUDE_CODE_CREDENTIALS_SERVICE,
361
274
  "-w",
362
275
  ]);
363
- if (result.code !== 0) {
364
- return {
365
- state: "not-found",
366
- location,
367
- };
368
- }
369
- const parsed = parseClaudeCredentialsAccessToken(result.stdout, { allowPlainText: true });
370
- if (parsed.accessToken) {
371
- return {
372
- state: "configured",
373
- accessToken: parsed.accessToken,
374
- };
375
- }
376
- return {
377
- state: "unavailable",
378
- detail: parsed.error && parsed.error !== "missing"
379
- ? `Could not parse Claude OAuth credentials from ${location}: ${parsed.error}.`
380
- : `Claude OAuth access token missing in ${location}.`,
381
- };
276
+ if (result.code !== 0)
277
+ return { state: "not-found", location: CLAUDE_KEYCHAIN_LOCATION };
278
+ return parseClaudeCredentials(result.stdout, {
279
+ location: CLAUDE_KEYCHAIN_LOCATION,
280
+ parseFailureLabel: `Claude OAuth credentials from ${CLAUDE_KEYCHAIN_LOCATION}`,
281
+ allowPlainText: true,
282
+ });
382
283
  }
383
- async function readClaudeCredentialsAccessTokenFromFile() {
384
- const credentialsPath = getClaudeCredentialsPath();
284
+ async function readClaudeCredentialsFromFile() {
285
+ const credentialsPath = join(homedir(), ".claude", ".credentials.json");
286
+ const location = sanitizeDisplayText(credentialsPath);
287
+ let content;
385
288
  try {
386
- const content = await readFile(credentialsPath, "utf8");
387
- const parsed = parseClaudeCredentialsAccessToken(content, { allowPlainText: false });
388
- const accessToken = parsed.accessToken?.trim() ?? "";
389
- if (!accessToken) {
390
- return {
391
- state: "unavailable",
392
- detail: parsed.error && parsed.error !== "missing"
393
- ? `Could not parse Claude credentials file ${sanitizeDisplayText(credentialsPath)}: ${parsed.error}.`
394
- : `Claude OAuth access token missing in ${sanitizeDisplayText(credentialsPath)}.`,
395
- };
396
- }
397
- return {
398
- state: "configured",
399
- accessToken,
400
- };
289
+ content = await readFile(credentialsPath, "utf8");
401
290
  }
402
291
  catch (error) {
403
- const code = error && typeof error === "object" && "code" in error
404
- ? error.code
405
- : undefined;
406
- if (code === "ENOENT") {
407
- return {
408
- state: "not-found",
409
- location: sanitizeDisplayText(credentialsPath),
410
- };
292
+ if (error?.code === "ENOENT") {
293
+ return { state: "not-found", location };
411
294
  }
412
295
  return {
413
296
  state: "unavailable",
414
- detail: `Could not read Claude credentials file: ${sanitizeDisplayText(error instanceof Error ? error.message : String(error))}`,
297
+ detail: `Could not read Claude credentials file: ${sanitizeDisplayText(errorText(error))}`,
415
298
  };
416
299
  }
300
+ return parseClaudeCredentials(content, {
301
+ location,
302
+ parseFailureLabel: `Claude credentials file ${location}`,
303
+ allowPlainText: false,
304
+ });
417
305
  }
418
306
  async function readClaudeOAuthAccessToken() {
419
- const locationsChecked = [];
307
+ const notFoundLocations = [];
420
308
  const unavailableDetails = [];
421
- const keychainCredentials = await readClaudeCredentialsAccessTokenFromMacOSKeychain();
422
- if (keychainCredentials?.state === "configured") {
423
- return { ...keychainCredentials, source: "claude-credentials" };
424
- }
425
- if (keychainCredentials?.state === "unavailable") {
426
- unavailableDetails.push(keychainCredentials.detail);
427
- }
428
- if (keychainCredentials?.state === "not-found") {
429
- locationsChecked.push(keychainCredentials.location);
430
- }
431
- const fileCredentials = await readClaudeCredentialsAccessTokenFromFile();
432
- if (fileCredentials.state === "configured") {
433
- return { ...fileCredentials, source: "claude-credentials" };
434
- }
435
- if (fileCredentials.state === "unavailable") {
436
- unavailableDetails.push(fileCredentials.detail);
437
- }
438
- if (fileCredentials.state === "not-found") {
439
- locationsChecked.push(fileCredentials.location);
309
+ for (const readSource of [
310
+ readClaudeCredentialsFromMacOSKeychain,
311
+ readClaudeCredentialsFromFile,
312
+ ]) {
313
+ const result = await readSource();
314
+ if (result?.state === "configured") {
315
+ return { state: "configured", accessToken: result.accessToken, source: "claude-credentials" };
316
+ }
317
+ if (result?.state === "unavailable")
318
+ unavailableDetails.push(result.detail);
319
+ if (result?.state === "not-found")
320
+ notFoundLocations.push(result.location);
440
321
  }
441
322
  return {
442
323
  state: "unavailable",
443
- detail: unavailableDetails[0] ?? getClaudeCredentialsNotFoundDetail(locationsChecked),
324
+ detail: unavailableDetails[0] ??
325
+ `Claude OAuth credentials not found in ${notFoundLocations.join(" or ")}.`,
444
326
  };
445
327
  }
446
328
  async function readAnthropicOAuthAccessToken(options) {
@@ -456,31 +338,34 @@ async function readAnthropicOAuthAccessToken(options) {
456
338
  ? await readClaudeOAuthAccessToken()
457
339
  : { state: "unavailable" };
458
340
  }
459
- function fingerprintAccessToken(accessToken) {
460
- return createHash("sha256").update(accessToken).digest("hex");
461
- }
462
341
  function parseRetryAfterMs(value, nowMs) {
463
342
  const trimmed = value?.trim();
464
- if (!trimmed) {
343
+ if (!trimmed)
465
344
  return undefined;
466
- }
467
345
  if (/^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(trimmed)) {
468
346
  const seconds = Number(trimmed);
469
347
  return Number.isFinite(seconds) && seconds > 0 ? seconds * 1_000 : undefined;
470
348
  }
471
- const retryAtMs = Date.parse(trimmed);
472
- const durationMs = retryAtMs - nowMs;
349
+ const durationMs = Date.parse(trimmed) - nowMs;
473
350
  return Number.isFinite(durationMs) && durationMs > 0 ? durationMs : undefined;
474
351
  }
475
- function getAnthropicOAuthCooldownDurationMs(failureCount, retryAfter, nowMs) {
476
- const exponentialMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, ANTHROPIC_OAUTH_BACKOFF_BASE_MS * 2 ** Math.min(failureCount, 30));
477
- const retryAfterMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, parseRetryAfterMs(retryAfter, nowMs) ?? 0);
478
- return Math.max(exponentialMs, retryAfterMs);
352
+ /** Records a 429 for this token and returns how long the usage probe stays paused. */
353
+ function startAnthropicOAuthCooldown(tokenFingerprint, retryAfter) {
354
+ const nowMs = Date.now();
355
+ const failureCount = anthropicOAuthCooldowns.get(tokenFingerprint)?.failureCount ?? 0;
356
+ // Exponential backoff from 30s, raised to Retry-After, capped at 15 minutes.
357
+ const durationMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, Math.max(ANTHROPIC_OAUTH_BACKOFF_BASE_MS * 2 ** failureCount, parseRetryAfterMs(retryAfter, nowMs) ?? 0));
358
+ anthropicOAuthCooldowns.set(tokenFingerprint, {
359
+ failureCount: failureCount + 1,
360
+ blockedUntilMs: nowMs + durationMs,
361
+ });
362
+ return durationMs;
479
363
  }
480
364
  function getAnthropicOAuthCooldownMessage(remainingMs) {
481
- const boundedRemainingMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, Math.max(0, remainingMs));
482
- return `Anthropic OAuth usage probe paused after HTTP 429; retry in ${Math.ceil(boundedRemainingMs / 1_000)}s.`;
365
+ const seconds = Math.ceil(Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, remainingMs) / 1_000);
366
+ return `Anthropic OAuth usage probe paused after HTTP 429; retry in ${seconds}s.`;
483
367
  }
368
+ /** Bounds the cooldown map, evicting the soonest-expiring entries other than this token. */
484
369
  function retainAnthropicOAuthCooldownForToken(tokenFingerprint) {
485
370
  const targetSize = anthropicOAuthCooldowns.has(tokenFingerprint)
486
371
  ? ANTHROPIC_OAUTH_COOLDOWN_MAX_ENTRIES
@@ -493,20 +378,14 @@ function retainAnthropicOAuthCooldownForToken(tokenFingerprint) {
493
378
  anthropicOAuthCooldowns.delete(fingerprint);
494
379
  }
495
380
  }
496
- function redactAccessTokenFromSanitizedDetail(detail, accessToken) {
497
- const sanitizedDetail = sanitizeDisplayText(detail);
381
+ /** Sanitizes a detail and removes the token, also in the form sanitizing may reassemble. */
382
+ function redactAccessToken(detail, accessToken) {
498
383
  const sanitizedAccessToken = sanitizeDisplayText(accessToken);
499
- const redactedDetail = sanitizedDetail.split(accessToken).join("[redacted]");
384
+ const redactedDetail = sanitizeDisplayText(detail).split(accessToken).join("[redacted]");
500
385
  return sanitizedAccessToken
501
386
  ? redactedDetail.split(sanitizedAccessToken).join("[redacted]")
502
387
  : redactedDetail;
503
388
  }
504
- function sanitizeAnthropicApiDetail(detail, accessToken) {
505
- return redactAccessTokenFromSanitizedDetail(detail, accessToken).slice(0, 120);
506
- }
507
- function sanitizeAnthropicRequestError(detail, accessToken) {
508
- return redactAccessTokenFromSanitizedDetail(detail, accessToken);
509
- }
510
389
  async function performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint, requestTimeoutMs) {
511
390
  try {
512
391
  return await fetchWithTimeout(ANTHROPIC_USAGE_URL, {
@@ -518,48 +397,32 @@ async function performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint,
518
397
  },
519
398
  timeoutMs: requestTimeoutMs,
520
399
  consume: async (response, timeoutSignal) => {
521
- if (response.status === 429) {
522
- const nowMs = Date.now();
523
- const previousFailureCount = anthropicOAuthCooldowns.get(tokenFingerprint)?.failureCount ?? 0;
524
- const durationMs = getAnthropicOAuthCooldownDurationMs(previousFailureCount, response.headers?.get?.("Retry-After") ?? null, nowMs);
525
- anthropicOAuthCooldowns.set(tokenFingerprint, {
526
- failureCount: previousFailureCount + 1,
527
- blockedUntilMs: nowMs + durationMs,
528
- });
529
- let detail = "";
530
- try {
531
- detail = sanitizeAnthropicApiDetail(await response.text(), accessToken);
532
- }
533
- catch (error) {
534
- if (timeoutSignal.aborted)
535
- throw error;
536
- detail = "";
537
- }
538
- const errorDetail = detail
539
- ? `Anthropic API error ${response.status}: ${detail}`
540
- : `Anthropic API returned ${response.status}`;
541
- return {
542
- state: "unavailable",
543
- detail: `${errorDetail} ${getAnthropicOAuthCooldownMessage(durationMs)}`,
544
- };
545
- }
546
- anthropicOAuthCooldowns.delete(tokenFingerprint);
400
+ // The cooldown starts before the body is read, so a stalled 429 body still pauses retries.
401
+ const cooldownMs = response.status === 429
402
+ ? startAnthropicOAuthCooldown(tokenFingerprint, response.headers.get("Retry-After"))
403
+ : undefined;
404
+ if (cooldownMs === undefined)
405
+ anthropicOAuthCooldowns.delete(tokenFingerprint);
547
406
  if (!response.ok) {
548
407
  const authenticationFailure = response.status === 401 || response.status === 403;
549
408
  let detail = "";
550
409
  try {
551
- detail = sanitizeAnthropicApiDetail(await response.text(), accessToken);
410
+ detail = redactAccessToken(await response.text(), accessToken).slice(0, 120);
552
411
  }
553
412
  catch (error) {
413
+ // A rejected token needs no body (it triggers the credential fallback);
414
+ // any other timed-out body read fails the whole request.
554
415
  if (timeoutSignal.aborted && !authenticationFailure)
555
416
  throw error;
556
- detail = "";
557
417
  }
418
+ const errorDetail = detail
419
+ ? `Anthropic API error ${response.status}: ${detail}`
420
+ : `Anthropic API returned ${response.status}`;
558
421
  return {
559
422
  state: "unavailable",
560
- detail: detail
561
- ? `Anthropic API error ${response.status}: ${detail}`
562
- : `Anthropic API returned ${response.status}`,
423
+ detail: cooldownMs === undefined
424
+ ? errorDetail
425
+ : `${errorDetail} ${getAnthropicOAuthCooldownMessage(cooldownMs)}`,
563
426
  ...(authenticationFailure ? { failureKind: "authentication" } : {}),
564
427
  };
565
428
  }
@@ -570,34 +433,21 @@ async function performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint,
570
433
  catch (error) {
571
434
  if (timeoutSignal.aborted)
572
435
  throw error;
573
- return {
574
- state: "unavailable",
575
- detail: "Failed to parse Anthropic quota response",
576
- };
436
+ return { state: "unavailable", detail: "Failed to parse Anthropic quota response" };
577
437
  }
578
438
  const quota = parseOAuthUsageResponse(data);
579
- if (!quota) {
580
- return {
581
- state: "unavailable",
582
- detail: "Unexpected Anthropic quota response shape",
583
- };
584
- }
585
- return {
586
- state: "success",
587
- quota,
588
- };
439
+ return quota
440
+ ? { state: "success", quota }
441
+ : { state: "unavailable", detail: "Unexpected Anthropic quota response shape" };
589
442
  },
590
443
  });
591
444
  }
592
445
  catch (error) {
593
- return {
594
- state: "unavailable",
595
- detail: sanitizeAnthropicRequestError(error instanceof Error ? error.message : String(error), accessToken),
596
- };
446
+ return { state: "unavailable", detail: redactAccessToken(errorText(error), accessToken) };
597
447
  }
598
448
  }
599
449
  async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeoutMs) {
600
- const tokenFingerprint = fingerprintAccessToken(accessToken);
450
+ const tokenFingerprint = createHash("sha256").update(accessToken).digest("hex");
601
451
  retainAnthropicOAuthCooldownForToken(tokenFingerprint);
602
452
  const nowMs = Date.now();
603
453
  const cooldown = anthropicOAuthCooldowns.get(tokenFingerprint);
@@ -607,10 +457,10 @@ async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeo
607
457
  detail: getAnthropicOAuthCooldownMessage(cooldown.blockedUntilMs - nowMs),
608
458
  };
609
459
  }
460
+ // Concurrent probes with the same token share one request.
610
461
  const existingInFlight = anthropicOAuthInFlight.get(tokenFingerprint);
611
- if (existingInFlight) {
462
+ if (existingInFlight)
612
463
  return await existingInFlight;
613
- }
614
464
  const inFlight = performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint, requestTimeoutMs);
615
465
  anthropicOAuthInFlight.set(tokenFingerprint, inFlight);
616
466
  try {
@@ -624,170 +474,79 @@ async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeo
624
474
  }
625
475
  export async function queryAnthropicQuotaWithOAuth(accessToken, requestTimeoutMs) {
626
476
  const result = await queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeoutMs);
627
- return result.state === "success"
628
- ? result.quota
629
- : { success: false, error: result.detail ?? "Anthropic OAuth quota unavailable" };
477
+ return result.state === "success" ? result.quota : { success: false, error: result.detail };
630
478
  }
631
479
  function extractAuthBoolean(data) {
632
480
  const record = asRecord(data);
633
- if (!record) {
481
+ if (!record)
634
482
  return undefined;
635
- }
483
+ const auth = asRecord(record["auth"]);
636
484
  for (const candidate of [
637
485
  record["authenticated"],
638
486
  record["isAuthenticated"],
639
487
  record["loggedIn"],
488
+ auth?.["authenticated"],
489
+ auth?.["loggedIn"],
640
490
  ]) {
641
- if (typeof candidate === "boolean") {
491
+ if (typeof candidate === "boolean")
642
492
  return candidate;
643
- }
644
- }
645
- const authRecord = asRecord(record["auth"]);
646
- if (authRecord) {
647
- for (const candidate of [authRecord["authenticated"], authRecord["loggedIn"]]) {
648
- if (typeof candidate === "boolean") {
649
- return candidate;
650
- }
651
- }
652
- }
653
- const status = record["status"];
654
- if (typeof status === "string") {
655
- const normalized = status.trim().toLowerCase();
656
- if (normalized === "authenticated") {
657
- return true;
658
- }
659
- if (normalized === "unauthenticated") {
660
- return false;
661
- }
662
493
  }
494
+ const status = nonEmptyString(record["status"])?.toLowerCase();
495
+ if (status === "authenticated")
496
+ return true;
497
+ if (status === "unauthenticated")
498
+ return false;
663
499
  return undefined;
664
500
  }
665
- function hasUnsupportedCommandText(output) {
666
- const normalized = output.toLowerCase();
667
- return (normalized.includes("unknown command") ||
668
- normalized.includes("unrecognized command") ||
669
- normalized.includes("unexpected argument"));
670
- }
671
- function hasUnauthenticatedText(output) {
501
+ function includesAnyPhrase(output, phrases) {
672
502
  const normalized = output.toLowerCase();
673
- return (normalized.includes("not logged in") ||
674
- normalized.includes("login required") ||
675
- normalized.includes("authentication required") ||
676
- normalized.includes("run `claude login`") ||
677
- normalized.includes("run `claude auth login`") ||
678
- normalized.includes("run claude login") ||
679
- normalized.includes("run claude auth login"));
680
- }
681
- function detailFromCommandResult(result) {
682
- const detail = `${result.stderr}\n${result.stdout}\n${result.errorMessage ?? ""}`.trim();
683
- return detail ? sanitizeDisplaySnippet(detail, 160) : undefined;
503
+ return phrases.some((phrase) => normalized.includes(phrase));
684
504
  }
685
505
  function parseVersion(output) {
686
506
  const match = output.match(/\b\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?\b/);
687
507
  return match ? match[0] : null;
688
508
  }
689
509
  function isCommandMissing(result) {
690
- if (result.spawnErrorCode === "ENOENT") {
691
- return true;
692
- }
693
- const output = `${result.stderr}\n${result.stdout}\n${result.errorMessage ?? ""}`.toLowerCase();
694
- return (output.includes("command not found") ||
695
- output.includes("not recognized as an internal or external command") ||
696
- output.includes("no such file or directory"));
697
- }
698
- function isTimedOutError(error) {
699
- return (error.code === "ETIMEDOUT" ||
700
- error.killed === true ||
701
- error.message.toLowerCase().includes("timed out"));
702
- }
703
- async function runClaudeCommand(invocation) {
704
- return await new Promise((resolve, reject) => {
705
- try {
706
- execFile(invocation.file, invocation.args, {
707
- encoding: "utf8",
708
- timeout: CLAUDE_COMMAND_TIMEOUT_MS,
709
- maxBuffer: 1024 * 1024,
710
- }, (error, stdout, stderr) => {
711
- const stdoutText = typeof stdout === "string" ? stdout : stdout.toString("utf8");
712
- const stderrText = typeof stderr === "string" ? stderr : stderr.toString("utf8");
713
- if (!error) {
714
- resolve({
715
- code: 0,
716
- stdout: stdoutText,
717
- stderr: stderrText,
718
- timedOut: false,
719
- });
720
- return;
721
- }
722
- const execError = error;
723
- resolve({
724
- code: typeof execError.code === "number" ? execError.code : null,
725
- stdout: stdoutText,
726
- stderr: stderrText,
727
- timedOut: isTimedOutError(execError),
728
- spawnErrorCode: execError.code,
729
- errorMessage: execError.message,
730
- });
731
- });
732
- }
733
- catch (error) {
734
- reject(error);
735
- }
736
- });
510
+ return (result.spawnErrorCode === "ENOENT" ||
511
+ includesAnyPhrase(`${result.stderr}\n${result.stdout}\n${result.errorMessage ?? ""}`, COMMAND_MISSING_TEXT));
737
512
  }
738
513
  function parseClaudeAuthStatusResult(result) {
739
514
  const combinedOutput = `${result.stdout}\n${result.stderr}`;
740
- if (hasUnsupportedCommandText(combinedOutput)) {
515
+ if (includesAnyPhrase(combinedOutput, UNSUPPORTED_COMMAND_TEXT)) {
741
516
  return {
742
517
  authStatus: "unknown",
743
518
  unsupportedCommand: true,
744
519
  message: "Claude CLI authentication status JSON is unavailable in this version of Claude.",
745
520
  };
746
521
  }
747
- if (hasUnauthenticatedText(combinedOutput)) {
748
- return {
749
- authStatus: "unauthenticated",
750
- message: "Claude is not authenticated. Run `claude auth login` and try again.",
751
- };
522
+ if (includesAnyPhrase(combinedOutput, UNAUTHENTICATED_TEXT)) {
523
+ return { authStatus: "unauthenticated", message: CLAUDE_NOT_AUTHENTICATED_MESSAGE };
752
524
  }
753
525
  const trimmed = result.stdout.trim();
754
526
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
755
527
  try {
756
528
  const payload = JSON.parse(trimmed);
757
529
  const auth = extractAuthBoolean(payload);
758
- if (auth === true) {
759
- return {
760
- authStatus: "authenticated",
761
- jsonPayload: payload,
762
- };
763
- }
530
+ if (auth === true)
531
+ return { authStatus: "authenticated", jsonPayload: payload };
764
532
  if (auth === false) {
765
- return {
766
- authStatus: "unauthenticated",
767
- message: "Claude is not authenticated. Run `claude auth login` and try again.",
768
- jsonPayload: payload,
769
- };
533
+ return { authStatus: "unauthenticated", message: CLAUDE_NOT_AUTHENTICATED_MESSAGE };
770
534
  }
771
535
  return {
772
536
  authStatus: "unknown",
773
537
  message: "Could not verify Claude authentication status from JSON output.",
774
- jsonPayload: payload,
775
538
  };
776
539
  }
777
540
  catch {
778
- // Fall through to exit-code-based handling.
541
+ // Not JSON after all: fall through to exit-code-based handling.
779
542
  }
780
543
  }
781
- if (result.code === 0) {
544
+ if (result.code === 0)
782
545
  return { authStatus: "authenticated" };
783
- }
784
546
  if (result.timedOut) {
785
- return {
786
- authStatus: "unknown",
787
- message: "Timed out while running Claude CLI auth status.",
788
- };
547
+ return { authStatus: "unknown", message: "Timed out while running Claude CLI auth status." };
789
548
  }
790
- const detail = detailFromCommandResult(result);
549
+ const detail = sanitizeDisplaySnippet(`${result.stderr}\n${result.stdout}\n${result.errorMessage ?? ""}`.trim(), 160);
791
550
  return {
792
551
  authStatus: "unknown",
793
552
  message: detail
@@ -795,43 +554,15 @@ function parseClaudeAuthStatusResult(result) {
795
554
  : "Could not verify Claude authentication status.",
796
555
  };
797
556
  }
798
- function mapLocalDiagnosticsToAnthropicDiagnostics(localDiagnostics) {
799
- if (localDiagnostics.localQuota) {
800
- return {
801
- installed: localDiagnostics.installed,
802
- version: localDiagnostics.version,
803
- authStatus: localDiagnostics.authStatus,
804
- quotaSupported: true,
805
- quotaSource: "claude-auth-status-json",
806
- binaryPath: localDiagnostics.binaryPath,
807
- checkedCommands: localDiagnostics.checkedCommands,
808
- quota: localDiagnostics.localQuota,
809
- };
810
- }
811
- const diagnostics = {
812
- installed: localDiagnostics.installed,
813
- version: localDiagnostics.version,
814
- authStatus: localDiagnostics.authStatus,
815
- quotaSupported: false,
816
- quotaSource: "none",
817
- binaryPath: localDiagnostics.binaryPath,
818
- checkedCommands: localDiagnostics.checkedCommands,
819
- };
820
- if (localDiagnostics.message) {
821
- diagnostics.message = localDiagnostics.message;
822
- }
823
- return diagnostics;
824
- }
825
- async function runClaudeVersionCommand(binaryPath, checkedCommands) {
826
- const versionCommand = buildClaudeCommandInvocation(binaryPath, ["--version"]);
827
- checkedCommands.push(versionCommand.display);
828
- return await runClaudeCommand(versionCommand);
829
- }
830
- async function probeAnthropicLocalDiagnostics(options = {}) {
831
- const configuredBinaryPath = resolveAnthropicBinaryPath(options.binaryPath);
557
+ async function probeAnthropicLocalDiagnostics(configuredBinaryPath) {
832
558
  const checkedCommands = [];
559
+ const runClaude = async (binaryPath, args) => {
560
+ const invocation = buildClaudeCommandInvocation(binaryPath, args);
561
+ checkedCommands.push(invocation.display);
562
+ return await runCommand(invocation.file, invocation.args);
563
+ };
833
564
  let binaryPath = configuredBinaryPath;
834
- let versionResult = await runClaudeVersionCommand(binaryPath, checkedCommands);
565
+ let versionResult = await runClaude(binaryPath, ["--version"]);
835
566
  // No configured path and no `claude` on PATH: the first install folder whose CLI runs wins.
836
567
  const installFolderCandidates = configuredBinaryPath === DEFAULT_CLAUDE_BINARY ? claudeInstallFolderCandidates() : [];
837
568
  if (isCommandMissing(versionResult)) {
@@ -839,14 +570,14 @@ async function probeAnthropicLocalDiagnostics(options = {}) {
839
570
  if (!existsSync(candidate))
840
571
  continue;
841
572
  binaryPath = candidate;
842
- versionResult = await runClaudeVersionCommand(candidate, checkedCommands);
573
+ versionResult = await runClaude(candidate, ["--version"]);
843
574
  if (!isCommandMissing(versionResult))
844
575
  break;
845
576
  }
846
577
  }
847
578
  if (isCommandMissing(versionResult)) {
848
579
  const alsoChecked = installFolderCandidates.length > 0
849
- ? ` Also checked: ${installFolderCandidates.map((candidate) => sanitizeDisplayText(candidate)).join(", ")}.`
580
+ ? ` Also checked: ${installFolderCandidates.map(sanitizeDisplayText).join(", ")}.`
850
581
  : "";
851
582
  return {
852
583
  installed: false,
@@ -857,50 +588,23 @@ async function probeAnthropicLocalDiagnostics(options = {}) {
857
588
  message: `Claude CLI (\`${sanitizeDisplayText(configuredBinaryPath)}\`) is not installed or not on PATH.${alsoChecked}`,
858
589
  };
859
590
  }
860
- const binaryPathDisplay = binaryPath === DEFAULT_CLAUDE_BINARY ? CLAUDE_ON_PATH_DISPLAY : binaryPath;
861
- const version = parseVersion(`${versionResult.stdout}\n${versionResult.stderr}`);
862
- const authStatusJsonCommand = buildClaudeCommandInvocation(binaryPath, [
863
- "auth",
864
- "status",
865
- "--json",
866
- ]);
867
- checkedCommands.push(authStatusJsonCommand.display);
868
- const authJsonResult = await runClaudeCommand(authStatusJsonCommand);
869
- let parsedAuth = parseClaudeAuthStatusResult(authJsonResult);
591
+ const installed = {
592
+ installed: true,
593
+ version: parseVersion(`${versionResult.stdout}\n${versionResult.stderr}`),
594
+ binaryPath: binaryPath === DEFAULT_CLAUDE_BINARY ? CLAUDE_ON_PATH_DISPLAY : binaryPath,
595
+ checkedCommands,
596
+ };
597
+ let parsedAuth = parseClaudeAuthStatusResult(await runClaude(binaryPath, ["auth", "status", "--json"]));
870
598
  if (parsedAuth.unsupportedCommand) {
871
- const authStatusCommand = buildClaudeCommandInvocation(binaryPath, ["auth", "status"]);
872
- checkedCommands.push(authStatusCommand.display);
873
- parsedAuth = parseClaudeAuthStatusResult(await runClaudeCommand(authStatusCommand));
599
+ parsedAuth = parseClaudeAuthStatusResult(await runClaude(binaryPath, ["auth", "status"]));
874
600
  }
875
601
  if (parsedAuth.authStatus !== "authenticated") {
876
- return {
877
- installed: true,
878
- version,
879
- authStatus: parsedAuth.authStatus,
880
- binaryPath: binaryPathDisplay,
881
- checkedCommands,
882
- message: parsedAuth.message,
883
- };
602
+ return { ...installed, authStatus: parsedAuth.authStatus, message: parsedAuth.message };
884
603
  }
885
- const quota = parsedAuth.jsonPayload ? parseUsageResponse(parsedAuth.jsonPayload) : null;
886
- if (quota) {
887
- return {
888
- installed: true,
889
- version,
890
- authStatus: "authenticated",
891
- binaryPath: binaryPathDisplay,
892
- checkedCommands,
893
- localQuota: quota,
894
- };
895
- }
896
- return {
897
- installed: true,
898
- version,
899
- authStatus: "authenticated",
900
- binaryPath: binaryPathDisplay,
901
- checkedCommands,
902
- message: CLAUDE_NO_LOCAL_QUOTA_MESSAGE,
903
- };
604
+ const localQuota = parseUsageResponse(parsedAuth.jsonPayload);
605
+ return localQuota
606
+ ? { ...installed, authStatus: "authenticated", localQuota }
607
+ : { ...installed, authStatus: "authenticated", message: CLAUDE_NO_LOCAL_QUOTA_MESSAGE };
904
608
  }
905
609
  export function clearAnthropicDiagnosticsCacheForTests() {
906
610
  diagnosticsCache.clear();
@@ -908,148 +612,99 @@ export function clearAnthropicDiagnosticsCacheForTests() {
908
612
  anthropicOAuthCooldowns.clear();
909
613
  anthropicOAuthInFlight.clear();
910
614
  }
911
- async function getCachedAnthropicLocalDiagnostics(options = {}) {
912
- const binaryPath = resolveAnthropicBinaryPath(options.binaryPath);
913
- const now = Date.now();
914
- const cached = localDiagnosticsCache.get(binaryPath) ?? {
915
- timestamp: 0,
916
- value: null,
917
- };
918
- if (cached.value &&
919
- cached.timestamp > 0 &&
920
- now - cached.timestamp < ANTHROPIC_DIAGNOSTICS_TTL_MS) {
615
+ /**
616
+ * Reuses a probe result for a few seconds and shares one in-flight probe
617
+ * between concurrent callers. A failed probe is dropped so the next call retries.
618
+ */
619
+ async function getCachedProbe(cache, key, probe) {
620
+ const cached = cache.get(key);
621
+ if (cached && "inFlight" in cached)
622
+ return await cached.inFlight;
623
+ if (cached && Date.now() - cached.timestamp < ANTHROPIC_DIAGNOSTICS_TTL_MS)
921
624
  return cached.value;
922
- }
923
- if (cached.inFlight) {
924
- return cached.inFlight;
925
- }
926
- const inFlight = probeAnthropicLocalDiagnostics({ binaryPath }).then((value) => {
927
- localDiagnosticsCache.set(binaryPath, {
928
- timestamp: Date.now(),
929
- value,
930
- });
931
- return value;
932
- });
933
- localDiagnosticsCache.set(binaryPath, {
934
- timestamp: cached.timestamp,
935
- value: cached.value,
936
- inFlight,
937
- });
625
+ const pending = { inFlight: probe() };
626
+ cache.set(key, pending);
938
627
  try {
939
- return await inFlight;
628
+ const value = await pending.inFlight;
629
+ cache.set(key, { value, timestamp: Date.now() });
630
+ return value;
940
631
  }
941
- finally {
942
- const latest = localDiagnosticsCache.get(binaryPath);
943
- if (latest?.inFlight === inFlight) {
944
- localDiagnosticsCache.set(binaryPath, {
945
- timestamp: latest.timestamp,
946
- value: latest.value,
947
- });
948
- }
632
+ catch (error) {
633
+ if (cache.get(key) === pending)
634
+ cache.delete(key);
635
+ throw error;
949
636
  }
950
637
  }
951
- export async function getAnthropicDiagnostics(options = {}) {
952
- const binaryPath = resolveAnthropicBinaryPath(options.binaryPath);
953
- const now = Date.now();
954
- const cached = diagnosticsCache.get(binaryPath) ?? {
955
- timestamp: 0,
956
- value: null,
638
+ async function getCachedAnthropicLocalDiagnostics(binaryPath) {
639
+ const resolvedBinaryPath = resolveAnthropicBinaryPath(binaryPath);
640
+ return await getCachedProbe(localDiagnosticsCache, resolvedBinaryPath, () => probeAnthropicLocalDiagnostics(resolvedBinaryPath));
641
+ }
642
+ function buildDiagnostics(local, outcome) {
643
+ return {
644
+ installed: local.installed,
645
+ version: local.version,
646
+ authStatus: local.authStatus,
647
+ quotaSupported: outcome.quota !== undefined,
648
+ quotaSource: outcome.quotaSource,
649
+ ...(outcome.oauthCredentialSource
650
+ ? { oauthCredentialSource: outcome.oauthCredentialSource }
651
+ : {}),
652
+ binaryPath: local.binaryPath,
653
+ checkedCommands: local.checkedCommands,
654
+ ...(outcome.message ? { message: outcome.message } : {}),
655
+ ...(outcome.quota ? { quota: outcome.quota } : {}),
957
656
  };
958
- if (cached.value &&
959
- cached.timestamp > 0 &&
960
- now - cached.timestamp < ANTHROPIC_DIAGNOSTICS_TTL_MS) {
961
- return cached.value;
962
- }
963
- if (cached.inFlight) {
964
- return cached.inFlight;
657
+ }
658
+ async function probeAnthropicDiagnostics(binaryPath, requestTimeoutMs) {
659
+ const local = await getCachedAnthropicLocalDiagnostics(binaryPath);
660
+ if (local.localQuota) {
661
+ return buildDiagnostics(local, {
662
+ quotaSource: "claude-auth-status-json",
663
+ quota: local.localQuota,
664
+ });
965
665
  }
966
- const inFlight = (async () => {
967
- const localDiagnostics = await getCachedAnthropicLocalDiagnostics({ binaryPath });
968
- if (localDiagnostics.localQuota) {
969
- return mapLocalDiagnosticsToAnthropicDiagnostics(localDiagnostics);
970
- }
971
- let credentials = await readAnthropicOAuthAccessToken({
972
- includeClaudeCredentials: localDiagnostics.authStatus === "authenticated",
666
+ const claudeAuthenticated = local.authStatus === "authenticated";
667
+ let credentials = await readAnthropicOAuthAccessToken({
668
+ includeClaudeCredentials: claudeAuthenticated,
669
+ });
670
+ if (credentials.state !== "configured") {
671
+ return buildDiagnostics(local, {
672
+ quotaSource: "none",
673
+ message: claudeAuthenticated
674
+ ? buildAnthropicNoQuotaDiagnosticsMessage(credentials.detail)
675
+ : local.message,
973
676
  });
974
- if (credentials.state !== "configured") {
975
- if (localDiagnostics.authStatus !== "authenticated") {
976
- return mapLocalDiagnosticsToAnthropicDiagnostics(localDiagnostics);
977
- }
978
- const diagnostics = {
979
- installed: localDiagnostics.installed,
980
- version: localDiagnostics.version,
981
- authStatus: localDiagnostics.authStatus,
982
- quotaSupported: false,
983
- quotaSource: "none",
984
- binaryPath: localDiagnostics.binaryPath,
985
- checkedCommands: localDiagnostics.checkedCommands,
986
- message: buildAnthropicNoQuotaDiagnosticsMessage(credentials.detail),
987
- };
988
- return diagnostics;
989
- }
990
- let fallbackQuota = await queryAnthropicQuotaFromOAuthAccessToken(credentials.accessToken, options.requestTimeoutMs);
991
- if (fallbackQuota.state === "unavailable" &&
992
- fallbackQuota.failureKind === "authentication" &&
993
- credentials.source === "opencode-auth" &&
994
- localDiagnostics.authStatus === "authenticated") {
995
- const claudeCredentials = await readClaudeOAuthAccessToken();
996
- if (claudeCredentials.state === "configured") {
997
- credentials = claudeCredentials;
998
- fallbackQuota = await queryAnthropicQuotaFromOAuthAccessToken(claudeCredentials.accessToken, options.requestTimeoutMs);
999
- }
1000
- }
1001
- if (fallbackQuota.state !== "success") {
1002
- const diagnostics = {
1003
- installed: localDiagnostics.installed,
1004
- version: localDiagnostics.version,
1005
- authStatus: localDiagnostics.authStatus,
1006
- quotaSupported: false,
1007
- quotaSource: "none",
1008
- oauthCredentialSource: credentials.source,
1009
- binaryPath: localDiagnostics.binaryPath,
1010
- checkedCommands: localDiagnostics.checkedCommands,
1011
- message: buildAnthropicNoQuotaDiagnosticsMessage(fallbackQuota.detail),
1012
- };
1013
- return diagnostics;
1014
- }
1015
- const diagnostics = {
1016
- installed: localDiagnostics.installed,
1017
- version: localDiagnostics.version,
1018
- authStatus: localDiagnostics.authStatus,
1019
- quotaSupported: true,
1020
- quotaSource: credentials.source === "opencode-auth"
1021
- ? "opencode-auth-oauth-api"
1022
- : "claude-credentials-oauth-api",
677
+ }
678
+ let fallbackQuota = await queryAnthropicQuotaFromOAuthAccessToken(credentials.accessToken, requestTimeoutMs);
679
+ // A rejected OpenCode login falls back to Claude's own credentials when the Claude CLI is signed in.
680
+ if (fallbackQuota.state === "unavailable" &&
681
+ fallbackQuota.failureKind === "authentication" &&
682
+ credentials.source === "opencode-auth" &&
683
+ claudeAuthenticated) {
684
+ const claudeCredentials = await readClaudeOAuthAccessToken();
685
+ if (claudeCredentials.state === "configured") {
686
+ credentials = claudeCredentials;
687
+ fallbackQuota = await queryAnthropicQuotaFromOAuthAccessToken(claudeCredentials.accessToken, requestTimeoutMs);
688
+ }
689
+ }
690
+ if (fallbackQuota.state !== "success") {
691
+ return buildDiagnostics(local, {
692
+ quotaSource: "none",
1023
693
  oauthCredentialSource: credentials.source,
1024
- binaryPath: localDiagnostics.binaryPath,
1025
- checkedCommands: localDiagnostics.checkedCommands,
1026
- quota: fallbackQuota.quota,
1027
- };
1028
- return diagnostics;
1029
- })().then((value) => {
1030
- diagnosticsCache.set(binaryPath, {
1031
- timestamp: Date.now(),
1032
- value,
694
+ message: buildAnthropicNoQuotaDiagnosticsMessage(fallbackQuota.detail),
1033
695
  });
1034
- return value;
1035
- });
1036
- diagnosticsCache.set(binaryPath, {
1037
- timestamp: cached.timestamp,
1038
- value: cached.value,
1039
- inFlight,
1040
- });
1041
- try {
1042
- return await inFlight;
1043
- }
1044
- finally {
1045
- const latest = diagnosticsCache.get(binaryPath);
1046
- if (latest?.inFlight === inFlight) {
1047
- diagnosticsCache.set(binaryPath, {
1048
- timestamp: latest.timestamp,
1049
- value: latest.value,
1050
- });
1051
- }
1052
696
  }
697
+ return buildDiagnostics(local, {
698
+ quotaSource: credentials.source === "opencode-auth"
699
+ ? "opencode-auth-oauth-api"
700
+ : "claude-credentials-oauth-api",
701
+ oauthCredentialSource: credentials.source,
702
+ quota: fallbackQuota.quota,
703
+ });
704
+ }
705
+ export async function getAnthropicDiagnostics(options = {}) {
706
+ const binaryPath = resolveAnthropicBinaryPath(options.binaryPath);
707
+ return await getCachedProbe(diagnosticsCache, binaryPath, () => probeAnthropicDiagnostics(binaryPath, options.requestTimeoutMs));
1053
708
  }
1054
709
  export async function hasAnthropicCredentialsConfigured(options = {}) {
1055
710
  try {
@@ -1063,7 +718,7 @@ export async function hasAnthropicCredentialsConfigured(options = {}) {
1063
718
  // Fall back to the existing local Claude CLI probe.
1064
719
  }
1065
720
  try {
1066
- const diagnostics = await getCachedAnthropicLocalDiagnostics(options);
721
+ const diagnostics = await getCachedAnthropicLocalDiagnostics(options.binaryPath);
1067
722
  return diagnostics.installed && diagnostics.authStatus === "authenticated";
1068
723
  }
1069
724
  catch {
@@ -1073,7 +728,7 @@ export async function hasAnthropicCredentialsConfigured(options = {}) {
1073
728
  export async function resolveAnthropicAuthIdentity(options = {}) {
1074
729
  let localDiagnostics;
1075
730
  try {
1076
- localDiagnostics = await getCachedAnthropicLocalDiagnostics(options);
731
+ localDiagnostics = await getCachedAnthropicLocalDiagnostics(options.binaryPath);
1077
732
  }
1078
733
  catch {
1079
734
  return null;
@@ -1089,9 +744,8 @@ export async function resolveAnthropicAuthIdentity(options = {}) {
1089
744
  principal: { kind: "credential", value: opencodeCredentials.accessToken },
1090
745
  })
1091
746
  : null;
1092
- if (localDiagnostics.authStatus !== "authenticated") {
747
+ if (localDiagnostics.authStatus !== "authenticated")
1093
748
  return opencodeIdentity;
1094
- }
1095
749
  const claudeCredentials = await readClaudeOAuthAccessToken();
1096
750
  const claudeIdentity = claudeCredentials.state === "configured"
1097
751
  ? await deriveResolvedAuthIdentity({
@@ -1110,23 +764,19 @@ export async function resolveAnthropicAuthIdentity(options = {}) {
1110
764
  export async function queryAnthropicQuota(options = {}) {
1111
765
  try {
1112
766
  const diagnostics = await getAnthropicDiagnostics(options);
1113
- if (diagnostics.quotaSupported) {
767
+ if (diagnostics.quotaSupported)
1114
768
  return diagnostics.quota ?? null;
1115
- }
1116
769
  if ((diagnostics.authStatus === "authenticated" ||
1117
770
  diagnostics.oauthCredentialSource !== undefined) &&
1118
771
  diagnostics.message) {
1119
- return {
1120
- success: false,
1121
- error: diagnostics.message,
1122
- };
772
+ return { success: false, error: diagnostics.message };
1123
773
  }
1124
774
  return null;
1125
775
  }
1126
776
  catch (err) {
1127
777
  return {
1128
778
  success: false,
1129
- error: `Claude CLI probe failed: ${sanitizeDisplayText(err instanceof Error ? err.message : String(err))}`,
779
+ error: `Claude CLI probe failed: ${sanitizeDisplayText(errorText(err))}`,
1130
780
  };
1131
781
  }
1132
782
  }