@slkiser/opencode-quota 5.0.3 → 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 +30 -44
  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/index.d.ts +2 -1
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js.map +1 -1
  68. package/dist/lib/accounting-format.d.ts +2 -52
  69. package/dist/lib/accounting-format.d.ts.map +1 -1
  70. package/dist/lib/accounting-format.js +6 -255
  71. package/dist/lib/accounting-format.js.map +1 -1
  72. package/dist/lib/alibaba-auth.d.ts +14 -21
  73. package/dist/lib/alibaba-auth.d.ts.map +1 -1
  74. package/dist/lib/alibaba-auth.js +36 -149
  75. package/dist/lib/alibaba-auth.js.map +1 -1
  76. package/dist/lib/alibaba-coding-plan-local-quota.d.ts +1 -6
  77. package/dist/lib/alibaba-coding-plan-local-quota.d.ts.map +1 -1
  78. package/dist/lib/alibaba-coding-plan-local-quota.js +1 -1
  79. package/dist/lib/alibaba-coding-plan-local-quota.js.map +1 -1
  80. package/dist/lib/alibaba-token-plan.d.ts +18 -27
  81. package/dist/lib/alibaba-token-plan.d.ts.map +1 -1
  82. package/dist/lib/alibaba-token-plan.js +121 -285
  83. package/dist/lib/alibaba-token-plan.js.map +1 -1
  84. package/dist/lib/anthropic-auth.d.ts +3 -5
  85. package/dist/lib/anthropic-auth.d.ts.map +1 -1
  86. package/dist/lib/anthropic-auth.js +6 -9
  87. package/dist/lib/anthropic-auth.js.map +1 -1
  88. package/dist/lib/anthropic.d.ts +12 -37
  89. package/dist/lib/anthropic.d.ts.map +1 -1
  90. package/dist/lib/anthropic.js +348 -698
  91. package/dist/lib/anthropic.js.map +1 -1
  92. package/dist/lib/api-key-resolver.d.ts +165 -192
  93. package/dist/lib/api-key-resolver.d.ts.map +1 -1
  94. package/dist/lib/api-key-resolver.js +208 -234
  95. package/dist/lib/api-key-resolver.js.map +1 -1
  96. package/dist/lib/atomic-json.d.ts +4 -1
  97. package/dist/lib/atomic-json.d.ts.map +1 -1
  98. package/dist/lib/atomic-json.js +2 -3
  99. package/dist/lib/atomic-json.js.map +1 -1
  100. package/dist/lib/calendar-date.d.ts +15 -0
  101. package/dist/lib/calendar-date.d.ts.map +1 -0
  102. package/dist/lib/calendar-date.js +21 -0
  103. package/dist/lib/calendar-date.js.map +1 -0
  104. package/dist/lib/chutes.d.ts +0 -1
  105. package/dist/lib/chutes.d.ts.map +1 -1
  106. package/dist/lib/chutes.js +2 -4
  107. package/dist/lib/chutes.js.map +1 -1
  108. package/dist/lib/cli-reports.d.ts +15 -11
  109. package/dist/lib/cli-reports.d.ts.map +1 -1
  110. package/dist/lib/cli-reports.js +34 -107
  111. package/dist/lib/cli-reports.js.map +1 -1
  112. package/dist/lib/cli-show.d.ts +9 -22
  113. package/dist/lib/cli-show.d.ts.map +1 -1
  114. package/dist/lib/cli-show.js +104 -75
  115. package/dist/lib/cli-show.js.map +1 -1
  116. package/dist/lib/config-file-utils.d.ts +3 -15
  117. package/dist/lib/config-file-utils.d.ts.map +1 -1
  118. package/dist/lib/config-file-utils.js +4 -63
  119. package/dist/lib/config-file-utils.js.map +1 -1
  120. package/dist/lib/config-write-target.d.ts +4 -7
  121. package/dist/lib/config-write-target.d.ts.map +1 -1
  122. package/dist/lib/config-write-target.js +4 -18
  123. package/dist/lib/config-write-target.js.map +1 -1
  124. package/dist/lib/copilot.d.ts +29 -20
  125. package/dist/lib/copilot.d.ts.map +1 -1
  126. package/dist/lib/copilot.js +392 -649
  127. package/dist/lib/copilot.js.map +1 -1
  128. package/dist/lib/cursor-detection.d.ts +3 -3
  129. package/dist/lib/cursor-detection.d.ts.map +1 -1
  130. package/dist/lib/cursor-detection.js +44 -88
  131. package/dist/lib/cursor-detection.js.map +1 -1
  132. package/dist/lib/cursor-pricing.d.ts +71 -8
  133. package/dist/lib/cursor-pricing.d.ts.map +1 -1
  134. package/dist/lib/cursor-pricing.js +33 -125
  135. package/dist/lib/cursor-pricing.js.map +1 -1
  136. package/dist/lib/cursor-usage.d.ts +6 -4
  137. package/dist/lib/cursor-usage.d.ts.map +1 -1
  138. package/dist/lib/cursor-usage.js +27 -40
  139. package/dist/lib/cursor-usage.js.map +1 -1
  140. package/dist/lib/deepseek.d.ts +9 -17
  141. package/dist/lib/deepseek.d.ts.map +1 -1
  142. package/dist/lib/deepseek.js +24 -54
  143. package/dist/lib/deepseek.js.map +1 -1
  144. package/dist/lib/display-sanitize.d.ts +0 -8
  145. package/dist/lib/display-sanitize.d.ts.map +1 -1
  146. package/dist/lib/display-sanitize.js +0 -139
  147. package/dist/lib/display-sanitize.js.map +1 -1
  148. package/dist/lib/entries.d.ts +13 -239
  149. package/dist/lib/entries.d.ts.map +1 -1
  150. package/dist/lib/entries.js +1 -46
  151. package/dist/lib/entries.js.map +1 -1
  152. package/dist/lib/file-lock.d.ts +23 -0
  153. package/dist/lib/file-lock.d.ts.map +1 -0
  154. package/dist/lib/file-lock.js +122 -0
  155. package/dist/lib/file-lock.js.map +1 -0
  156. package/dist/lib/format-utils.d.ts +2 -82
  157. package/dist/lib/format-utils.d.ts.map +1 -1
  158. package/dist/lib/format-utils.js +2 -191
  159. package/dist/lib/format-utils.js.map +1 -1
  160. package/dist/lib/glm-coding-plan.d.ts +6 -5
  161. package/dist/lib/glm-coding-plan.d.ts.map +1 -1
  162. package/dist/lib/glm-coding-plan.js +19 -1
  163. package/dist/lib/glm-coding-plan.js.map +1 -1
  164. package/dist/lib/google-agy.d.ts +8 -40
  165. package/dist/lib/google-agy.d.ts.map +1 -1
  166. package/dist/lib/google-agy.js +88 -519
  167. package/dist/lib/google-agy.js.map +1 -1
  168. package/dist/lib/google-companion-credentials.d.ts +9 -40
  169. package/dist/lib/google-companion-credentials.d.ts.map +1 -1
  170. package/dist/lib/google-companion-credentials.js +167 -224
  171. package/dist/lib/google-companion-credentials.js.map +1 -1
  172. package/dist/lib/google-gemini-cli.d.ts +5 -38
  173. package/dist/lib/google-gemini-cli.d.ts.map +1 -1
  174. package/dist/lib/google-gemini-cli.js +71 -442
  175. package/dist/lib/google-gemini-cli.js.map +1 -1
  176. package/dist/lib/google-oauth-quota.d.ts +76 -0
  177. package/dist/lib/google-oauth-quota.d.ts.map +1 -0
  178. package/dist/lib/google-oauth-quota.js +297 -0
  179. package/dist/lib/google-oauth-quota.js.map +1 -0
  180. package/dist/lib/google-token-cache.d.ts +3 -5
  181. package/dist/lib/google-token-cache.d.ts.map +1 -1
  182. package/dist/lib/google-token-cache.js +2 -14
  183. package/dist/lib/google-token-cache.js.map +1 -1
  184. package/dist/lib/home-dir-display.d.ts.map +1 -1
  185. package/dist/lib/home-dir-display.js +21 -39
  186. package/dist/lib/home-dir-display.js.map +1 -1
  187. package/dist/lib/http.d.ts +4 -1
  188. package/dist/lib/http.d.ts.map +1 -1
  189. package/dist/lib/http.js +2 -1
  190. package/dist/lib/http.js.map +1 -1
  191. package/dist/lib/json-guards.d.ts +11 -0
  192. package/dist/lib/json-guards.d.ts.map +1 -0
  193. package/dist/lib/json-guards.js +25 -0
  194. package/dist/lib/json-guards.js.map +1 -0
  195. package/dist/lib/kilo.d.ts +0 -2
  196. package/dist/lib/kilo.d.ts.map +1 -1
  197. package/dist/lib/kilo.js +33 -116
  198. package/dist/lib/kilo.js.map +1 -1
  199. package/dist/lib/kimi-endpoints.d.ts +2 -2
  200. package/dist/lib/kimi-endpoints.d.ts.map +1 -1
  201. package/dist/lib/kimi-endpoints.js +1 -1
  202. package/dist/lib/kimi-endpoints.js.map +1 -1
  203. package/dist/lib/kimi.d.ts.map +1 -1
  204. package/dist/lib/kimi.js +40 -86
  205. package/dist/lib/kimi.js.map +1 -1
  206. package/dist/lib/maintainer-announcements.d.ts +4 -17
  207. package/dist/lib/maintainer-announcements.d.ts.map +1 -1
  208. package/dist/lib/maintainer-announcements.js +7 -44
  209. package/dist/lib/maintainer-announcements.js.map +1 -1
  210. package/dist/lib/maintainer-home-notice.d.ts +19 -0
  211. package/dist/lib/maintainer-home-notice.d.ts.map +1 -0
  212. package/dist/lib/maintainer-home-notice.js +92 -0
  213. package/dist/lib/maintainer-home-notice.js.map +1 -0
  214. package/dist/lib/mimo-config.d.ts +6 -9
  215. package/dist/lib/mimo-config.d.ts.map +1 -1
  216. package/dist/lib/mimo-config.js +43 -74
  217. package/dist/lib/mimo-config.js.map +1 -1
  218. package/dist/lib/mimo.d.ts +2 -5
  219. package/dist/lib/mimo.d.ts.map +1 -1
  220. package/dist/lib/mimo.js +57 -109
  221. package/dist/lib/mimo.js.map +1 -1
  222. package/dist/lib/minimax-endpoints.d.ts +2 -2
  223. package/dist/lib/minimax-endpoints.d.ts.map +1 -1
  224. package/dist/lib/minimax-endpoints.js +1 -1
  225. package/dist/lib/minimax-endpoints.js.map +1 -1
  226. package/dist/lib/modelsdev-pricing.d.ts +22 -16
  227. package/dist/lib/modelsdev-pricing.d.ts.map +1 -1
  228. package/dist/lib/modelsdev-pricing.js +279 -560
  229. package/dist/lib/modelsdev-pricing.js.map +1 -1
  230. package/dist/lib/nanogpt.d.ts +6 -6
  231. package/dist/lib/nanogpt.d.ts.map +1 -1
  232. package/dist/lib/nanogpt.js +19 -72
  233. package/dist/lib/nanogpt.js.map +1 -1
  234. package/dist/lib/ollama-cloud.d.ts +3 -6
  235. package/dist/lib/ollama-cloud.d.ts.map +1 -1
  236. package/dist/lib/ollama-cloud.js +26 -37
  237. package/dist/lib/ollama-cloud.js.map +1 -1
  238. package/dist/lib/openai.d.ts +18 -29
  239. package/dist/lib/openai.d.ts.map +1 -1
  240. package/dist/lib/openai.js +108 -182
  241. package/dist/lib/openai.js.map +1 -1
  242. package/dist/lib/opencode-auth-sqlite.d.ts.map +1 -1
  243. package/dist/lib/opencode-auth-sqlite.js +22 -23
  244. package/dist/lib/opencode-auth-sqlite.js.map +1 -1
  245. package/dist/lib/opencode-auth.d.ts +17 -11
  246. package/dist/lib/opencode-auth.d.ts.map +1 -1
  247. package/dist/lib/opencode-auth.js +39 -46
  248. package/dist/lib/opencode-auth.js.map +1 -1
  249. package/dist/lib/opencode-config-editor.d.ts +3 -34
  250. package/dist/lib/opencode-config-editor.d.ts.map +1 -1
  251. package/dist/lib/opencode-config-editor.js +23 -142
  252. package/dist/lib/opencode-config-editor.js.map +1 -1
  253. package/dist/lib/opencode-config-providers.d.ts +4 -3
  254. package/dist/lib/opencode-config-providers.d.ts.map +1 -1
  255. package/dist/lib/opencode-config-providers.js +7 -11
  256. package/dist/lib/opencode-config-providers.js.map +1 -1
  257. package/dist/lib/opencode-config-read.d.ts +2 -1
  258. package/dist/lib/opencode-config-read.d.ts.map +1 -1
  259. package/dist/lib/opencode-config-read.js +3 -2
  260. package/dist/lib/opencode-config-read.js.map +1 -1
  261. package/dist/lib/opencode-console-auth.d.ts +2 -3
  262. package/dist/lib/opencode-console-auth.d.ts.map +1 -1
  263. package/dist/lib/opencode-console-auth.js +2 -2
  264. package/dist/lib/opencode-console-auth.js.map +1 -1
  265. package/dist/lib/opencode-go.d.ts.map +1 -1
  266. package/dist/lib/opencode-go.js +51 -79
  267. package/dist/lib/opencode-go.js.map +1 -1
  268. package/dist/lib/opencode-storage.d.ts +18 -3
  269. package/dist/lib/opencode-storage.d.ts.map +1 -1
  270. package/dist/lib/opencode-storage.js +134 -2
  271. package/dist/lib/opencode-storage.js.map +1 -1
  272. package/dist/lib/opencode-zen.d.ts +15 -12
  273. package/dist/lib/opencode-zen.d.ts.map +1 -1
  274. package/dist/lib/opencode-zen.js +139 -147
  275. package/dist/lib/opencode-zen.js.map +1 -1
  276. package/dist/lib/openrouter.d.ts.map +1 -1
  277. package/dist/lib/openrouter.js +1 -13
  278. package/dist/lib/openrouter.js.map +1 -1
  279. package/dist/lib/pricing-key.d.ts +48 -0
  280. package/dist/lib/pricing-key.d.ts.map +1 -0
  281. package/dist/lib/pricing-key.js +371 -0
  282. package/dist/lib/pricing-key.js.map +1 -0
  283. package/dist/lib/provider-metadata.d.ts +16 -20
  284. package/dist/lib/provider-metadata.d.ts.map +1 -1
  285. package/dist/lib/provider-metadata.js +69 -69
  286. package/dist/lib/provider-metadata.js.map +1 -1
  287. package/dist/lib/provider-model-matching.d.ts +2 -1
  288. package/dist/lib/provider-model-matching.d.ts.map +1 -1
  289. package/dist/lib/provider-registration.d.ts +1 -177
  290. package/dist/lib/provider-registration.d.ts.map +1 -1
  291. package/dist/lib/provider-registration.js +1 -163
  292. package/dist/lib/provider-registration.js.map +1 -1
  293. package/dist/lib/quota-dialog-commands.d.ts +87 -53
  294. package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
  295. package/dist/lib/quota-dialog-commands.js +259 -519
  296. package/dist/lib/quota-dialog-commands.js.map +1 -1
  297. package/dist/lib/quota-export-types.d.ts +29 -23
  298. package/dist/lib/quota-export-types.d.ts.map +1 -1
  299. package/dist/lib/quota-export.d.ts +16 -26
  300. package/dist/lib/quota-export.d.ts.map +1 -1
  301. package/dist/lib/quota-export.js +105 -147
  302. package/dist/lib/quota-export.js.map +1 -1
  303. package/dist/lib/quota-providers-local.d.ts +12 -8
  304. package/dist/lib/quota-providers-local.d.ts.map +1 -1
  305. package/dist/lib/quota-providers-local.js +150 -223
  306. package/dist/lib/quota-providers-local.js.map +1 -1
  307. package/dist/lib/quota-providers-remote.d.ts +3 -8
  308. package/dist/lib/quota-providers-remote.d.ts.map +1 -1
  309. package/dist/lib/quota-providers-remote.js +309 -449
  310. package/dist/lib/quota-providers-remote.js.map +1 -1
  311. package/dist/lib/quota-providers.d.ts +57 -15
  312. package/dist/lib/quota-providers.d.ts.map +1 -1
  313. package/dist/lib/quota-providers.js +157 -64
  314. package/dist/lib/quota-providers.js.map +1 -1
  315. package/dist/lib/quota-report-message.d.ts +23 -10
  316. package/dist/lib/quota-report-message.d.ts.map +1 -1
  317. package/dist/lib/quota-report-message.js +37 -13
  318. package/dist/lib/quota-report-message.js.map +1 -1
  319. package/dist/lib/quota-retry-wait.d.ts +14 -6
  320. package/dist/lib/quota-retry-wait.d.ts.map +1 -1
  321. package/dist/lib/quota-retry-wait.js +37 -39
  322. package/dist/lib/quota-retry-wait.js.map +1 -1
  323. package/dist/lib/quota-status.d.ts +50 -33
  324. package/dist/lib/quota-status.d.ts.map +1 -1
  325. package/dist/lib/quota-status.js +1113 -773
  326. package/dist/lib/quota-status.js.map +1 -1
  327. package/dist/lib/quota-telemetry.d.ts +7 -14
  328. package/dist/lib/quota-telemetry.d.ts.map +1 -1
  329. package/dist/lib/quota-telemetry.js +46 -97
  330. package/dist/lib/quota-telemetry.js.map +1 -1
  331. package/dist/lib/report-document.d.ts +5 -65
  332. package/dist/lib/report-document.d.ts.map +1 -1
  333. package/dist/lib/report-document.js +14 -167
  334. package/dist/lib/report-document.js.map +1 -1
  335. package/dist/lib/resolved-auth-identity.d.ts +1 -2
  336. package/dist/lib/resolved-auth-identity.d.ts.map +1 -1
  337. package/dist/lib/resolved-auth-identity.js +0 -4
  338. package/dist/lib/resolved-auth-identity.js.map +1 -1
  339. package/dist/lib/session-tokens.d.ts +19 -19
  340. package/dist/lib/session-tokens.d.ts.map +1 -1
  341. package/dist/lib/session-tokens.js +58 -44
  342. package/dist/lib/session-tokens.js.map +1 -1
  343. package/dist/lib/synthetic.d.ts +0 -1
  344. package/dist/lib/synthetic.d.ts.map +1 -1
  345. package/dist/lib/synthetic.js +43 -94
  346. package/dist/lib/synthetic.js.map +1 -1
  347. package/dist/lib/token-buckets.d.ts +0 -1
  348. package/dist/lib/token-buckets.d.ts.map +1 -1
  349. package/dist/lib/token-buckets.js +0 -3
  350. package/dist/lib/token-buckets.js.map +1 -1
  351. package/dist/lib/token-cost.d.ts +2 -1
  352. package/dist/lib/token-cost.d.ts.map +1 -1
  353. package/dist/lib/types.d.ts +25 -333
  354. package/dist/lib/types.d.ts.map +1 -1
  355. package/dist/lib/types.js +2 -70
  356. package/dist/lib/types.js.map +1 -1
  357. package/dist/lib/xai.d.ts +6 -6
  358. package/dist/lib/xai.d.ts.map +1 -1
  359. package/dist/lib/xai.js +51 -90
  360. package/dist/lib/xai.js.map +1 -1
  361. package/dist/plugin.d.ts +6 -3
  362. package/dist/plugin.d.ts.map +1 -1
  363. package/dist/plugin.js +315 -90
  364. package/dist/plugin.js.map +1 -1
  365. package/dist/providers/alibaba-coding-plan.d.ts +4 -0
  366. package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
  367. package/dist/providers/alibaba-coding-plan.js +47 -77
  368. package/dist/providers/alibaba-coding-plan.js.map +1 -1
  369. package/dist/providers/alibaba-token-plan.d.ts.map +1 -1
  370. package/dist/providers/alibaba-token-plan.js +34 -46
  371. package/dist/providers/alibaba-token-plan.js.map +1 -1
  372. package/dist/providers/anthropic.d.ts +2 -4
  373. package/dist/providers/anthropic.d.ts.map +1 -1
  374. package/dist/providers/anthropic.js +80 -162
  375. package/dist/providers/anthropic.js.map +1 -1
  376. package/dist/providers/cache-policies.d.ts +0 -2
  377. package/dist/providers/cache-policies.d.ts.map +1 -1
  378. package/dist/providers/cache-policies.js +38 -88
  379. package/dist/providers/cache-policies.js.map +1 -1
  380. package/dist/providers/chutes.d.ts +0 -3
  381. package/dist/providers/chutes.d.ts.map +1 -1
  382. package/dist/providers/chutes.js +16 -28
  383. package/dist/providers/chutes.js.map +1 -1
  384. package/dist/providers/contract.d.ts +128 -0
  385. package/dist/providers/contract.d.ts.map +1 -0
  386. package/dist/providers/contract.js +101 -0
  387. package/dist/providers/contract.js.map +1 -0
  388. package/dist/providers/copilot.d.ts.map +1 -1
  389. package/dist/providers/copilot.js +171 -175
  390. package/dist/providers/copilot.js.map +1 -1
  391. package/dist/providers/cursor.d.ts.map +1 -1
  392. package/dist/providers/cursor.js +56 -109
  393. package/dist/providers/cursor.js.map +1 -1
  394. package/dist/providers/deepseek.d.ts +1 -6
  395. package/dist/providers/deepseek.d.ts.map +1 -1
  396. package/dist/providers/deepseek.js +46 -81
  397. package/dist/providers/deepseek.js.map +1 -1
  398. package/dist/providers/glm-coding-plan.d.ts +8 -0
  399. package/dist/providers/glm-coding-plan.d.ts.map +1 -0
  400. package/dist/providers/glm-coding-plan.js +106 -0
  401. package/dist/providers/glm-coding-plan.js.map +1 -0
  402. package/dist/providers/google-agy.d.ts +0 -1
  403. package/dist/providers/google-agy.d.ts.map +1 -1
  404. package/dist/providers/google-agy.js +41 -192
  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 -6
  433. package/dist/providers/ollama-cloud.d.ts.map +1 -1
  434. package/dist/providers/ollama-cloud.js +86 -112
  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 +144 -166
  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 +100 -150
  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 -1092
  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 -21
  719. package/dist/lib/quota-surface-data.d.ts.map +0 -1
  720. package/dist/lib/quota-surface-data.js +0 -362
  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
