@slkiser/opencode-quota 3.11.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -57
- package/dist/bin/opencode-quota.d.ts.map +1 -1
- package/dist/bin/opencode-quota.js +24 -7
- package/dist/bin/opencode-quota.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/anthropic.d.ts.map +1 -1
- package/dist/lib/anthropic.js +106 -3
- package/dist/lib/anthropic.js.map +1 -1
- package/dist/lib/atomic-json.d.ts +1 -0
- package/dist/lib/atomic-json.d.ts.map +1 -1
- package/dist/lib/atomic-json.js +5 -2
- package/dist/lib/atomic-json.js.map +1 -1
- package/dist/lib/cli-show.d.ts.map +1 -1
- package/dist/lib/cli-show.js +11 -7
- package/dist/lib/cli-show.js.map +1 -1
- package/dist/lib/command-surfaces.d.ts +10 -0
- package/dist/lib/command-surfaces.d.ts.map +1 -0
- package/dist/lib/command-surfaces.js +9 -0
- package/dist/lib/command-surfaces.js.map +1 -0
- package/dist/lib/config-file-utils.d.ts +5 -0
- package/dist/lib/config-file-utils.d.ts.map +1 -1
- package/dist/lib/config-file-utils.js +20 -3
- package/dist/lib/config-file-utils.js.map +1 -1
- package/dist/lib/config.d.ts +5 -3
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +124 -32
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/copilot.d.ts +19 -12
- package/dist/lib/copilot.d.ts.map +1 -1
- package/dist/lib/copilot.js +462 -566
- package/dist/lib/copilot.js.map +1 -1
- package/dist/lib/display-sanitize.d.ts.map +1 -1
- package/dist/lib/display-sanitize.js +13 -0
- package/dist/lib/display-sanitize.js.map +1 -1
- package/dist/lib/entries.d.ts +53 -4
- package/dist/lib/entries.d.ts.map +1 -1
- package/dist/lib/entries.js.map +1 -1
- package/dist/lib/init-installer.d.ts +11 -1
- package/dist/lib/init-installer.d.ts.map +1 -1
- package/dist/lib/init-installer.js +542 -154
- package/dist/lib/init-installer.js.map +1 -1
- package/dist/lib/openai.d.ts +9 -12
- package/dist/lib/openai.d.ts.map +1 -1
- package/dist/lib/openai.js +69 -40
- package/dist/lib/openai.js.map +1 -1
- package/dist/lib/opencode-config-editor.d.ts +53 -0
- package/dist/lib/opencode-config-editor.d.ts.map +1 -0
- package/dist/lib/opencode-config-editor.js +274 -0
- package/dist/lib/opencode-config-editor.js.map +1 -0
- package/dist/lib/opencode-config-providers.d.ts +18 -0
- package/dist/lib/opencode-config-providers.d.ts.map +1 -1
- package/dist/lib/opencode-config-providers.js +75 -4
- package/dist/lib/opencode-config-providers.js.map +1 -1
- package/dist/lib/opencode-runtime-paths.d.ts.map +1 -1
- package/dist/lib/opencode-runtime-paths.js +10 -3
- package/dist/lib/opencode-runtime-paths.js.map +1 -1
- package/dist/lib/opencode-storage.d.ts +10 -0
- package/dist/lib/opencode-storage.d.ts.map +1 -1
- package/dist/lib/opencode-storage.js +75 -0
- package/dist/lib/opencode-storage.js.map +1 -1
- package/dist/lib/provider-add-command.d.ts +35 -0
- package/dist/lib/provider-add-command.d.ts.map +1 -0
- package/dist/lib/provider-add-command.js +185 -0
- package/dist/lib/provider-add-command.js.map +1 -0
- package/dist/lib/provider-add.d.ts +21 -0
- package/dist/lib/provider-add.d.ts.map +1 -0
- package/dist/lib/provider-add.js +210 -0
- package/dist/lib/provider-add.js.map +1 -0
- package/dist/lib/provider-metadata.d.ts +1 -1
- package/dist/lib/provider-metadata.d.ts.map +1 -1
- package/dist/lib/provider-metadata.js +11 -5
- package/dist/lib/provider-metadata.js.map +1 -1
- package/dist/lib/quota-command-format.d.ts +2 -0
- package/dist/lib/quota-command-format.d.ts.map +1 -1
- package/dist/lib/quota-command-format.js +94 -26
- package/dist/lib/quota-command-format.js.map +1 -1
- package/dist/lib/quota-dialog-commands.d.ts.map +1 -1
- package/dist/lib/quota-dialog-commands.js +8 -4
- package/dist/lib/quota-dialog-commands.js.map +1 -1
- package/dist/lib/quota-export-types.d.ts +48 -27
- package/dist/lib/quota-export-types.d.ts.map +1 -1
- package/dist/lib/quota-export-types.js +0 -7
- package/dist/lib/quota-export-types.js.map +1 -1
- package/dist/lib/quota-export.d.ts.map +1 -1
- package/dist/lib/quota-export.js +63 -16
- package/dist/lib/quota-export.js.map +1 -1
- package/dist/lib/quota-providers-local.d.ts +55 -0
- package/dist/lib/quota-providers-local.d.ts.map +1 -0
- package/dist/lib/quota-providers-local.js +313 -0
- package/dist/lib/quota-providers-local.js.map +1 -0
- package/dist/lib/quota-providers-remote.d.ts +23 -0
- package/dist/lib/quota-providers-remote.d.ts.map +1 -0
- package/dist/lib/quota-providers-remote.js +318 -0
- package/dist/lib/quota-providers-remote.js.map +1 -0
- package/dist/lib/quota-providers.d.ts +77 -0
- package/dist/lib/quota-providers.d.ts.map +1 -0
- package/dist/lib/quota-providers.js +630 -0
- package/dist/lib/quota-providers.js.map +1 -0
- package/dist/lib/quota-render-data.d.ts +1 -0
- package/dist/lib/quota-render-data.d.ts.map +1 -1
- package/dist/lib/quota-render-data.js +35 -16
- package/dist/lib/quota-render-data.js.map +1 -1
- package/dist/lib/quota-runtime-context.d.ts.map +1 -1
- package/dist/lib/quota-runtime-context.js +3 -4
- package/dist/lib/quota-runtime-context.js.map +1 -1
- package/dist/lib/quota-state.d.ts +5 -2
- package/dist/lib/quota-state.d.ts.map +1 -1
- package/dist/lib/quota-state.js +268 -51
- package/dist/lib/quota-state.js.map +1 -1
- package/dist/lib/quota-status.d.ts +2 -1
- package/dist/lib/quota-status.d.ts.map +1 -1
- package/dist/lib/quota-status.js +247 -69
- package/dist/lib/quota-status.js.map +1 -1
- package/dist/lib/qwen-local-quota.d.ts +12 -11
- package/dist/lib/qwen-local-quota.d.ts.map +1 -1
- package/dist/lib/qwen-local-quota.js +82 -87
- package/dist/lib/qwen-local-quota.js.map +1 -1
- package/dist/lib/scoped-update.d.ts +63 -0
- package/dist/lib/scoped-update.d.ts.map +1 -0
- package/dist/lib/scoped-update.js +311 -0
- package/dist/lib/scoped-update.js.map +1 -0
- package/dist/lib/tui-runtime.d.ts +2 -0
- package/dist/lib/tui-runtime.d.ts.map +1 -1
- package/dist/lib/tui-runtime.js +33 -9
- package/dist/lib/tui-runtime.js.map +1 -1
- package/dist/lib/types.d.ts +51 -15
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +2 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +75 -100
- package/dist/plugin.js.map +1 -1
- package/dist/providers/alibaba-coding-plan.d.ts.map +1 -1
- package/dist/providers/alibaba-coding-plan.js +35 -4
- package/dist/providers/alibaba-coding-plan.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +13 -1
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/chutes.d.ts.map +1 -1
- package/dist/providers/chutes.js +6 -0
- package/dist/providers/chutes.js.map +1 -1
- package/dist/providers/copilot.d.ts +2 -1
- package/dist/providers/copilot.d.ts.map +1 -1
- package/dist/providers/copilot.js +143 -60
- package/dist/providers/copilot.js.map +1 -1
- package/dist/providers/cursor.d.ts.map +1 -1
- package/dist/providers/cursor.js +30 -1
- package/dist/providers/cursor.js.map +1 -1
- package/dist/providers/deepseek.d.ts.map +1 -1
- package/dist/providers/deepseek.js +13 -1
- package/dist/providers/deepseek.js.map +1 -1
- package/dist/providers/google-agy.d.ts.map +1 -1
- package/dist/providers/google-agy.js +7 -1
- package/dist/providers/google-agy.js.map +1 -1
- package/dist/providers/google-antigravity.d.ts.map +1 -1
- package/dist/providers/google-antigravity.js +10 -2
- package/dist/providers/google-antigravity.js.map +1 -1
- package/dist/providers/google-gemini-cli.d.ts.map +1 -1
- package/dist/providers/google-gemini-cli.js +8 -2
- package/dist/providers/google-gemini-cli.js.map +1 -1
- package/dist/providers/kimi-code.d.ts.map +1 -1
- package/dist/providers/kimi-code.js +6 -0
- package/dist/providers/kimi-code.js.map +1 -1
- package/dist/providers/minimax-coding-plan.d.ts.map +1 -1
- package/dist/providers/minimax-coding-plan.js +12 -4
- package/dist/providers/minimax-coding-plan.js.map +1 -1
- package/dist/providers/nanogpt.d.ts.map +1 -1
- package/dist/providers/nanogpt.js +19 -1
- package/dist/providers/nanogpt.js.map +1 -1
- package/dist/providers/ollama-cloud.d.ts.map +1 -1
- package/dist/providers/ollama-cloud.js +12 -0
- package/dist/providers/ollama-cloud.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +7 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js +9 -1
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/quota-providers.d.ts +6 -0
- package/dist/providers/quota-providers.d.ts.map +1 -0
- package/dist/providers/quota-providers.js +276 -0
- package/dist/providers/quota-providers.js.map +1 -0
- package/dist/providers/qwen-code.d.ts.map +1 -1
- package/dist/providers/qwen-code.js +29 -3
- package/dist/providers/qwen-code.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +2 -0
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/result-helpers.d.ts +2 -1
- package/dist/providers/result-helpers.d.ts.map +1 -1
- package/dist/providers/result-helpers.js +6 -1
- package/dist/providers/result-helpers.js.map +1 -1
- package/dist/providers/synthetic.d.ts.map +1 -1
- package/dist/providers/synthetic.js +7 -1
- package/dist/providers/synthetic.js.map +1 -1
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js +7 -1
- package/dist/providers/zai.js.map +1 -1
- package/dist/providers/zhipu.d.ts.map +1 -1
- package/dist/providers/zhipu.js +7 -1
- package/dist/providers/zhipu.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +148 -122
- package/dist/tui.tsx +122 -114
- package/package.json +29 -21
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</picture>
|
|
8
8
|
</a>
|
|
9
9
|
</p>
|
|
10
|
-
<p align="center">Quota, usage, and token visibility
|
|
10
|
+
<p align="center">Quota, usage, and token visibility in OpenCode and your terminal.</p>
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://www.npmjs.com/package/@slkiser/opencode-quota"><img alt="npm" src="https://img.shields.io/npm/v/%40slkiser%2Fopencode-quota?style=flat-square" /></a>
|
|
13
13
|
<a href="https://www.npmjs.com/package/@slkiser/opencode-quota"><img alt="npm downloads" src="https://img.shields.io/npm/dm/%40slkiser%2Fopencode-quota?style=flat-square" /></a>
|
|
@@ -26,14 +26,32 @@ npx @slkiser/opencode-quota init
|
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
> [!IMPORTANT]
|
|
29
|
-
>
|
|
29
|
+
> Node.js `>= 22` is required.
|
|
30
|
+
|
|
31
|
+
Upgrading from v3? Read the [v4 migration guide](docs/readme/v4-migration.md).
|
|
32
|
+
|
|
33
|
+
After installation:
|
|
30
34
|
|
|
31
35
|
1. Restart OpenCode.
|
|
32
|
-
2. Run
|
|
33
|
-
3. If you enabled the
|
|
34
|
-
4. If you enabled
|
|
36
|
+
2. Run a slash command in OpenCode, or use `opencode-quota show` from your terminal.
|
|
37
|
+
3. If you enabled the sidebar, open the session sidebar and look for `Quota`.
|
|
38
|
+
4. If you enabled the compact status line, look at the bottom of Home or below the message input.
|
|
35
39
|
5. If something looks wrong, run `/quota_status` in OpenCode or see [Troubleshooting](docs/readme/troubleshooting.md).
|
|
36
40
|
|
|
41
|
+
## Updating
|
|
42
|
+
|
|
43
|
+
1. Close OpenCode.
|
|
44
|
+
2. Run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx @slkiser/opencode-quota@latest update
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3. Review the exact config edits and cache directories, then confirm.
|
|
51
|
+
4. Restart OpenCode.
|
|
52
|
+
|
|
53
|
+
Use `--dry-run` to preview without changing anything. Otherwise, `update` shows the OpenCode Quota config and cache changes and asks before applying them. It leaves your other plugins and settings alone. Use `--yes` only when you intentionally need a noninteractive run.
|
|
54
|
+
|
|
37
55
|
## What you get
|
|
38
56
|
|
|
39
57
|
<table>
|
|
@@ -47,7 +65,7 @@ npx @slkiser/opencode-quota init
|
|
|
47
65
|
</tr>
|
|
48
66
|
<tr>
|
|
49
67
|
<td width="50%" align="center"><strong>Sidebar panel</strong><br />A full quota view in OpenCode's session sidebar.</td>
|
|
50
|
-
<td width="50%" align="center"><strong>
|
|
68
|
+
<td width="50%" align="center"><strong>TUI toast</strong><br />Quota checks can appear automatically while you work.</td>
|
|
51
69
|
</tr>
|
|
52
70
|
<tr>
|
|
53
71
|
<td width="50%">
|
|
@@ -58,17 +76,17 @@ npx @slkiser/opencode-quota init
|
|
|
58
76
|
</td>
|
|
59
77
|
</tr>
|
|
60
78
|
<tr>
|
|
61
|
-
<td width="50%" align="center"><strong>Compact status line</strong><br />Short quota text on
|
|
79
|
+
<td width="50%" align="center"><strong>Compact status line</strong><br />Short quota text on Home and below the message input.</td>
|
|
62
80
|
<td width="50%" align="center"><strong>Token reports</strong><br /><code>/tokens_today</code>, <code>/tokens_weekly</code>, session reports, and more.</td>
|
|
63
81
|
</tr>
|
|
64
82
|
</table>
|
|
65
83
|
|
|
66
84
|
More ways to use it:
|
|
67
85
|
|
|
68
|
-
-
|
|
69
|
-
- JSON output
|
|
70
|
-
-
|
|
71
|
-
-
|
|
86
|
+
- Check quota from a terminal with `opencode-quota show`
|
|
87
|
+
- Use JSON output in scripts, status bars, CI checks, and other tools
|
|
88
|
+
- Run the same slash commands in the TUI, Web, and Desktop
|
|
89
|
+
- Diagnose authentication, quota sources, pricing, and maintainer notices
|
|
72
90
|
|
|
73
91
|
See [Configuration](docs/readme/configuration.md) for UI options and [Manual install](docs/readme/manual-install.md) for setup details.
|
|
74
92
|
|
|
@@ -76,62 +94,79 @@ See [Configuration](docs/readme/configuration.md) for UI options and [Manual ins
|
|
|
76
94
|
|
|
77
95
|
### Core slash commands
|
|
78
96
|
|
|
79
|
-
| Command
|
|
80
|
-
|
|
|
81
|
-
| `/quota`
|
|
82
|
-
| `/quota_status`
|
|
83
|
-
| `/quota_announcements`
|
|
84
|
-
| `/pricing_refresh`
|
|
85
|
-
| `/tokens_today`
|
|
86
|
-
| `/tokens_daily`
|
|
87
|
-
| `/tokens_weekly`
|
|
88
|
-
| `/tokens_monthly`
|
|
89
|
-
| `/tokens_all`
|
|
90
|
-
| `/tokens_session`
|
|
91
|
-
| `/tokens_session_all`
|
|
92
|
-
| `/tokens_between YYYY-MM-DD YYYY-MM-DD` | Show tokens used between two dates
|
|
97
|
+
| Command | Use when |
|
|
98
|
+
| --------------------------------------- | --------------------------------------------------------------- |
|
|
99
|
+
| `/quota` | Show current quota |
|
|
100
|
+
| `/quota_status` | Diagnose setup, authentication, providers, pricing, and notices |
|
|
101
|
+
| `/quota_announcements` | Read active bundled maintainer notices |
|
|
102
|
+
| `/pricing_refresh` | Refresh local runtime pricing from `models.dev` |
|
|
103
|
+
| `/tokens_today` | Show tokens used today |
|
|
104
|
+
| `/tokens_daily` | Show tokens used in the last 24 hours |
|
|
105
|
+
| `/tokens_weekly` | Show tokens used in the last 7 days |
|
|
106
|
+
| `/tokens_monthly` | Show tokens used in the last 30 days, including pricing |
|
|
107
|
+
| `/tokens_all` | Show tokens used across all local history |
|
|
108
|
+
| `/tokens_session` | Show tokens used in the current session |
|
|
109
|
+
| `/tokens_session_all` | Show current session plus descendant sessions |
|
|
110
|
+
| `/tokens_between YYYY-MM-DD YYYY-MM-DD` | Show tokens used between two dates |
|
|
93
111
|
|
|
94
112
|
### CLI commands
|
|
95
113
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
| `opencode-quota
|
|
101
|
-
| `opencode-quota
|
|
114
|
+
Use the CLI for scripts, CI, or a quick terminal check outside OpenCode.
|
|
115
|
+
|
|
116
|
+
| Command | Use when |
|
|
117
|
+
| ---------------------------------------------- | ------------------------------------------------------------ |
|
|
118
|
+
| `opencode-quota init --dry-run` | Validate and preview installer changes without writing files |
|
|
119
|
+
| `opencode-quota update` | Preview, confirm, and apply a scoped OpenCode Quota update |
|
|
120
|
+
| `opencode-quota update --dry-run` | Preview exact config and cache targets without changing them |
|
|
121
|
+
| `opencode-quota show` | Check quota from your terminal |
|
|
122
|
+
| `opencode-quota show --provider <id>` | Check one provider only, such as `copilot` or `openai` |
|
|
123
|
+
| `opencode-quota show --json` | Print JSON for scripts, status bars, and other tools |
|
|
124
|
+
| `opencode-quota show --json --threshold <pct>` | Fail when quota is low; return exit 2 for incomplete results |
|
|
102
125
|
|
|
103
126
|
## Providers
|
|
104
127
|
|
|
128
|
+
### Pre-configured providers
|
|
129
|
+
|
|
105
130
|
Most providers work automatically. If a provider has a “Needs setup” link, open that setup note only if you use that provider.
|
|
106
131
|
|
|
107
|
-
| Provider
|
|
108
|
-
|
|
|
109
|
-
| Anthropic (Claude)
|
|
110
|
-
| GitHub Copilot
|
|
111
|
-
| OpenAI
|
|
112
|
-
| Cursor
|
|
113
|
-
| Qwen Code
|
|
114
|
-
| Alibaba Coding Plan
|
|
115
|
-
| MiniMax Coding Plan
|
|
116
|
-
| MiniMax Coding Plan (CN) | OpenCode config
|
|
117
|
-
| Kimi Code
|
|
118
|
-
| Chutes AI
|
|
119
|
-
| Synthetic
|
|
120
|
-
| Google Antigravity
|
|
121
|
-
| Google AGY
|
|
122
|
-
| Gemini CLI
|
|
123
|
-
| Z.ai Coding Plan
|
|
124
|
-
| Zhipu Coding Plan
|
|
125
|
-
| NanoGPT
|
|
126
|
-
| DeepSeek
|
|
127
|
-
| Ollama Cloud
|
|
128
|
-
| OpenCode Go
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
| Provider | Auth/setup | Data from | Reports |
|
|
133
|
+
| ------------------------ | -------------------------------------------------------------- | ------------------ | ------------------ |
|
|
134
|
+
| Anthropic (Claude) | [Needs setup](docs/readme/providers.md#anthropic-claude) | Local CLI/OAuth | Quota |
|
|
135
|
+
| GitHub Copilot | [Needs setup](docs/readme/providers.md#github-copilot) | Remote API | Usage and budget |
|
|
136
|
+
| OpenAI | Automatic | Remote API | Quota |
|
|
137
|
+
| Cursor | [Needs setup](docs/readme/providers.md#cursor) | Local estimate | Budget and spend |
|
|
138
|
+
| Qwen Code | [Needs setup](docs/readme/providers.md#qwen-code) | Local estimate | Quota |
|
|
139
|
+
| Alibaba Coding Plan | OpenCode config | Local estimate | Quota |
|
|
140
|
+
| MiniMax Coding Plan | OpenCode config | Remote API | Quota |
|
|
141
|
+
| MiniMax Coding Plan (CN) | OpenCode config | Remote API | Quota |
|
|
142
|
+
| Kimi Code | OpenCode config | Remote API | Quota |
|
|
143
|
+
| Chutes AI | API key/config | Remote API | Quota |
|
|
144
|
+
| Synthetic | Automatic | Remote API | Quota |
|
|
145
|
+
| Google Antigravity | [Needs setup](docs/readme/providers.md#google-antigravity) | Remote API | Quota |
|
|
146
|
+
| Google AGY | [Needs setup](docs/readme/providers.md#google-agy-quick-setup) | Remote API | Quota |
|
|
147
|
+
| Gemini CLI | [Needs setup](docs/readme/providers.md#gemini-cli) | Remote API | Quota |
|
|
148
|
+
| Z.ai Coding Plan | OpenCode config | Remote API | Quota |
|
|
149
|
+
| Zhipu Coding Plan | OpenCode config | Remote API | Quota |
|
|
150
|
+
| NanoGPT | API key/config | Remote API | Quota and balance |
|
|
151
|
+
| DeepSeek | API key/config | Remote API | Balance and status |
|
|
152
|
+
| Ollama Cloud | [Needs setup](docs/readme/providers.md#ollama-cloud) | Dashboard scraping | Quota |
|
|
153
|
+
| OpenCode Go | [Needs setup](docs/readme/providers.md#opencode-go) | Dashboard scraping | Quota |
|
|
154
|
+
|
|
155
|
+
The quota view uses short labels such as `Day quota`, `5h quota`, `Day budget`, and `Balance`. Bar width varies by surface. JSON keeps the precise accounting type for scripts.
|
|
156
|
+
|
|
157
|
+
### Custom providers
|
|
158
|
+
|
|
159
|
+
A quota provider definition tells OpenCode Quota how to obtain accounting data for an OpenCode provider. Run the guided command. It asks only structural questions, previews the exact global OpenCode config change, and asks before writing:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx @slkiser/opencode-quota@latest provider add
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Setup details live in the [Provider setup guide](docs/readme/providers.md#custom-providers).
|
|
131
166
|
|
|
132
167
|
## Troubleshooting
|
|
133
168
|
|
|
134
|
-
|
|
169
|
+
If quota or token data looks wrong:
|
|
135
170
|
|
|
136
171
|
1. Run `/quota_status`, or start with `opencode-quota show` for a terminal quota summary.
|
|
137
172
|
2. Confirm the expected provider appears in the detected provider list.
|
|
@@ -141,12 +176,23 @@ Start here when quota or token data looks wrong:
|
|
|
141
176
|
|
|
142
177
|
## Reference
|
|
143
178
|
|
|
179
|
+
Project guides:
|
|
180
|
+
|
|
144
181
|
- [Manual install](docs/readme/manual-install.md)
|
|
145
182
|
- [Configuration](docs/readme/configuration.md)
|
|
146
183
|
- [Providers](docs/readme/providers.md)
|
|
147
184
|
- [Troubleshooting](docs/readme/troubleshooting.md)
|
|
148
185
|
- [External integration](docs/readme/external-integration.md)
|
|
149
186
|
|
|
187
|
+
External references:
|
|
188
|
+
|
|
189
|
+
- [OpenCode docs](https://opencode.ai/docs/)
|
|
190
|
+
- [OpenCode config](https://opencode.ai/docs/config/)
|
|
191
|
+
- [OpenCode plugins](https://opencode.ai/docs/plugins/)
|
|
192
|
+
- [OpenCode TUI](https://opencode.ai/docs/tui/)
|
|
193
|
+
- [models.dev pricing data](https://models.dev/)
|
|
194
|
+
- [Node.js downloads](https://nodejs.org/en/download)
|
|
195
|
+
|
|
150
196
|
## Contributors
|
|
151
197
|
|
|
152
198
|
Thanks to everyone who has contributed to OpenCode Quota.
|
|
@@ -165,4 +211,4 @@ OpenCode Quota is not built by the OpenCode team and is not affiliated with Open
|
|
|
165
211
|
|
|
166
212
|
## Star history
|
|
167
213
|
|
|
168
|
-
|
|
214
|
+

|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-quota.d.ts","sourceRoot":"","sources":["../../src/bin/opencode-quota.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"opencode-quota.d.ts","sourceRoot":"","sources":["../../src/bin/opencode-quota.ts"],"names":[],"mappings":";AA2CA,wBAAgB,gBAAgB,CAC9B,KAAK,GAAE,MAAM,GAAG,SAA2B,EAC3C,UAAU,GAAE,MAAuC,EACnD,WAAW,GAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAuB,GACzD,OAAO,CAMT;AAED,wBAAsB,IAAI,CAAC,IAAI,WAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwCxE"}
|
|
@@ -5,17 +5,25 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { runInitInstaller } from "../lib/init-installer.js";
|
|
6
6
|
const USAGE = [
|
|
7
7
|
"Usage:",
|
|
8
|
-
" npx @slkiser/opencode-quota init [--sync-legacy-config]",
|
|
8
|
+
" npx @slkiser/opencode-quota init [--dry-run] [--sync-legacy-config]",
|
|
9
9
|
" npx @slkiser/opencode-quota show [--provider <provider-id>] [--json] [--threshold <pct>]",
|
|
10
|
+
" npx @slkiser/opencode-quota update [--dry-run] [--yes]",
|
|
11
|
+
" npx @slkiser/opencode-quota provider add [--dry-run]",
|
|
10
12
|
" npx @slkiser/opencode-quota --help",
|
|
11
13
|
"",
|
|
12
14
|
"Commands:",
|
|
13
15
|
" init Run the interactive quota installer",
|
|
16
|
+
" --dry-run Preview validated changes without writing files",
|
|
14
17
|
" --sync-legacy-config also writes experimental.quotaToast",
|
|
15
18
|
" show Print a quick quota glance",
|
|
16
19
|
" --json Machine-readable JSON output (reads from cache)",
|
|
17
|
-
" --threshold <pct> With --json, exit 1 if below <pct>%, 2 if
|
|
20
|
+
" --threshold <pct> With --json, exit 1 if below <pct>%, 2 if incomplete/not comparable",
|
|
18
21
|
" --provider <id> Filter to one provider",
|
|
22
|
+
" update Safely refresh only OpenCode Quota config and verified cache entries",
|
|
23
|
+
" --dry-run Preview without changing config or cache",
|
|
24
|
+
" --yes Apply noninteractively after printing the preview",
|
|
25
|
+
" provider add Add or update one global quotaProviders definition",
|
|
26
|
+
" --dry-run Preview the exact global OpenCode config without writing",
|
|
19
27
|
].join("\n");
|
|
20
28
|
function printUsage() {
|
|
21
29
|
console.log(USAGE);
|
|
@@ -45,17 +53,26 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
45
53
|
return 0;
|
|
46
54
|
}
|
|
47
55
|
if (command === "init") {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const allowed = new Set(["--dry-run", "--sync-legacy-config"]);
|
|
57
|
+
if (rest.every((arg) => allowed.has(arg)) && new Set(rest).size === rest.length) {
|
|
58
|
+
return await runInitInstaller({
|
|
59
|
+
...(rest.includes("--dry-run") ? { dryRun: true } : {}),
|
|
60
|
+
...(rest.includes("--sync-legacy-config") ? { syncLegacyConfig: true } : {}),
|
|
61
|
+
});
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
if (command === "show") {
|
|
56
65
|
const { runCliShowCommand } = await import("../lib/cli-show.js");
|
|
57
66
|
return await runCliShowCommand({ argv: rest });
|
|
58
67
|
}
|
|
68
|
+
if (command === "update") {
|
|
69
|
+
const { runScopedUpdateCommand } = await import("../lib/scoped-update.js");
|
|
70
|
+
return await runScopedUpdateCommand({ argv: rest });
|
|
71
|
+
}
|
|
72
|
+
if (command === "provider" && rest[0] === "add") {
|
|
73
|
+
const { runProviderAddCommand } = await import("../lib/provider-add-command.js");
|
|
74
|
+
return await runProviderAddCommand({ argv: rest.slice(1) });
|
|
75
|
+
}
|
|
59
76
|
printUsage();
|
|
60
77
|
return 1;
|
|
61
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-quota.js","sourceRoot":"","sources":["../../src/bin/opencode-quota.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,KAAK,GAAG;IACZ,QAAQ;IACR,
|
|
1
|
+
{"version":3,"file":"opencode-quota.js","sourceRoot":"","sources":["../../src/bin/opencode-quota.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,7 @@ declare const pluginModule: {
|
|
|
11
11
|
};
|
|
12
12
|
export default pluginModule;
|
|
13
13
|
export { QuotaToastPlugin } from "./plugin.js";
|
|
14
|
+
export { QUOTA_PROVIDER_MODES, QUOTA_PROVIDER_REMOTE_FORMATS, QUOTA_PROVIDER_WINDOW_TYPES, validateQuotaProviders, } from "./lib/quota-providers.js";
|
|
15
|
+
export type { QuotaProviderDefinition, RemoteApiQuotaProviderDefinition, LocalEstimateQuotaProviderDefinition, LocalEstimateWindow, } from "./lib/quota-providers.js";
|
|
14
16
|
export type { QuotaToastConfig, MaintainerAnnouncementsConfig, GoogleModelId, PricingSnapshotSource, CopilotEnterpriseUsageResult, CopilotOrganizationUsageResult, CopilotQuotaResult, GoogleQuotaResult, GoogleModelQuota, MiniMaxResult, MiniMaxResultEntry, } from "./lib/types.js";
|
|
15
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,QAAA,MAAM,YAAY;;;CAGQ,CAAC;AAE3B,eAAe,YAAY,CAAC;AAI5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,YAAY,EACV,gBAAgB,EAChB,6BAA6B,EAC7B,aAAa,EACb,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,QAAA,MAAM,YAAY;;;CAGQ,CAAC;AAE3B,eAAe,YAAY,CAAC;AAI5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,uBAAuB,EACvB,gCAAgC,EAChC,oCAAoC,EACpC,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACV,gBAAgB,EAChB,6BAA6B,EAC7B,aAAa,EACb,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,kBAAkB,GACnB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -18,4 +18,6 @@ export default pluginModule;
|
|
|
18
18
|
// Keep the named export for backward compatibility with consumers that import
|
|
19
19
|
// { QuotaToastPlugin } directly.
|
|
20
20
|
export { QuotaToastPlugin } from "./plugin.js";
|
|
21
|
+
// Re-export types for consumers (types are erased at runtime, so safe to export)
|
|
22
|
+
export { QUOTA_PROVIDER_MODES, QUOTA_PROVIDER_REMOTE_FORMATS, QUOTA_PROVIDER_WINDOW_TYPES, validateQuotaProviders, } from "./lib/quota-providers.js";
|
|
21
23
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAO/C,qDAAqD;AACrD,6EAA6E;AAC7E,wEAAwE;AACxE,yCAAyC;AACzC,MAAM,YAAY,GAAG;IACnB,EAAE,EAAE,yBAAyB;IAC7B,MAAM,EAAE,gBAAgB;CACA,CAAC;AAE3B,eAAe,YAAY,CAAC;AAE5B,8EAA8E;AAC9E,iCAAiC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAO/C,qDAAqD;AACrD,6EAA6E;AAC7E,wEAAwE;AACxE,yCAAyC;AACzC,MAAM,YAAY,GAAG;IACnB,EAAE,EAAE,yBAAyB;IAC7B,MAAM,EAAE,gBAAgB;CACA,CAAC;AAE3B,eAAe,YAAY,CAAC;AAE5B,8EAA8E;AAC9E,iCAAiC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,iFAAiF;AACjF,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,0BAA0B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/lib/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/lib/anthropic.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/anthropic.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* file) and Anthropic's OAuth usage endpoint.
|
|
8
8
|
*/
|
|
9
9
|
import { execFile } from "child_process";
|
|
10
|
+
import { createHash } from "crypto";
|
|
10
11
|
import { readFile } from "fs/promises";
|
|
11
12
|
import { homedir } from "os";
|
|
12
13
|
import { join } from "path";
|
|
@@ -15,6 +16,8 @@ import { fetchWithTimeout } from "./http.js";
|
|
|
15
16
|
const DEFAULT_CLAUDE_BINARY = "claude";
|
|
16
17
|
const CLAUDE_COMMAND_TIMEOUT_MS = 3_000;
|
|
17
18
|
const ANTHROPIC_DIAGNOSTICS_TTL_MS = 5_000;
|
|
19
|
+
const ANTHROPIC_OAUTH_BACKOFF_BASE_MS = 30_000;
|
|
20
|
+
const ANTHROPIC_OAUTH_COOLDOWN_MAX_MS = 15 * 60_000;
|
|
18
21
|
const ANTHROPIC_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
19
22
|
const ANTHROPIC_BETA_HEADER = "oauth-2025-04-20";
|
|
20
23
|
const CLAUDE_CODE_CREDENTIALS_SERVICE = "Claude Code-credentials";
|
|
@@ -22,6 +25,8 @@ const CLAUDE_NO_LOCAL_QUOTA_MESSAGE = "Claude CLI auth detected, but local quota
|
|
|
22
25
|
const ANTHROPIC_NO_QUOTA_MESSAGE = "Claude CLI auth detected, but quota was unavailable from both the local CLI and Claude OAuth fallback.";
|
|
23
26
|
const diagnosticsCache = new Map();
|
|
24
27
|
const localDiagnosticsCache = new Map();
|
|
28
|
+
const anthropicOAuthCooldowns = new Map();
|
|
29
|
+
const anthropicOAuthInFlight = new Map();
|
|
25
30
|
export function resolveAnthropicBinaryPath(binaryPath) {
|
|
26
31
|
const trimmed = binaryPath?.trim();
|
|
27
32
|
return trimmed ? trimmed : DEFAULT_CLAUDE_BINARY;
|
|
@@ -361,7 +366,53 @@ async function readClaudeCredentialsAccessToken() {
|
|
|
361
366
|
detail: unavailableDetails[0] ?? getClaudeCredentialsNotFoundDetail(locationsChecked),
|
|
362
367
|
};
|
|
363
368
|
}
|
|
364
|
-
|
|
369
|
+
function fingerprintAccessToken(accessToken) {
|
|
370
|
+
return createHash("sha256").update(accessToken).digest("hex");
|
|
371
|
+
}
|
|
372
|
+
function parseRetryAfterMs(value, nowMs) {
|
|
373
|
+
const trimmed = value?.trim();
|
|
374
|
+
if (!trimmed) {
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
if (/^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(trimmed)) {
|
|
378
|
+
const seconds = Number(trimmed);
|
|
379
|
+
return Number.isFinite(seconds) && seconds > 0 ? seconds * 1_000 : undefined;
|
|
380
|
+
}
|
|
381
|
+
const retryAtMs = Date.parse(trimmed);
|
|
382
|
+
const durationMs = retryAtMs - nowMs;
|
|
383
|
+
return Number.isFinite(durationMs) && durationMs > 0 ? durationMs : undefined;
|
|
384
|
+
}
|
|
385
|
+
function getAnthropicOAuthCooldownDurationMs(failureCount, retryAfter, nowMs) {
|
|
386
|
+
const exponentialMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, ANTHROPIC_OAUTH_BACKOFF_BASE_MS * 2 ** Math.min(failureCount, 30));
|
|
387
|
+
const retryAfterMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, parseRetryAfterMs(retryAfter, nowMs) ?? 0);
|
|
388
|
+
return Math.max(exponentialMs, retryAfterMs);
|
|
389
|
+
}
|
|
390
|
+
function getAnthropicOAuthCooldownMessage(remainingMs) {
|
|
391
|
+
const boundedRemainingMs = Math.min(ANTHROPIC_OAUTH_COOLDOWN_MAX_MS, Math.max(0, remainingMs));
|
|
392
|
+
return `Anthropic OAuth usage probe paused after HTTP 429; retry in ${Math.ceil(boundedRemainingMs / 1_000)}s.`;
|
|
393
|
+
}
|
|
394
|
+
function retainAnthropicOAuthCooldownForToken(tokenFingerprint) {
|
|
395
|
+
for (const fingerprint of anthropicOAuthCooldowns.keys()) {
|
|
396
|
+
if (fingerprint !== tokenFingerprint) {
|
|
397
|
+
anthropicOAuthCooldowns.delete(fingerprint);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
function redactAccessTokenFromSanitizedDetail(detail, accessToken) {
|
|
402
|
+
const sanitizedDetail = sanitizeDisplayText(detail);
|
|
403
|
+
const sanitizedAccessToken = sanitizeDisplayText(accessToken);
|
|
404
|
+
const redactedDetail = sanitizedDetail.split(accessToken).join("[redacted]");
|
|
405
|
+
return sanitizedAccessToken
|
|
406
|
+
? redactedDetail.split(sanitizedAccessToken).join("[redacted]")
|
|
407
|
+
: redactedDetail;
|
|
408
|
+
}
|
|
409
|
+
function sanitizeAnthropicApiDetail(detail, accessToken) {
|
|
410
|
+
return redactAccessTokenFromSanitizedDetail(detail, accessToken).slice(0, 120);
|
|
411
|
+
}
|
|
412
|
+
function sanitizeAnthropicRequestError(detail, accessToken) {
|
|
413
|
+
return redactAccessTokenFromSanitizedDetail(detail, accessToken);
|
|
414
|
+
}
|
|
415
|
+
async function performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint, requestTimeoutMs) {
|
|
365
416
|
let response;
|
|
366
417
|
try {
|
|
367
418
|
response = await fetchWithTimeout(ANTHROPIC_USAGE_URL, {
|
|
@@ -374,13 +425,37 @@ async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeo
|
|
|
374
425
|
catch (error) {
|
|
375
426
|
return {
|
|
376
427
|
state: "unavailable",
|
|
377
|
-
detail:
|
|
428
|
+
detail: sanitizeAnthropicRequestError(error instanceof Error ? error.message : String(error), accessToken),
|
|
378
429
|
};
|
|
379
430
|
}
|
|
431
|
+
if (response.status === 429) {
|
|
432
|
+
let detail = "";
|
|
433
|
+
try {
|
|
434
|
+
detail = sanitizeAnthropicApiDetail(await response.text(), accessToken);
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
detail = "";
|
|
438
|
+
}
|
|
439
|
+
const nowMs = Date.now();
|
|
440
|
+
const previousFailureCount = anthropicOAuthCooldowns.get(tokenFingerprint)?.failureCount ?? 0;
|
|
441
|
+
const durationMs = getAnthropicOAuthCooldownDurationMs(previousFailureCount, response.headers?.get?.("Retry-After") ?? null, nowMs);
|
|
442
|
+
anthropicOAuthCooldowns.set(tokenFingerprint, {
|
|
443
|
+
failureCount: previousFailureCount + 1,
|
|
444
|
+
blockedUntilMs: nowMs + durationMs,
|
|
445
|
+
});
|
|
446
|
+
const errorDetail = detail
|
|
447
|
+
? `Anthropic API error ${response.status}: ${detail}`
|
|
448
|
+
: `Anthropic API returned ${response.status}`;
|
|
449
|
+
return {
|
|
450
|
+
state: "unavailable",
|
|
451
|
+
detail: `${errorDetail} ${getAnthropicOAuthCooldownMessage(durationMs)}`,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
anthropicOAuthCooldowns.delete(tokenFingerprint);
|
|
380
455
|
if (!response.ok) {
|
|
381
456
|
let detail = "";
|
|
382
457
|
try {
|
|
383
|
-
detail =
|
|
458
|
+
detail = sanitizeAnthropicApiDetail(await response.text(), accessToken);
|
|
384
459
|
}
|
|
385
460
|
catch {
|
|
386
461
|
detail = "";
|
|
@@ -414,6 +489,32 @@ async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeo
|
|
|
414
489
|
quota,
|
|
415
490
|
};
|
|
416
491
|
}
|
|
492
|
+
async function queryAnthropicQuotaFromOAuthAccessToken(accessToken, requestTimeoutMs) {
|
|
493
|
+
const tokenFingerprint = fingerprintAccessToken(accessToken);
|
|
494
|
+
retainAnthropicOAuthCooldownForToken(tokenFingerprint);
|
|
495
|
+
const nowMs = Date.now();
|
|
496
|
+
const cooldown = anthropicOAuthCooldowns.get(tokenFingerprint);
|
|
497
|
+
if (cooldown && cooldown.blockedUntilMs > nowMs) {
|
|
498
|
+
return {
|
|
499
|
+
state: "unavailable",
|
|
500
|
+
detail: getAnthropicOAuthCooldownMessage(cooldown.blockedUntilMs - nowMs),
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
const existingInFlight = anthropicOAuthInFlight.get(tokenFingerprint);
|
|
504
|
+
if (existingInFlight) {
|
|
505
|
+
return await existingInFlight;
|
|
506
|
+
}
|
|
507
|
+
const inFlight = performAnthropicOAuthUsageRequest(accessToken, tokenFingerprint, requestTimeoutMs);
|
|
508
|
+
anthropicOAuthInFlight.set(tokenFingerprint, inFlight);
|
|
509
|
+
try {
|
|
510
|
+
return await inFlight;
|
|
511
|
+
}
|
|
512
|
+
finally {
|
|
513
|
+
if (anthropicOAuthInFlight.get(tokenFingerprint) === inFlight) {
|
|
514
|
+
anthropicOAuthInFlight.delete(tokenFingerprint);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
417
518
|
function extractAuthBoolean(data) {
|
|
418
519
|
const record = asRecord(data);
|
|
419
520
|
if (!record) {
|
|
@@ -665,6 +766,8 @@ async function probeAnthropicLocalDiagnostics(options = {}) {
|
|
|
665
766
|
export function clearAnthropicDiagnosticsCacheForTests() {
|
|
666
767
|
diagnosticsCache.clear();
|
|
667
768
|
localDiagnosticsCache.clear();
|
|
769
|
+
anthropicOAuthCooldowns.clear();
|
|
770
|
+
anthropicOAuthInFlight.clear();
|
|
668
771
|
}
|
|
669
772
|
async function getCachedAnthropicLocalDiagnostics(options = {}) {
|
|
670
773
|
const binaryPath = resolveAnthropicBinaryPath(options.binaryPath);
|