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