@@ -7,16 +7,14 @@
7
7
  */
8
8
  import { existsSync, readFileSync } from "fs";
9
9
  import { join } from "path";
10
- import { sanitizeDisplaySnippet, sanitizeDisplayText } from "./display-sanitize.js";
10
+ import { sanitizeDisplaySnippet, sanitizeDisplayText, sanitizeSingleLineDisplaySnippet, } from "./display-sanitize.js";
11
11
  import { fetchWithTimeout } from "./http.js";
12
+ import { finiteNumber } from "./json-guards.js";
12
13
  import { readAuthFile } from "./opencode-auth.js";
13
14
  import { getOpencodeRuntimeDirs } from "./opencode-runtime-paths.js";
14
15
  import { deriveResolvedAuthIdentity } from "./resolved-auth-identity.js";
15
16
  const GITHUB_API_BASE_URL = "https://api.github.com";
16
- const GITHUB_API_VERSION = "2026-03-10";
17
17
  const COPILOT_QUOTA_CONFIG_FILENAME = "copilot-quota-token.json";
18
- const USER_AGENT = "opencode-quota/copilot-billing";
19
- const COPILOT_INTERNAL_USER_PATH = "/copilot_internal/user";
20
18
  /** Integration ids that can hold the Copilot OAuth login, in precedence order. */
21
19
  export const COPILOT_AUTH_KEYS = [
22
20
  "github-copilot",
@@ -24,10 +22,33 @@ export const COPILOT_AUTH_KEYS = [
24
22
  "copilot-chat",
25
23
  "github-copilot-chat",
26
24
  ];
25
+ const VALID_TIERS = [
26
+ "free",
27
+ "student",
28
+ "pro",
29
+ "pro+",
30
+ "max",
31
+ "business",
32
+ "enterprise",
33
+ ];
27
34
  const LEGACY_PREMIUM_REQUEST_TOTALS = {
28
35
  pro: 300,
29
36
  "pro+": 1500,
30
37
  };
38
+ /** More specific budgets win when several apply to the same target. */
39
+ const BUDGET_SCOPE_SPECIFICITY = {
40
+ user: 5,
41
+ multi_user_cost_center: 4,
42
+ multi_user_customer: 3,
43
+ organization: 2,
44
+ enterprise: 1,
45
+ };
46
+ function errorText(error) {
47
+ return error instanceof Error ? error.message : String(error);
48
+ }
49
+ function toQuotaError(message) {
50
+ return { success: false, error: message };
51
+ }
31
52
  function validateEnterpriseHost(value) {
32
53
  if (value === undefined || value === null)
33
54
  return {};
@@ -56,7 +77,7 @@ function validateEnterpriseHost(value) {
56
77
  url.username ||
57
78
  url.password ||
58
79
  url.port ||
59
- (url.pathname !== "" && url.pathname !== "/") ||
80
+ url.pathname !== "/" ||
60
81
  url.search ||
61
82
  url.hash) {
62
83
  return invalid;
@@ -80,9 +101,6 @@ function validateEnterpriseHost(value) {
80
101
  function getApiBaseUrl(enterpriseHost) {
81
102
  return enterpriseHost ? `https://api.${enterpriseHost}` : GITHUB_API_BASE_URL;
82
103
  }
83
- function getApiHost(apiBaseUrl) {
84
- return new URL(apiBaseUrl).hostname;
85
- }
86
104
  function classifyPatTokenKind(token) {
87
105
  if (token.startsWith("github_pat_"))
88
106
  return "github_pat";
@@ -94,101 +112,50 @@ function classifyPatTokenKind(token) {
94
112
  return "ghs";
95
113
  return "other";
96
114
  }
97
- function getCurrentBillingPeriod(now = new Date()) {
98
- return {
99
- year: now.getUTCFullYear(),
100
- month: now.getUTCMonth() + 1,
101
- };
102
- }
103
- function getApproxNextResetIso(nowMs = Date.now()) {
104
- const now = new Date(nowMs);
105
- return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)).toISOString();
106
- }
107
- function formatBillingPeriod(period) {
108
- return `${period.year}-${String(period.month).padStart(2, "0")}`;
109
- }
110
115
  function computePercentRemainingFromUsed(used, total) {
111
116
  if (!Number.isFinite(used) || used < 0 || !Number.isFinite(total) || total <= 0) {
112
117
  return undefined;
113
118
  }
114
119
  return Math.max(0, Math.min(100, Math.floor(((total - used) * 100) / total)));
115
120
  }
116
- function resolvePatBillingTarget(config) {
117
- const billingPeriod = getCurrentBillingPeriod();
121
+ /** Why this tier/billing model cannot be combined with the configured scope, if it cannot. */
122
+ function getPatScopeError(config) {
123
+ const hasManagedScope = Boolean(config.organization || config.enterprise);
118
124
  if (config.billingModel === "legacy_premium_requests") {
119
125
  if (config.tier !== "pro" && config.tier !== "pro+") {
120
- return {
121
- target: null,
122
- error: "Legacy premium-request billing is only available to Copilot Pro or Pro+ subscribers on an existing annual plan that remained on legacy billing after June 1, 2026.",
123
- };
126
+ return "Legacy premium-request billing is only available to Copilot Pro or Pro+ subscribers on an existing annual plan that remained on legacy billing after June 1, 2026.";
124
127
  }
125
- if (config.organization || config.enterprise) {
126
- return {
127
- target: null,
128
- error: "Legacy premium-request billing is personal-only. Remove organization and enterprise from copilot-quota-token.json.",
129
- };
128
+ if (hasManagedScope) {
129
+ return "Legacy premium-request billing is personal-only. Remove organization and enterprise from copilot-quota-token.json.";
130
130
  }
131
131
  }
132
132
  if (config.tier === "business") {
133
- if (!config.organization || config.enterprise) {
134
- return {
135
- target: null,
136
- error: 'Copilot Business AI Credit usage requires "organization" and does not accept "enterprise" in copilot-quota-token.json.',
137
- };
138
- }
139
- return {
140
- target: {
141
- scope: "organization",
142
- organization: config.organization,
143
- username: config.username,
144
- billingPeriod,
145
- },
146
- };
133
+ return !config.organization || config.enterprise
134
+ ? 'Copilot Business AI Credit usage requires "organization" and does not accept "enterprise" in copilot-quota-token.json.'
135
+ : undefined;
147
136
  }
148
137
  if (config.tier === "enterprise") {
149
- if (config.enterprise) {
150
- return {
151
- target: {
152
- scope: "enterprise",
153
- enterprise: config.enterprise,
154
- organization: config.organization,
155
- username: config.username,
156
- billingPeriod,
157
- },
158
- };
159
- }
160
- if (config.organization) {
161
- return {
162
- target: {
163
- scope: "organization",
164
- organization: config.organization,
165
- username: config.username,
166
- billingPeriod,
167
- },
168
- };
169
- }
170
- return {
171
- target: null,
172
- error: 'Copilot Enterprise AI Credit usage requires "enterprise" or "organization" in copilot-quota-token.json.',
173
- };
138
+ return hasManagedScope
139
+ ? undefined
140
+ : 'Copilot Enterprise AI Credit usage requires "enterprise" or "organization" in copilot-quota-token.json.';
174
141
  }
175
- if (config.organization || config.enterprise) {
176
- return {
177
- target: null,
178
- error: `Copilot ${config.tier} AI Credit usage is personal. Remove organization and enterprise from copilot-quota-token.json.`,
179
- };
142
+ return hasManagedScope
143
+ ? `Copilot ${config.tier} AI Credit usage is personal. Remove organization and enterprise from copilot-quota-token.json.`
144
+ : undefined;
145
+ }
146
+ /** Billing target of a config that already passed `getPatScopeError`. */
147
+ function resolvePatBillingTarget(config) {
148
+ const now = new Date();
149
+ const billingPeriod = { year: now.getUTCFullYear(), month: now.getUTCMonth() + 1 };
150
+ const { username, organization, enterprise } = config;
151
+ if (enterprise) {
152
+ return { scope: "enterprise", enterprise, organization, username, billingPeriod };
180
153
  }
181
- return {
182
- target: {
183
- scope: "user",
184
- username: config.username,
185
- billingPeriod,
186
- },
187
- };
154
+ if (organization)
155
+ return { scope: "organization", organization, username, billingPeriod };
156
+ return { scope: "user", username, billingPeriod };
188
157
  }
189
158
  function validatePatTargetCompatibility(target, tokenKind) {
190
- if (!tokenKind)
191
- return null;
192
159
  if (target.scope === "user" && tokenKind === "ghs") {
193
160
  return ("GitHub's personal AI Credit report supports GitHub App user access tokens, " +
194
161
  "but not GitHub App installation access tokens. Use a GitHub App user token, fine-grained PAT with Plan (read), or supported classic credential.");
@@ -200,13 +167,9 @@ function validatePatTargetCompatibility(target, tokenKind) {
200
167
  }
201
168
  return null;
202
169
  }
203
- export function getCopilotPatConfigCandidatePaths() {
204
- return [join(getOpencodeRuntimeDirs().configDir, COPILOT_QUOTA_CONFIG_FILENAME)];
205
- }
206
170
  function validateQuotaConfig(raw) {
207
- if (!raw || typeof raw !== "object") {
208
- return { config: null, error: "Config must be a JSON object" };
209
- }
171
+ if (!raw || typeof raw !== "object")
172
+ return { error: "Config must be a JSON object" };
210
173
  const obj = raw;
211
174
  const token = typeof obj.token === "string" ? obj.token.trim() : "";
212
175
  const tier = typeof obj.tier === "string" ? obj.tier.trim().toLowerCase() : "";
@@ -215,110 +178,69 @@ function validateQuotaConfig(raw) {
215
178
  : typeof obj.billingModel === "string"
216
179
  ? obj.billingModel.trim()
217
180
  : "";
218
- if (!token) {
219
- return { config: null, error: "Missing required string field: token" };
220
- }
221
- const validTiers = [
222
- "free",
223
- "student",
224
- "pro",
225
- "pro+",
226
- "max",
227
- "business",
228
- "enterprise",
229
- ];
230
- if (!validTiers.includes(tier)) {
181
+ if (!token)
182
+ return { error: "Missing required string field: token" };
183
+ if (!VALID_TIERS.includes(tier)) {
231
184
  return {
232
- config: null,
233
185
  error: "Invalid tier; expected one of: free, student, pro, pro+, max, business, enterprise",
234
186
  };
235
187
  }
236
188
  if (billingModel !== "ai_credits" && billingModel !== "legacy_premium_requests") {
237
- return {
238
- config: null,
239
- error: "Invalid billingModel; expected ai_credits or legacy_premium_requests",
240
- };
189
+ return { error: "Invalid billingModel; expected ai_credits or legacy_premium_requests" };
241
190
  }
242
- const readOptionalString = (key) => {
191
+ const enterpriseHost = validateEnterpriseHost(obj.enterpriseUrl);
192
+ if (enterpriseHost.error)
193
+ return { error: enterpriseHost.error };
194
+ const optional = {};
195
+ for (const key of ["username", "organization", "enterprise"]) {
243
196
  const value = obj[key];
244
197
  if (value == null)
245
- return undefined;
198
+ continue;
246
199
  if (typeof value !== "string" || !value.trim()) {
247
- throw new Error(`${key} must be a non-empty string when provided`);
200
+ return { error: `${key} must be a non-empty string when provided` };
248
201
  }
249
- return value.trim();
202
+ optional[key] = value.trim();
203
+ }
204
+ const config = {
205
+ token,
206
+ tier: tier,
207
+ billingModel,
208
+ username: optional.username,
209
+ organization: optional.organization,
210
+ enterprise: optional.enterprise,
211
+ enterpriseUrl: enterpriseHost.host,
250
212
  };
213
+ const scopeError = getPatScopeError(config);
214
+ return scopeError ? { error: scopeError } : { config };
215
+ }
216
+ function readQuotaConfigWithMeta() {
217
+ const path = join(getOpencodeRuntimeDirs().configDir, COPILOT_QUOTA_CONFIG_FILENAME);
218
+ const checkedPaths = [path];
219
+ if (!existsSync(path))
220
+ return { state: "absent", checkedPaths };
251
221
  try {
252
- const enterpriseHost = validateEnterpriseHost(obj.enterpriseUrl);
253
- if (enterpriseHost.error)
254
- throw new Error(enterpriseHost.error);
255
- const config = {
256
- token,
257
- tier: tier,
258
- billingModel,
259
- username: readOptionalString("username"),
260
- organization: readOptionalString("organization"),
261
- enterprise: readOptionalString("enterprise"),
262
- enterpriseUrl: enterpriseHost.host,
263
- };
264
- const resolved = resolvePatBillingTarget(config);
265
- if (!resolved.target) {
266
- return { config: null, error: resolved.error };
222
+ const validated = validateQuotaConfig(JSON.parse(readFileSync(path, "utf-8")));
223
+ if ("error" in validated) {
224
+ return { state: "invalid", checkedPaths, selectedPath: path, error: validated.error };
267
225
  }
268
- return { config };
226
+ return {
227
+ state: "valid",
228
+ checkedPaths,
229
+ selectedPath: path,
230
+ config: validated.config,
231
+ tokenKind: classifyPatTokenKind(validated.config.token),
232
+ };
269
233
  }
270
234
  catch (error) {
271
- return { config: null, error: error instanceof Error ? error.message : String(error) };
272
- }
273
- }
274
- export function readQuotaConfigWithMeta() {
275
- const checkedPaths = getCopilotPatConfigCandidatePaths();
276
- for (const path of checkedPaths) {
277
- if (!existsSync(path))
278
- continue;
279
- try {
280
- const parsed = JSON.parse(readFileSync(path, "utf-8"));
281
- const validated = validateQuotaConfig(parsed);
282
- if (!validated.config) {
283
- return {
284
- state: "invalid",
285
- checkedPaths,
286
- selectedPath: path,
287
- error: validated.error ?? "Invalid config",
288
- };
289
- }
290
- return {
291
- state: "valid",
292
- checkedPaths,
293
- selectedPath: path,
294
- config: validated.config,
295
- tokenKind: classifyPatTokenKind(validated.config.token),
296
- };
297
- }
298
- catch (error) {
299
- return {
300
- state: "invalid",
301
- checkedPaths,
302
- selectedPath: path,
303
- error: error instanceof Error ? error.message : String(error),
304
- };
305
- }
235
+ return { state: "invalid", checkedPaths, selectedPath: path, error: errorText(error) };
306
236
  }
307
- return { state: "absent", checkedPaths };
308
237
  }
309
238
  function getCopilotOAuthToken(auth) {
310
239
  return auth?.access?.trim() || auth?.refresh?.trim() || null;
311
240
  }
312
241
  function selectCopilotAuth(authData) {
313
- if (!authData)
314
- return { auth: null, keyName: null };
315
- const candidates = [
316
- ["github-copilot", authData["github-copilot"]],
317
- ["copilot", authData.copilot],
318
- ["copilot-chat", authData["copilot-chat"]],
319
- ["github-copilot-chat", authData["github-copilot-chat"]],
320
- ];
321
- for (const [keyName, auth] of candidates) {
242
+ for (const keyName of COPILOT_AUTH_KEYS) {
243
+ const auth = authData?.[keyName];
322
244
  if (!auth || auth.type !== "oauth")
323
245
  continue;
324
246
  // A login OpenCode could not return still counts, so it shows as an error.
@@ -328,36 +250,15 @@ function selectCopilotAuth(authData) {
328
250
  }
329
251
  return { auth: null, keyName: null };
330
252
  }
331
- function getRemainingTotalsState(target, config) {
332
- if (!target || !config)
333
- return "unavailable";
334
- if (target.scope === "organization")
335
- return "not_available_from_org_usage";
336
- if (target.scope === "enterprise")
337
- return "not_available_from_enterprise_usage";
338
- if (config.billingModel !== "legacy_premium_requests") {
339
- return "value_only_without_denominator";
340
- }
341
- return LEGACY_PREMIUM_REQUEST_TOTALS[config.tier]
342
- ? "available"
343
- : "value_only_without_denominator";
344
- }
345
253
  export function getCopilotQuotaAuthDiagnostics(authData) {
346
254
  const pat = readQuotaConfigWithMeta();
347
255
  const { auth, keyName } = selectCopilotAuth(authData);
348
256
  const oauthEnterpriseHost = validateEnterpriseHost(auth?.enterpriseUrl);
349
- const resolved = pat.state === "valid" && pat.config
350
- ? resolvePatBillingTarget(pat.config)
351
- : { target: null };
352
- const compatibilityError = resolved.target && pat.state === "valid"
353
- ? validatePatTargetCompatibility(resolved.target, pat.tokenKind)
354
- : null;
257
+ const target = pat.config ? resolvePatBillingTarget(pat.config) : null;
258
+ const compatibilityError = target ? validatePatTargetCompatibility(target, pat.tokenKind) : null;
259
+ // Any PAT config, even an invalid one, is authoritative over OAuth.
355
260
  const patBlocksOAuth = pat.state !== "absent";
356
- const effectiveSource = patBlocksOAuth
357
- ? "pat"
358
- : auth
359
- ? "oauth"
360
- : "none";
261
+ const effectiveSource = patBlocksOAuth ? "pat" : auth ? "oauth" : "none";
361
262
  const effectiveEnterpriseHost = effectiveSource === "pat"
362
263
  ? pat.config?.enterpriseUrl
363
264
  : effectiveSource === "oauth"
@@ -377,25 +278,9 @@ export function getCopilotQuotaAuthDiagnostics(authData) {
377
278
  : effectiveSource === "pat" && pat.state !== "valid"
378
279
  ? "none"
379
280
  : "github.com";
380
- const apiBaseUrl = deployment === "github.com" || deployment === "ghe.com"
381
- ? getApiBaseUrl(effectiveEnterpriseHost)
382
- : null;
383
281
  const billingModel = pat.config?.billingModel ?? "ai_credits";
384
- const oauthAvailable = effectiveSource === "oauth" && Boolean(auth) && !oauthEnterpriseHost.error;
385
- const quotaApi = pat.state === "valid"
386
- ? billingModel === "legacy_premium_requests"
387
- ? "github_legacy_premium_request_api"
388
- : "github_ai_credit_api"
389
- : oauthAvailable
390
- ? "copilot_internal_user"
391
- : "none";
392
- const billingMode = resolved.target?.scope === "organization"
393
- ? "organization_usage"
394
- : resolved.target?.scope === "enterprise"
395
- ? "enterprise_usage"
396
- : resolved.target?.scope === "user" || oauthAvailable
397
- ? "user_quota"
398
- : "none";
282
+ const oauthAvailable = effectiveSource === "oauth" && !oauthEnterpriseHost.error;
283
+ const billingScope = target?.scope ?? (oauthAvailable ? "user" : "none");
399
284
  return {
400
285
  pat,
401
286
  oauth: {
@@ -406,35 +291,49 @@ export function getCopilotQuotaAuthDiagnostics(authData) {
406
291
  hasEnterpriseUrl: auth?.enterpriseUrl !== undefined,
407
292
  },
408
293
  deployment,
409
- apiHost: apiBaseUrl ? getApiHost(apiBaseUrl) : null,
410
- enterpriseHostSource: effectiveSource === "pat" && pat.config?.enterpriseUrl
411
- ? "pat"
412
- : effectiveSource === "oauth" && oauthEnterpriseHost.host
413
- ? "oauth"
414
- : "none",
294
+ apiHost: deployment === "github.com" || deployment === "ghe.com"
295
+ ? new URL(getApiBaseUrl(effectiveEnterpriseHost)).hostname
296
+ : null,
297
+ enterpriseHostSource: effectiveEnterpriseHost ? effectiveSource : "none",
415
298
  enterpriseHostError,
416
299
  effectiveSource,
417
300
  override: patBlocksOAuth && auth ? "pat_overrides_oauth" : "none",
418
- quotaApi,
419
- billingMode,
420
- billingScope: resolved.target?.scope ?? (oauthAvailable ? "user" : "none"),
421
- billingApiAccessLikely: oauthAvailable ||
422
- (pat.state === "valid" && Boolean(resolved.target) && !resolved.error && !compatibilityError),
301
+ quotaApi: target
302
+ ? billingModel === "legacy_premium_requests"
303
+ ? "github_legacy_premium_request_api"
304
+ : "github_ai_credit_api"
305
+ : oauthAvailable
306
+ ? "copilot_internal_user"
307
+ : "none",
308
+ billingMode: billingScope === "organization"
309
+ ? "organization_usage"
310
+ : billingScope === "enterprise"
311
+ ? "enterprise_usage"
312
+ : billingScope === "user"
313
+ ? "user_quota"
314
+ : "none",
315
+ billingScope,
316
+ billingApiAccessLikely: oauthAvailable || (target !== null && !compatibilityError),
423
317
  remainingTotalsState: oauthAvailable
424
318
  ? "reported_by_copilot_internal_user"
425
- : getRemainingTotalsState(resolved.target, pat.config),
426
- queryPeriod: resolved.target?.billingPeriod,
319
+ : billingScope === "organization"
320
+ ? "not_available_from_org_usage"
321
+ : billingScope === "enterprise"
322
+ ? "not_available_from_enterprise_usage"
323
+ : billingScope === "none"
324
+ ? "unavailable"
325
+ : billingModel === "legacy_premium_requests"
326
+ ? "available"
327
+ : "value_only_without_denominator",
328
+ queryPeriod: target?.billingPeriod,
427
329
  usernameFilter: pat.config?.username,
428
- billingTargetError: resolved.error,
429
330
  tokenCompatibilityError: compatibilityError ?? undefined,
430
331
  billingModel,
431
- budgetApi: billingModel !== "ai_credits" || oauthAvailable
432
- ? "not_available"
433
- : resolved.target?.scope === "organization"
434
- ? "organization_budgets"
435
- : resolved.target?.scope === "enterprise"
436
- ? "enterprise_budgets"
437
- : "not_available",
332
+ budgetApi: billingScope === "organization"
333
+ ? "organization_budgets"
334
+ : billingScope === "enterprise"
335
+ ? "enterprise_budgets"
336
+ : "not_available",
438
337
  oauthAccountingState: !auth
439
338
  ? "not_configured"
440
339
  : oauthEnterpriseHost.error
@@ -442,116 +341,107 @@ export function getCopilotQuotaAuthDiagnostics(authData) {
442
341
  : "available_via_copilot_internal_user",
443
342
  };
444
343
  }
445
- function buildGitHubRestHeaders(token) {
446
- return {
447
- Accept: "application/vnd.github+json",
448
- Authorization: `Bearer ${token}`,
449
- "X-GitHub-Api-Version": GITHUB_API_VERSION,
450
- "User-Agent": USER_AGENT,
451
- };
452
- }
453
- function redactGitHubErrorText(text, secrets) {
454
- let sanitized = sanitizeDisplayText(text);
455
- for (const secret of secrets) {
456
- if (!secret)
457
- continue;
458
- sanitized = sanitized.split(secret).join("[redacted]");
459
- const sanitizedSecret = sanitizeDisplayText(secret);
460
- if (sanitizedSecret) {
461
- sanitized = sanitized.split(sanitizedSecret).join("[redacted]");
462
- }
463
- }
464
- return sanitized;
344
+ function redactSecret(text, secret) {
345
+ const redacted = sanitizeDisplayText(text).replaceAll(secret, "[redacted]");
346
+ const sanitizedSecret = sanitizeDisplayText(secret);
347
+ return sanitizedSecret ? redacted.replaceAll(sanitizedSecret, "[redacted]") : redacted;
465
348
  }
466
- async function readGitHubRestErrorMessage(response, secrets) {
349
+ async function readGitHubErrorMessage(response, token) {
467
350
  const text = await response.text();
468
351
  try {
469
352
  const parsed = JSON.parse(text);
470
353
  const message = typeof parsed.message === "string" ? parsed.message : null;
471
354
  const documentationUrl = typeof parsed.documentation_url === "string" ? parsed.documentation_url : null;
472
- if (message && documentationUrl) {
473
- return redactGitHubErrorText(`${message} (${documentationUrl})`, secrets);
474
- }
355
+ if (message && documentationUrl)
356
+ return redactSecret(`${message} (${documentationUrl})`, token);
475
357
  if (message)
476
- return redactGitHubErrorText(message, secrets);
358
+ return redactSecret(message, token);
477
359
  }
478
360
  catch {
479
361
  // Fall through to a bounded plain-text snippet.
480
362
  }
481
- return sanitizeDisplaySnippet(redactGitHubErrorText(text, secrets), 160);
363
+ return sanitizeDisplaySnippet(redactSecret(text, token), 160);
482
364
  }
483
- async function fetchGitHubRestJson(url, token, requestTimeoutMs) {
484
- return await fetchWithTimeout(url, {
485
- request: { headers: buildGitHubRestHeaders(token) },
486
- timeoutMs: requestTimeoutMs,
365
+ /** GET a GitHub JSON endpoint; failures become errors that never contain `token`. */
366
+ async function fetchGitHubJson(params) {
367
+ const { apiName, token } = params;
368
+ return await fetchWithTimeout(params.url, {
369
+ request: { headers: params.headers },
370
+ timeoutMs: params.requestTimeoutMs,
487
371
  consume: async (response) => {
488
372
  if (!response.ok) {
489
- const message = await readGitHubRestErrorMessage(response, [token]);
490
- const rateLimit = response.status === 403 && response.headers.get("x-ratelimit-remaining") === "0"
373
+ const message = await readGitHubErrorMessage(response, token);
374
+ const rateLimit = apiName === "GitHub API" &&
375
+ response.status === 403 &&
376
+ response.headers.get("x-ratelimit-remaining") === "0"
491
377
  ? " (GitHub API rate limit exhausted)"
492
378
  : "";
493
- throw new Error(`GitHub API error ${response.status}: ${message}${rateLimit}`);
379
+ throw new Error(`${apiName} error ${response.status}: ${message}${rateLimit}`);
494
380
  }
495
381
  try {
496
382
  return (await response.json());
497
383
  }
498
384
  catch {
499
- throw new Error("GitHub API returned malformed JSON");
385
+ throw new Error(`${apiName} returned malformed JSON`);
500
386
  }
501
387
  },
502
388
  });
503
389
  }
390
+ async function fetchGitHubRestJson(url, token, requestTimeoutMs) {
391
+ return await fetchGitHubJson({
392
+ url,
393
+ apiName: "GitHub API",
394
+ headers: {
395
+ Accept: "application/vnd.github+json",
396
+ Authorization: `Bearer ${token}`,
397
+ "X-GitHub-Api-Version": "2026-03-10",
398
+ "User-Agent": "opencode-quota/copilot-billing",
399
+ },
400
+ token,
401
+ requestTimeoutMs,
402
+ });
403
+ }
504
404
  async function resolveGitHubUsername(apiBaseUrl, token, requestTimeoutMs) {
505
- const response = await fetchGitHubRestJson(`${apiBaseUrl}/user`, token, requestTimeoutMs);
506
- const login = response.login?.trim();
507
- if (!login) {
405
+ const viewer = await fetchGitHubRestJson(`${apiBaseUrl}/user`, token, requestTimeoutMs);
406
+ const login = viewer.login?.trim();
407
+ if (!login)
508
408
  throw new Error("GitHub /user response did not include a login");
509
- }
510
409
  return login;
511
410
  }
512
- function buildBillingQuery(target) {
513
- const query = new URLSearchParams({
514
- year: String(target.billingPeriod.year),
515
- month: String(target.billingPeriod.month),
516
- });
517
- if (target.scope !== "user" && target.username)
518
- query.set("user", target.username);
519
- if (target.scope === "enterprise" && target.organization) {
520
- query.set("organization", target.organization);
521
- }
522
- return query;
523
- }
524
- function getBillingUsageUrl(apiBaseUrl, target, billingModel) {
525
- const report = billingModel === "legacy_premium_requests" ? "premium_request" : "ai_credit";
526
- const query = buildBillingQuery(target);
411
+ function billingSettingsUrl(apiBaseUrl, target) {
527
412
  if (target.scope === "enterprise") {
528
- return `${apiBaseUrl}/enterprises/${encodeURIComponent(target.enterprise)}/settings/billing/${report}/usage?${query}`;
413
+ return `${apiBaseUrl}/enterprises/${encodeURIComponent(target.enterprise)}/settings/billing`;
529
414
  }
530
415
  if (target.scope === "organization") {
531
- return `${apiBaseUrl}/organizations/${encodeURIComponent(target.organization)}/settings/billing/${report}/usage?${query}`;
416
+ return `${apiBaseUrl}/organizations/${encodeURIComponent(target.organization)}/settings/billing`;
532
417
  }
533
- return `${apiBaseUrl}/users/${encodeURIComponent(target.username)}/settings/billing/${report}/usage?${query}`;
418
+ return `${apiBaseUrl}/users/${encodeURIComponent(target.username)}/settings/billing`;
534
419
  }
535
420
  async function fetchBillingUsage(params) {
421
+ const { apiBaseUrl, token, requestTimeoutMs } = params;
536
422
  const target = params.target.scope === "user"
537
423
  ? {
538
424
  ...params.target,
539
425
  username: params.target.username ??
540
- (await resolveGitHubUsername(params.apiBaseUrl, params.token, params.requestTimeoutMs)),
426
+ (await resolveGitHubUsername(apiBaseUrl, token, requestTimeoutMs)),
541
427
  }
542
428
  : params.target;
429
+ const query = new URLSearchParams({
430
+ year: String(target.billingPeriod.year),
431
+ month: String(target.billingPeriod.month),
432
+ });
433
+ if (target.scope !== "user" && target.username)
434
+ query.set("user", target.username);
435
+ if (target.scope === "enterprise" && target.organization) {
436
+ query.set("organization", target.organization);
437
+ }
438
+ const report = params.billingModel === "legacy_premium_requests" ? "premium_request" : "ai_credit";
439
+ const url = `${billingSettingsUrl(apiBaseUrl, target)}/${report}/usage?${query}`;
543
440
  return {
544
- response: await fetchGitHubRestJson(getBillingUsageUrl(params.apiBaseUrl, target, params.billingModel), params.token, params.requestTimeoutMs),
441
+ response: await fetchGitHubRestJson(url, token, requestTimeoutMs),
545
442
  target,
546
443
  };
547
444
  }
548
- function getResponsePeriod(response, fallback) {
549
- const period = response.timePeriod ?? response.time_period;
550
- return {
551
- year: typeof period?.year === "number" ? period.year : fallback.year,
552
- month: typeof period?.month === "number" ? period.month : fallback.month,
553
- };
554
- }
555
445
  function getUsageItems(response) {
556
446
  if (Array.isArray(response.usageItems))
557
447
  return response.usageItems;
@@ -559,27 +449,28 @@ function getUsageItems(response) {
559
449
  return response.usage_items;
560
450
  throw new Error("GitHub billing response did not include a usageItems array");
561
451
  }
562
- function readFiniteNumber(value) {
563
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
564
- }
565
- function quantitiesDiffer(left, right) {
566
- return (Math.abs(left - right) > Number.EPSILON * 16 * Math.max(1, Math.abs(left), Math.abs(right)));
567
- }
568
- function isAiCreditItem(item) {
569
- const text = [item.product, item.sku, item.unitType, item.unit_type]
452
+ function usageItemText(item) {
453
+ return [item.product, item.sku, item.unitType, item.unit_type]
570
454
  .filter((value) => typeof value === "string")
571
455
  .join(" ")
572
456
  .toLowerCase();
573
- const identifiesCopilot = text.includes("copilot");
574
- const identifiesAiCredits = text.includes("ai credit") || text.includes("ai-credit");
575
- return identifiesCopilot && identifiesAiCredits;
576
457
  }
577
- function isPremiumRequestItem(item) {
578
- const text = [item.product, item.sku, item.unitType, item.unit_type]
579
- .filter((value) => typeof value === "string")
580
- .join(" ")
581
- .toLowerCase();
582
- return text.includes("premium request");
458
+ function isAiCreditItem(item) {
459
+ const text = usageItemText(item);
460
+ return text.includes("copilot") && (text.includes("ai credit") || text.includes("ai-credit"));
461
+ }
462
+ function quantitiesDiffer(left, right) {
463
+ return (Math.abs(left - right) > Number.EPSILON * 16 * Math.max(1, Math.abs(left), Math.abs(right)));
464
+ }
465
+ function hasInconsistentQuantities(gross, discount, net) {
466
+ if (gross === undefined)
467
+ return false;
468
+ if (discount !== undefined && net !== undefined) {
469
+ return quantitiesDiffer(gross, discount + net);
470
+ }
471
+ // With one part missing, only a part larger than gross is a contradiction.
472
+ const part = discount ?? net;
473
+ return part !== undefined && part > gross && quantitiesDiffer(gross, part);
583
474
  }
584
475
  function parseAiCreditTotals(response) {
585
476
  const items = getUsageItems(response);
@@ -587,16 +478,17 @@ function parseAiCreditTotals(response) {
587
478
  if (matches.length === 0 && items.length > 0) {
588
479
  throw new Error("GitHub billing response did not contain a Copilot AI Credit usage item");
589
480
  }
590
- let used = 0;
591
- let includedUsed = 0;
592
- let billedUsed = 0;
593
- let billedAmountUsd = 0;
594
- let hasBilledAmount = false;
595
- let authority = "provider_reported";
481
+ const totals = {
482
+ used: 0,
483
+ includedUsed: 0,
484
+ billedUsed: 0,
485
+ billedAmountUsd: undefined,
486
+ authority: "provider_reported",
487
+ };
596
488
  for (const item of matches) {
597
- const gross = readFiniteNumber(item.grossQuantity ?? item.gross_quantity);
598
- const discount = readFiniteNumber(item.discountQuantity ?? item.discount_quantity);
599
- const net = readFiniteNumber(item.netQuantity ?? item.net_quantity);
489
+ const gross = finiteNumber(item.grossQuantity ?? item.gross_quantity);
490
+ const discount = finiteNumber(item.discountQuantity ?? item.discount_quantity);
491
+ const net = finiteNumber(item.netQuantity ?? item.net_quantity);
600
492
  const quantities = [gross, discount, net].filter((value) => value !== undefined);
601
493
  if (quantities.length === 0) {
602
494
  throw new Error("GitHub Copilot AI Credit usage item did not include quantity fields");
@@ -604,65 +496,36 @@ function parseAiCreditTotals(response) {
604
496
  if (quantities.some((value) => value < 0)) {
605
497
  throw new Error("GitHub Copilot AI Credit usage item contained a negative quantity");
606
498
  }
607
- if (gross !== undefined &&
608
- discount !== undefined &&
609
- net !== undefined &&
610
- quantitiesDiffer(gross, discount + net)) {
499
+ if (hasInconsistentQuantities(gross, discount, net)) {
611
500
  throw new Error("GitHub Copilot AI Credit usage item contained inconsistent quantities");
612
501
  }
613
- let normalizedGross = gross;
614
- let normalizedIncluded = discount;
615
- let normalizedBilled = net;
616
- if (gross !== undefined && discount !== undefined && net === undefined) {
617
- if (discount > gross && quantitiesDiffer(gross, discount)) {
618
- throw new Error("GitHub Copilot AI Credit usage item contained inconsistent quantities");
619
- }
620
- normalizedBilled = Math.max(0, gross - discount);
621
- }
622
- else if (gross !== undefined && discount === undefined && net !== undefined) {
623
- if (net > gross && quantitiesDiffer(gross, net)) {
624
- throw new Error("GitHub Copilot AI Credit usage item contained inconsistent quantities");
625
- }
626
- normalizedIncluded = Math.max(0, gross - net);
627
- }
628
- else if (gross === undefined && discount !== undefined && net !== undefined) {
629
- normalizedGross = discount + net;
630
- }
631
- normalizedIncluded ??= 0;
632
- normalizedBilled ??= Math.max(0, (normalizedGross ?? 0) - normalizedIncluded);
633
- normalizedGross ??= normalizedIncluded + normalizedBilled;
634
- used += normalizedGross;
635
- includedUsed += normalizedIncluded;
636
- billedUsed += normalizedBilled;
637
- if (gross === undefined || discount === undefined || net === undefined) {
638
- authority = "locally_derived";
639
- }
640
- const netAmount = readFiniteNumber(item.netAmount ?? item.net_amount);
502
+ // gross = included (discount) + billed (net); fill in whichever part is missing.
503
+ const included = discount ?? (gross !== undefined && net !== undefined ? Math.max(0, gross - net) : 0);
504
+ const billed = net ?? Math.max(0, (gross ?? 0) - included);
505
+ totals.used += gross ?? included + billed;
506
+ totals.includedUsed += included;
507
+ totals.billedUsed += billed;
508
+ if (quantities.length < 3)
509
+ totals.authority = "locally_derived";
510
+ const netAmount = finiteNumber(item.netAmount ?? item.net_amount);
641
511
  if (netAmount !== undefined) {
642
512
  if (netAmount < 0) {
643
513
  throw new Error("GitHub Copilot AI Credit usage item contained a negative net amount");
644
514
  }
645
- billedAmountUsd += netAmount;
646
- hasBilledAmount = true;
515
+ totals.billedAmountUsd = (totals.billedAmountUsd ?? 0) + netAmount;
647
516
  }
648
517
  }
649
- return {
650
- used,
651
- includedUsed,
652
- billedUsed,
653
- billedAmountUsd: hasBilledAmount ? billedAmountUsd : undefined,
654
- authority,
655
- };
518
+ return totals;
656
519
  }
657
520
  function parseLegacyPremiumRequestUsage(response) {
658
521
  const items = getUsageItems(response);
659
- const matches = items.filter(isPremiumRequestItem);
522
+ const matches = items.filter((item) => usageItemText(item).includes("premium request"));
660
523
  if (matches.length === 0 && items.length > 0) {
661
524
  throw new Error("GitHub billing response did not contain a premium-request usage item");
662
525
  }
663
526
  return matches.reduce((sum, item) => {
664
- const gross = readFiniteNumber(item.grossQuantity ?? item.gross_quantity);
665
- const net = readFiniteNumber(item.netQuantity ?? item.net_quantity);
527
+ const gross = finiteNumber(item.grossQuantity ?? item.gross_quantity);
528
+ const net = finiteNumber(item.netQuantity ?? item.net_quantity);
666
529
  if (gross === undefined && net === undefined) {
667
530
  throw new Error("GitHub premium-request usage item did not include quantity fields");
668
531
  }
@@ -682,67 +545,36 @@ function budgetMatchesTarget(budget, target) {
682
545
  const scope = budget.budget_scope;
683
546
  const entity = budget.budget_entity_name?.toLowerCase();
684
547
  const user = (budget.user ?? budget.budget_entity_name)?.toLowerCase();
685
- if (target.scope === "organization") {
686
- if (target.username && scope === "user") {
548
+ if (target.username) {
549
+ if (scope === "user")
687
550
  return !user || user === target.username.toLowerCase();
688
- }
689
- if (target.username && scope === "multi_user_customer")
551
+ if (scope === "multi_user_customer")
690
552
  return true;
691
- return scope === "organization";
692
- }
693
- if (target.scope === "enterprise") {
694
- if (target.username && scope === "user") {
695
- return !user || user === target.username.toLowerCase();
696
- }
697
- if (target.username &&
698
- (scope === "multi_user_customer" || scope === "multi_user_cost_center")) {
553
+ if (scope === "multi_user_cost_center" && target.scope === "enterprise")
699
554
  return true;
700
- }
701
- if (target.organization && scope === "organization") {
702
- return !entity || entity === target.organization.toLowerCase();
703
- }
704
- return scope === "enterprise";
705
555
  }
706
- return false;
707
- }
708
- function budgetSpecificity(budget) {
709
- switch (budget.budget_scope) {
710
- case "user":
711
- return 5;
712
- case "multi_user_cost_center":
713
- return 4;
714
- case "multi_user_customer":
715
- return 3;
716
- case "organization":
717
- return 2;
718
- case "enterprise":
719
- return 1;
720
- default:
721
- return 0;
556
+ if (target.scope === "organization")
557
+ return scope === "organization";
558
+ if (target.organization && scope === "organization") {
559
+ return !entity || entity === target.organization.toLowerCase();
722
560
  }
723
- }
724
- function getBudgetsUrl(apiBaseUrl, target, page) {
725
- const base = target.scope === "organization"
726
- ? `${apiBaseUrl}/organizations/${encodeURIComponent(target.organization)}/settings/billing/budgets`
727
- : `${apiBaseUrl}/enterprises/${encodeURIComponent(target.enterprise)}/settings/billing/budgets`;
728
- const query = new URLSearchParams({ page: String(page), per_page: "100" });
729
- if (target.username)
730
- query.set("user", target.username);
731
- return `${base}?${query}`;
561
+ return scope === "enterprise";
732
562
  }
733
563
  async function fetchApplicableBudget(params) {
734
564
  const budgets = [];
735
565
  for (let page = 1; page <= 100; page += 1) {
736
- const response = await fetchGitHubRestJson(getBudgetsUrl(params.apiBaseUrl, params.target, page), params.token, params.requestTimeoutMs);
566
+ const query = new URLSearchParams({ page: String(page), per_page: "100" });
567
+ if (params.target.username)
568
+ query.set("user", params.target.username);
569
+ const response = await fetchGitHubRestJson(`${billingSettingsUrl(params.apiBaseUrl, params.target)}/budgets?${query}`, params.token, params.requestTimeoutMs);
737
570
  if (!Array.isArray(response.budgets)) {
738
571
  throw new Error("GitHub budgets response did not include a budgets array");
739
572
  }
740
573
  budgets.push(...response.budgets);
741
574
  if (!response.has_next_page)
742
575
  break;
743
- if (page === 100) {
576
+ if (page === 100)
744
577
  throw new Error("GitHub budgets response exceeded 100 pages");
745
- }
746
578
  }
747
579
  const selected = budgets
748
580
  .filter((budget) => isAiCreditBudget(budget) &&
@@ -750,7 +582,8 @@ async function fetchApplicableBudget(params) {
750
582
  typeof budget.budget_amount === "number" &&
751
583
  Number.isFinite(budget.budget_amount) &&
752
584
  budget.budget_amount >= 0)
753
- .sort((a, b) => budgetSpecificity(b) - budgetSpecificity(a))[0];
585
+ .sort((a, b) => (BUDGET_SCOPE_SPECIFICITY[b.budget_scope ?? ""] ?? 0) -
586
+ (BUDGET_SCOPE_SPECIFICITY[a.budget_scope ?? ""] ?? 0))[0];
754
587
  if (!selected || selected.budget_amount === undefined)
755
588
  return undefined;
756
589
  const percentRemaining = params.spentUsd === undefined
@@ -764,67 +597,55 @@ async function fetchApplicableBudget(params) {
764
597
  authority: percentRemaining === undefined ? "provider_reported" : "locally_derived",
765
598
  };
766
599
  }
767
- function makeBudgetWarning(error) {
768
- const message = error instanceof Error ? error.message : String(error);
769
- return `AI Credit usage loaded, but the budget report failed: ${message}`;
770
- }
771
600
  async function toAiCreditResult(params) {
601
+ const { target } = params;
772
602
  const totals = parseAiCreditTotals(params.response);
773
- const period = getResponsePeriod(params.response, params.target.billingPeriod);
603
+ const responsePeriod = params.response.timePeriod ?? params.response.time_period;
604
+ const period = {
605
+ year: typeof responsePeriod?.year === "number" ? responsePeriod.year : target.billingPeriod.year,
606
+ month: typeof responsePeriod?.month === "number" ? responsePeriod.month : target.billingPeriod.month,
607
+ };
608
+ if (target.scope === "user") {
609
+ return { success: true, mode: "user_quota", unit: "ai_credits", period, ...totals };
610
+ }
611
+ // The budget is optional context: its failure becomes a warning, not a failed usage read.
774
612
  let budget;
775
- const warnings = [];
776
- if (params.target.scope !== "user") {
777
- try {
778
- budget = await fetchApplicableBudget({
779
- apiBaseUrl: params.apiBaseUrl,
780
- token: params.token,
781
- target: params.target,
782
- spentUsd: totals.billedAmountUsd,
783
- requestTimeoutMs: params.requestTimeoutMs,
784
- });
785
- }
786
- catch (error) {
787
- warnings.push(makeBudgetWarning(error));
788
- }
613
+ let warnings;
614
+ try {
615
+ budget = await fetchApplicableBudget({
616
+ apiBaseUrl: params.apiBaseUrl,
617
+ token: params.token,
618
+ target,
619
+ spentUsd: totals.billedAmountUsd,
620
+ requestTimeoutMs: params.requestTimeoutMs,
621
+ });
789
622
  }
790
- if (params.target.scope === "organization") {
791
- return {
792
- success: true,
793
- mode: "organization_usage",
794
- organization: params.target.organization,
795
- username: params.target.username,
796
- period,
797
- unit: "ai_credits",
798
- ...totals,
799
- budget,
800
- warnings: warnings.length ? warnings : undefined,
801
- };
623
+ catch (error) {
624
+ warnings = [`AI Credit usage loaded, but the budget report failed: ${errorText(error)}`];
802
625
  }
803
- if (params.target.scope === "enterprise") {
626
+ const usage = { period, unit: "ai_credits", ...totals, budget, warnings };
627
+ if (target.scope === "organization") {
804
628
  return {
805
629
  success: true,
806
- mode: "enterprise_usage",
807
- enterprise: params.target.enterprise,
808
- organization: params.target.organization,
809
- username: params.target.username,
810
- period,
811
- unit: "ai_credits",
812
- ...totals,
813
- budget,
814
- warnings: warnings.length ? warnings : undefined,
630
+ mode: "organization_usage",
631
+ organization: target.organization,
632
+ username: target.username,
633
+ ...usage,
815
634
  };
816
635
  }
817
636
  return {
818
637
  success: true,
819
- mode: "user_quota",
820
- unit: "ai_credits",
821
- period,
822
- ...totals,
638
+ mode: "enterprise_usage",
639
+ enterprise: target.enterprise,
640
+ organization: target.organization,
641
+ username: target.username,
642
+ ...usage,
823
643
  };
824
644
  }
825
645
  function toLegacyResult(response, config) {
826
646
  const used = parseLegacyPremiumRequestUsage(response);
827
647
  const total = LEGACY_PREMIUM_REQUEST_TOTALS[config.tier];
648
+ const now = new Date();
828
649
  return {
829
650
  success: true,
830
651
  mode: "user_quota",
@@ -834,28 +655,10 @@ function toLegacyResult(response, config) {
834
655
  total,
835
656
  percentRemaining: total ? computePercentRemainingFromUsed(used, total) : undefined,
836
657
  plan: config.tier,
837
- resetTimeIso: getApproxNextResetIso(),
838
- };
839
- }
840
- function toQuotaError(message) {
841
- return { success: false, error: message };
842
- }
843
- function buildCopilotInternalHeaders(token) {
844
- return {
845
- Accept: "application/json",
846
- Authorization: `token ${token}`,
847
- "Editor-Version": "vscode/1.96.2",
848
- "Editor-Plugin-Version": "copilot-chat/0.26.7",
849
- "User-Agent": "GitHubCopilotChat/0.26.7",
850
- "X-GitHub-Api-Version": "2025-04-01",
658
+ // Approximate: the start of the next UTC month.
659
+ resetTimeIso: new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)).toISOString(),
851
660
  };
852
661
  }
853
- function normalizeCopilotPlan(value) {
854
- if (typeof value !== "string")
855
- return undefined;
856
- const plan = sanitizeDisplayText(value).replace(/\s+/gu, " ").trim().slice(0, 64);
857
- return plan || undefined;
858
- }
859
662
  function normalizeResetTime(value) {
860
663
  if (typeof value !== "string" || !value.trim())
861
664
  return undefined;
@@ -863,32 +666,11 @@ function normalizeResetTime(value) {
863
666
  return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : undefined;
864
667
  }
865
668
  function parseCopilotInternalUser(response) {
866
- const plan = normalizeCopilotPlan(response.copilot_plan);
669
+ const plan = typeof response.copilot_plan === "string"
670
+ ? sanitizeSingleLineDisplaySnippet(response.copilot_plan, 64) || undefined
671
+ : undefined;
867
672
  const resetTimeIso = normalizeResetTime(response.quota_reset_date_utc ?? response.quota_reset_date);
868
673
  const snapshot = response.quota_snapshots?.premium_interactions;
869
- const entitlement = readFiniteNumber(snapshot?.entitlement);
870
- const remaining = readFiniteNumber(snapshot?.quota_remaining ?? snapshot?.remaining);
871
- const reportedPercentRemaining = readFiniteNumber(snapshot?.percent_remaining);
872
- const hasPercentRemaining = snapshot?.percent_remaining !== undefined;
873
- const hasReportedPercent = reportedPercentRemaining !== undefined &&
874
- reportedPercentRemaining >= 0 &&
875
- reportedPercentRemaining <= 100;
876
- const tokenBasedBilling = response.token_based_billing === true;
877
- const isPlaceholder = tokenBasedBilling &&
878
- (!snapshot ||
879
- (snapshot.unlimited !== true &&
880
- entitlement === 0 &&
881
- remaining === 0 &&
882
- (!hasReportedPercent || reportedPercentRemaining === 0)));
883
- if (isPlaceholder) {
884
- return {
885
- success: true,
886
- mode: "user_plan",
887
- authority: "provider_reported",
888
- plan,
889
- resetTimeIso,
890
- };
891
- }
892
674
  if (snapshot?.unlimited === true) {
893
675
  return {
894
676
  success: true,
@@ -901,82 +683,90 @@ function parseCopilotInternalUser(response) {
901
683
  resetTimeIso,
902
684
  };
903
685
  }
904
- if (entitlement !== undefined &&
905
- entitlement > 0 &&
906
- remaining !== undefined &&
907
- remaining >= 0 &&
908
- remaining <= entitlement) {
909
- return {
910
- success: true,
911
- mode: "user_quota",
912
- unit: "premium_interactions",
913
- used: entitlement - remaining,
914
- authority: "locally_derived",
915
- total: entitlement,
916
- percentRemaining: hasReportedPercent
917
- ? reportedPercentRemaining
918
- : !hasPercentRemaining
919
- ? Math.min(100, Math.max(0, (remaining / entitlement) * 100))
920
- : undefined,
921
- plan,
922
- resetTimeIso,
923
- };
924
- }
925
- // Token-based billing reports a negative remaining once usage goes over the
926
- // entitlement, alongside a provider-reported clamp in [0, 100].
927
- const creditsUsed = readFiniteNumber(snapshot?.credits_used);
928
- const hasValidCreditsUsed = creditsUsed !== undefined && creditsUsed >= 0;
929
- if (tokenBasedBilling &&
930
- entitlement !== undefined &&
931
- entitlement > 0 &&
932
- remaining !== undefined &&
933
- remaining < 0 &&
934
- hasReportedPercent) {
935
- return {
936
- success: true,
937
- mode: "user_quota",
938
- unit: hasValidCreditsUsed ? "ai_credits" : "premium_interactions",
939
- used: hasValidCreditsUsed ? creditsUsed : entitlement - remaining,
940
- authority: hasValidCreditsUsed ? "provider_reported" : "locally_derived",
941
- total: entitlement,
942
- percentRemaining: reportedPercentRemaining,
943
- plan,
944
- resetTimeIso,
945
- };
686
+ const entitlement = finiteNumber(snapshot?.entitlement);
687
+ const remaining = finiteNumber(snapshot?.quota_remaining ?? snapshot?.remaining);
688
+ const reportedPercent = finiteNumber(snapshot?.percent_remaining);
689
+ const validReportedPercent = reportedPercent !== undefined && reportedPercent >= 0 && reportedPercent <= 100
690
+ ? reportedPercent
691
+ : undefined;
692
+ const tokenBasedBilling = response.token_based_billing === true;
693
+ if (entitlement !== undefined && entitlement > 0 && remaining !== undefined) {
694
+ if (remaining >= 0 && remaining <= entitlement) {
695
+ return {
696
+ success: true,
697
+ mode: "user_quota",
698
+ unit: "premium_interactions",
699
+ used: entitlement - remaining,
700
+ authority: "locally_derived",
701
+ total: entitlement,
702
+ // An invalid reported percentage is dropped, not replaced by a derived one.
703
+ percentRemaining: validReportedPercent ??
704
+ (snapshot?.percent_remaining === undefined
705
+ ? Math.min(100, Math.max(0, (remaining / entitlement) * 100))
706
+ : undefined),
707
+ plan,
708
+ resetTimeIso,
709
+ };
710
+ }
711
+ // Token-based billing reports a negative remaining once usage goes over the
712
+ // entitlement, alongside a provider-reported clamp in [0, 100].
713
+ if (tokenBasedBilling && remaining < 0 && validReportedPercent !== undefined) {
714
+ const creditsUsed = finiteNumber(snapshot?.credits_used);
715
+ const hasCreditsUsed = creditsUsed !== undefined && creditsUsed >= 0;
716
+ return {
717
+ success: true,
718
+ mode: "user_quota",
719
+ unit: hasCreditsUsed ? "ai_credits" : "premium_interactions",
720
+ used: hasCreditsUsed ? creditsUsed : entitlement - remaining,
721
+ authority: hasCreditsUsed ? "provider_reported" : "locally_derived",
722
+ total: entitlement,
723
+ percentRemaining: validReportedPercent,
724
+ plan,
725
+ resetTimeIso,
726
+ };
727
+ }
946
728
  }
947
- if (response.token_based_billing === true) {
948
- return {
949
- success: true,
950
- mode: "user_plan",
951
- authority: "provider_reported",
952
- plan,
953
- resetTimeIso,
954
- };
729
+ // Token-based billing without usable numbers (e.g. an all-zero placeholder) is plan-only.
730
+ if (tokenBasedBilling) {
731
+ return { success: true, mode: "user_plan", authority: "provider_reported", plan, resetTimeIso };
955
732
  }
956
733
  throw new Error("GitHub Copilot user response did not include a usable quota snapshot");
957
734
  }
958
- async function fetchCopilotInternalUser(params) {
959
- return await fetchWithTimeout(`${params.apiBaseUrl}${COPILOT_INTERNAL_USER_PATH}`, {
960
- request: { headers: buildCopilotInternalHeaders(params.token) },
961
- timeoutMs: params.requestTimeoutMs,
962
- consume: async (response) => {
963
- if (!response.ok) {
964
- const message = await readGitHubRestErrorMessage(response, [params.token]);
965
- throw new Error(`GitHub Copilot API error ${response.status}: ${message}`);
966
- }
967
- let parsed;
968
- try {
969
- parsed = (await response.json());
970
- }
971
- catch {
972
- throw new Error("GitHub Copilot API returned malformed JSON");
973
- }
974
- if (!parsed || typeof parsed !== "object") {
975
- throw new Error("GitHub Copilot API returned malformed JSON");
976
- }
977
- return parseCopilotInternalUser(parsed);
978
- },
979
- });
735
+ async function queryCopilotOAuthQuota(authData, requestTimeoutMs) {
736
+ const { auth } = selectCopilotAuth(authData ?? (await readAuthFile({ integrationIds: COPILOT_AUTH_KEYS })));
737
+ if (auth?.resolveError !== undefined) {
738
+ return toQuotaError(`Copilot sign-in could not be read: ${auth.resolveError}. Run \`opencode auth login github-copilot\`.`);
739
+ }
740
+ const token = getCopilotOAuthToken(auth);
741
+ if (!auth || !token)
742
+ return null;
743
+ const enterpriseHost = validateEnterpriseHost(auth.enterpriseUrl);
744
+ if (enterpriseHost.error) {
745
+ return toQuotaError(`Invalid OpenCode Copilot enterpriseUrl: ${enterpriseHost.error}`);
746
+ }
747
+ try {
748
+ const response = await fetchGitHubJson({
749
+ url: `${getApiBaseUrl(enterpriseHost.host)}/copilot_internal/user`,
750
+ apiName: "GitHub Copilot API",
751
+ headers: {
752
+ Accept: "application/json",
753
+ Authorization: `token ${token}`,
754
+ "Editor-Version": "vscode/1.96.2",
755
+ "Editor-Plugin-Version": "copilot-chat/0.26.7",
756
+ "User-Agent": "GitHubCopilotChat/0.26.7",
757
+ "X-GitHub-Api-Version": "2025-04-01",
758
+ },
759
+ token,
760
+ requestTimeoutMs,
761
+ });
762
+ if (!response || typeof response !== "object") {
763
+ throw new Error("GitHub Copilot API returned malformed JSON");
764
+ }
765
+ return parseCopilotInternalUser(response);
766
+ }
767
+ catch (error) {
768
+ return toQuotaError(errorText(error));
769
+ }
980
770
  }
981
771
  /**
982
772
  * Query GitHub Copilot accounting.
@@ -987,71 +777,48 @@ async function fetchCopilotInternalUser(params) {
987
777
  export async function queryCopilotQuota(options = {}) {
988
778
  const pat = readQuotaConfigWithMeta();
989
779
  if (pat.state === "invalid") {
990
- return toQuotaError(`Invalid copilot-quota-token.json: ${pat.error ?? "unknown error"}${pat.selectedPath ? ` (${pat.selectedPath})` : ""}`);
991
- }
992
- if (pat.state === "absent" || !pat.config) {
993
- const { auth } = selectCopilotAuth(options.authData ?? (await readAuthFile({ integrationIds: COPILOT_AUTH_KEYS })));
994
- if (auth?.resolveError !== undefined) {
995
- return toQuotaError(`Copilot sign-in could not be read: ${auth.resolveError}. Run \`opencode auth login github-copilot\`.`);
996
- }
997
- const token = getCopilotOAuthToken(auth);
998
- if (!auth || !token)
999
- return null;
1000
- const enterpriseHost = validateEnterpriseHost(auth.enterpriseUrl);
1001
- if (enterpriseHost.error) {
1002
- return toQuotaError(`Invalid OpenCode Copilot enterpriseUrl: ${enterpriseHost.error}`);
1003
- }
1004
- try {
1005
- return await fetchCopilotInternalUser({
1006
- apiBaseUrl: getApiBaseUrl(enterpriseHost.host),
1007
- token,
1008
- requestTimeoutMs: options.requestTimeoutMs,
1009
- });
1010
- }
1011
- catch (error) {
1012
- return toQuotaError(error instanceof Error ? error.message : String(error));
1013
- }
1014
- }
1015
- const resolved = resolvePatBillingTarget(pat.config);
1016
- if (!resolved.target) {
1017
- return toQuotaError(resolved.error ?? "Unable to resolve Copilot billing scope.");
780
+ return toQuotaError(`Invalid copilot-quota-token.json: ${pat.error} (${pat.selectedPath})`);
1018
781
  }
1019
- const compatibilityError = validatePatTargetCompatibility(resolved.target, pat.tokenKind);
782
+ if (!pat.config)
783
+ return await queryCopilotOAuthQuota(options.authData, options.requestTimeoutMs);
784
+ const config = pat.config;
785
+ const billingTarget = resolvePatBillingTarget(config);
786
+ const compatibilityError = validatePatTargetCompatibility(billingTarget, pat.tokenKind);
1020
787
  if (compatibilityError)
1021
788
  return toQuotaError(compatibilityError);
1022
789
  try {
1023
- const billingModel = pat.config.billingModel ?? "ai_credits";
1024
- const apiBaseUrl = getApiBaseUrl(pat.config.enterpriseUrl);
790
+ const billingModel = config.billingModel ?? "ai_credits";
791
+ const apiBaseUrl = getApiBaseUrl(config.enterpriseUrl);
1025
792
  const { response, target } = await fetchBillingUsage({
1026
793
  apiBaseUrl,
1027
- token: pat.config.token,
1028
- target: resolved.target,
794
+ token: config.token,
795
+ target: billingTarget,
1029
796
  billingModel,
1030
797
  requestTimeoutMs: options.requestTimeoutMs,
1031
798
  });
1032
799
  return billingModel === "legacy_premium_requests"
1033
- ? toLegacyResult(response, pat.config)
800
+ ? toLegacyResult(response, config)
1034
801
  : await toAiCreditResult({
1035
802
  apiBaseUrl,
1036
803
  response,
1037
804
  target,
1038
- token: pat.config.token,
805
+ token: config.token,
1039
806
  requestTimeoutMs: options.requestTimeoutMs,
1040
807
  });
1041
808
  }
1042
809
  catch (error) {
1043
- return toQuotaError(error instanceof Error ? error.message : String(error));
810
+ return toQuotaError(errorText(error));
1044
811
  }
1045
812
  }
1046
813
  export async function resolveCopilotAuthIdentity() {
1047
814
  const pat = readQuotaConfigWithMeta();
1048
815
  if (pat.state === "invalid")
1049
816
  return null;
1050
- if (pat.state === "valid" && pat.config) {
1051
- const resolved = resolvePatBillingTarget(pat.config);
1052
- if (!resolved.target || validatePatTargetCompatibility(resolved.target, pat.tokenKind)) {
817
+ if (pat.config) {
818
+ const target = resolvePatBillingTarget(pat.config);
819
+ if (validatePatTargetCompatibility(target, pat.tokenKind))
1053
820
  return null;
1054
- }
821
+ const { year, month } = target.billingPeriod;
1055
822
  return deriveResolvedAuthIdentity({
1056
823
  providerId: "copilot:pat",
1057
824
  principal: { kind: "credential", value: pat.config.token },
@@ -1059,11 +826,11 @@ export async function resolveCopilotAuthIdentity() {
1059
826
  `api=${getApiBaseUrl(pat.config.enterpriseUrl)}`,
1060
827
  `billingModel=${pat.config.billingModel ?? "ai_credits"}`,
1061
828
  `tier=${pat.config.tier}`,
1062
- `scope=${resolved.target.scope}`,
1063
- `username=${resolved.target.username ?? ""}`,
1064
- `organization=${"organization" in resolved.target ? resolved.target.organization : ""}`,
1065
- `enterprise=${"enterprise" in resolved.target ? resolved.target.enterprise : ""}`,
1066
- `period=${formatBillingPeriod(resolved.target.billingPeriod)}`,
829
+ `scope=${target.scope}`,
830
+ `username=${target.username ?? ""}`,
831
+ `organization=${"organization" in target ? target.organization : ""}`,
832
+ `enterprise=${"enterprise" in target ? target.enterprise : ""}`,
833
+ `period=${year}-${String(month).padStart(2, "0")}`,
1067
834
  ],
1068
835
  });
1069
836
  }
@@ -1084,28 +851,4 @@ export async function hasCopilotQuotaRuntimeAvailable() {
1084
851
  const diagnostics = getCopilotQuotaAuthDiagnostics(await readAuthFile({ integrationIds: COPILOT_AUTH_KEYS }));
1085
852
  return diagnostics.billingApiAccessLikely;
1086
853
  }
1087
- export function formatCopilotQuota(result) {
1088
- if (!result || !result.success)
1089
- return null;
1090
- if (result.mode === "user_plan") {
1091
- return result.plan ? `Copilot Plan ${result.plan}` : "Copilot Plan available";
1092
- }
1093
- const unit = result.unit === "ai_credits"
1094
- ? "AI Credits"
1095
- : result.unit === "premium_interactions"
1096
- ? "Premium Interactions"
1097
- : "Premium Requests";
1098
- if (result.mode === "organization_usage") {
1099
- return `Copilot Org (${result.organization}) ${result.used} ${unit} | ${formatBillingPeriod(result.period)}`;
1100
- }
1101
- if (result.mode === "enterprise_usage") {
1102
- return `Copilot Enterprise (${result.enterprise}) ${result.used} ${unit} | ${formatBillingPeriod(result.period)}`;
1103
- }
1104
- if (result.unlimited)
1105
- return `Copilot ${unit} Unlimited`;
1106
- if (result.total !== undefined) {
1107
- return `Copilot ${unit} ${result.used}/${result.total}`;
1108
- }
1109
- return `Copilot ${unit} ${result.used} used`;
1110
- }
1111
854
  //# sourceMappingURL=copilot.js.map