dsh-subscriptions 0.2.0 → 0.2.2
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 +212 -180
- package/lib/auth/claude-code-creds.js +31 -9
- package/lib/auth/device-flow.js +16 -9
- package/lib/auth/oauth-flow.js +13 -10
- package/lib/auth/rpc.js +74 -23
- package/lib/auth/store.js +80 -31
- package/lib/client/CursorCard.d.ts +1 -1
- package/lib/client/CursorCard.js +50 -16
- package/lib/client/ExternalUsageCards.d.ts +1 -1
- package/lib/client/ExternalUsageCards.js +37 -16
- package/lib/client/ImageGallery.d.ts +2 -2
- package/lib/client/ImageGallery.js +92 -33
- package/lib/client/ImageGenerateToolview.js +50 -14
- package/lib/client/OllamaCard.d.ts +1 -1
- package/lib/client/OllamaCard.js +26 -8
- package/lib/client/OllamaSettingsManager.js +113 -30
- package/lib/client/ProviderAccountManager.d.ts +1 -1
- package/lib/client/ProviderAccountManager.js +164 -49
- package/lib/client/ProviderModelEditor.js +107 -26
- package/lib/client/SpeedSelect.d.ts +62 -14
- package/lib/client/SpeedSelect.js +257 -46
- package/lib/client/SubscriptionUsageBadge.d.ts +4 -10
- package/lib/client/SubscriptionUsageBadge.js +300 -112
- package/lib/client/SubscriptionsSection.js +258 -85
- package/lib/client/UsageBadgeDisplaySetting.js +35 -12
- package/lib/client/UsageMeter.d.ts +1 -1
- package/lib/client/UsageMeter.js +62 -24
- package/lib/client/VideoGenerateToolview.js +69 -17
- package/lib/client/account-preferences.d.ts +8 -0
- package/lib/client/account-preferences.js +20 -5
- package/lib/client/host-contract.d.ts +11 -2
- package/lib/client/host-contract.js +20 -3
- package/lib/client/index.d.ts +5 -5
- package/lib/client/index.js +34 -12
- package/lib/client/locales.d.ts +10 -0
- package/lib/client/locales.js +61 -51
- package/lib/client/ollama-draft.js +21 -12
- package/lib/client/reset-action.js +6 -4
- package/lib/client/reset-credits-view.d.ts +1 -1
- package/lib/client/reset-credits-view.js +66 -17
- package/lib/client/subscription-card-styles.js +94 -24
- package/lib/client/usage-color-preferences.js +4 -2
- package/lib/client/usage-pace.js +30 -12
- package/lib/client.js +287 -47
- package/lib/client.js.map +1 -1
- package/lib/http.js +1 -1
- package/lib/index.d.ts +3 -3
- package/lib/index.js +118 -64
- package/lib/model-defaults.js +4 -2
- package/lib/provider-settings.d.ts +12 -0
- package/lib/provider-settings.js +58 -16
- package/lib/providers/account-preferences.js +51 -22
- package/lib/providers/accounts.js +15 -9
- package/lib/providers/antigravity-oauth-client.js +2 -2
- package/lib/providers/antigravity.js +141 -68
- package/lib/providers/catalog-store.js +120 -41
- package/lib/providers/claude-cli-version.js +3 -3
- package/lib/providers/claude.d.ts +9 -2
- package/lib/providers/claude.js +153 -90
- package/lib/providers/codex-client-version.js +3 -3
- package/lib/providers/codex-search.js +40 -13
- package/lib/providers/codex.js +196 -112
- package/lib/providers/common.js +71 -39
- package/lib/providers/copilot.js +143 -82
- package/lib/providers/cursor-adapter.js +42 -18
- package/lib/providers/cursor-auth.d.ts +1 -1
- package/lib/providers/cursor-auth.js +69 -24
- package/lib/providers/cursor-model-settings.js +14 -5
- package/lib/providers/cursor-usage.js +27 -13
- package/lib/providers/external-usage-controller.js +14 -5
- package/lib/providers/external-usage.js +59 -23
- package/lib/providers/grok.js +152 -89
- package/lib/providers/image-pool.js +29 -11
- package/lib/providers/minimax-usage.js +31 -11
- package/lib/providers/npm-cli-version.js +10 -3
- package/lib/providers/ollama-settings.js +24 -8
- package/lib/providers/ollama-web.js +29 -11
- package/lib/providers/ollama.js +129 -66
- package/lib/providers/pool-family.js +11 -3
- package/lib/providers/pool-health.js +28 -8
- package/lib/providers/pool-usage.js +16 -9
- package/lib/providers/pool.d.ts +8 -0
- package/lib/providers/pool.js +81 -42
- package/lib/providers/rate-limit.js +8 -2
- package/lib/providers/replay.js +40 -17
- package/lib/providers/reset-redemption.js +18 -6
- package/lib/tools/image-generate.js +123 -65
- package/lib/tools/registration.js +5 -2
- package/lib/tools/video-generate.js +51 -31
- package/lib/tools/x-search.js +50 -22
- package/lib/translate/anthropic.js +85 -37
- package/lib/translate/antigravity-schema.js +71 -28
- package/lib/translate/antigravity-thinking.js +22 -9
- package/lib/translate/antigravity.js +141 -50
- package/lib/translate/chat-completions.js +67 -23
- package/lib/translate/resolved.js +55 -21
- package/lib/translate/responses.js +69 -29
- package/lib/translate/sse.js +4 -1
- package/package.json +26 -4
package/README.md
CHANGED
|
@@ -11,46 +11,45 @@ reported quota in **Settings → Subscriptions**.
|
|
|
11
11
|
## What it adds
|
|
12
12
|
|
|
13
13
|
- **Six subscription model sources:** Connect ChatGPT/Codex, Claude, Grok,
|
|
14
|
-
GitHub Copilot, Google Antigravity, or Cursor and choose their models in
|
|
15
|
-
|
|
14
|
+
GitHub Copilot, Google Antigravity, or Cursor and choose their models in DSH's
|
|
15
|
+
picker. These routes use account sign-in, without provider API keys.
|
|
16
16
|
- **Ollama Cloud key route:** Add the `ollama-cloud` route with an
|
|
17
|
-
`OLLAMA_API_KEY` credential. The route ships no model catalog:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
The
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
the
|
|
25
|
-
route
|
|
26
|
-
|
|
27
|
-
on
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
from the standalone plugin: its transient-error reclassification,
|
|
32
|
-
per-image request quotas, and per-model usage counts. See the
|
|
17
|
+
`OLLAMA_API_KEY` credential. The route ships no model catalog: configure it on
|
|
18
|
+
the Settings → Subscriptions card, which fetches the cloud list, ticks the
|
|
19
|
+
models to keep, and edits each one's display name, order, default reasoning
|
|
20
|
+
effort, and local context window. The picker shows exactly the ticked list, so
|
|
21
|
+
an unconfigured route offers no model. The card also edits the base URL, the
|
|
22
|
+
credential reference, and the web search/fetch switch, and persists them under
|
|
23
|
+
the DSH home directory. No OAuth sign-in. A hand-written `llm-pi-ai` route
|
|
24
|
+
with the same id collides with this one: delete the manual block when enabling
|
|
25
|
+
the plugin route. Stop sequences are unsupported on this route, consistent
|
|
26
|
+
with the other adapters. Web search/fetch stay off until the card's switch is
|
|
27
|
+
on (or a profile sets `ollama.web`), so untouched installs keep their existing
|
|
28
|
+
web provider; a profile still pins them to `ollama-cloud`. Not ported from the
|
|
29
|
+
standalone plugin: its transient-error reclassification, per-image request
|
|
30
|
+
quotas, and per-model usage counts. See the
|
|
33
31
|
[key-route note](.agents/notes/implemented/provider/2026-10-10-ollama-cloud-key-route.md).
|
|
34
|
-
- **Account and model control:** Refresh catalogs and choose visible models.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
- **Account and model control:** Refresh catalogs and choose visible models. For
|
|
33
|
+
Codex, Claude, Grok, Copilot, and Antigravity, manage multiple accounts and
|
|
34
|
+
same-provider pools. Pools can use available quota to select an account and
|
|
35
|
+
fail over before a reply starts. See
|
|
36
|
+
[account management](docs/account-management.md).
|
|
38
37
|
- **Quota while you work:** See reported usage windows and reset times on
|
|
39
38
|
provider cards and in an optional session-footer pill. The same view reads
|
|
40
|
-
OpenCode Go and Kimi Code usage through keys already configured in
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- **Provider tools:** Use Codex web search, Grok X search, ChatGPT or Grok
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
OpenCode Go and Kimi Code usage through keys already configured in **Settings
|
|
40
|
+
→ Models** (their model routes remain built into DSH), and Ollama Cloud usage
|
|
41
|
+
through its `OLLAMA_API_KEY` credential (its route ships in this plugin).
|
|
42
|
+
GitHub Copilot has no usage endpoint.
|
|
43
|
+
- **Provider tools:** Use Codex web search, Grok X search, ChatGPT or Grok image
|
|
44
|
+
generation and editing, and Grok video generation when the matching provider
|
|
45
|
+
is enabled.
|
|
47
46
|
|
|
48
47
|
## Screenshots
|
|
49
48
|
|
|
50
|
-
Captured against DSH 0.2.0-rc.2 in the web UI with a local stub serving
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
Captured against DSH 0.2.0-rc.2 in the web UI with a local stub serving frozen
|
|
50
|
+
provider responses, so each image shows a product state rather than a real
|
|
51
|
+
account. Identities in the images are fabricated, and the quota percentages,
|
|
52
|
+
catalogs, and reset countdowns are sample data.
|
|
54
53
|
|
|
55
54
|
### Subscriptions
|
|
56
55
|
|
|
@@ -65,23 +64,23 @@ Logged-in providers join the session model picker with their live catalogs.
|
|
|
65
64
|
|
|
66
65
|

|
|
67
66
|
|
|
68
|
-
Models that advertise reasoning levels get an **Effort** selector in the
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
Models that advertise reasoning levels get an **Effort** selector in the same
|
|
68
|
+
menu. Levels and defaults come from the provider's live catalog; without
|
|
69
|
+
discovery Codex falls back to a built-in list, and a configured default
|
|
70
|
+
overrides either.
|
|
72
71
|
|
|
73
72
|

|
|
74
73
|
|
|
75
|
-
Codex models whose catalog advertises the fast tier get a **Speed** toggle
|
|
76
|
-
|
|
74
|
+
Codex models whose catalog advertises the fast tier get a **Speed** toggle in
|
|
75
|
+
the composer's tool row: Standard or Fast, per session.
|
|
77
76
|
|
|
78
77
|

|
|
79
78
|
|
|
80
|
-
**Settings → Subscriptions → provider → Manage** edits account aliases,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
**Settings → Subscriptions → provider → Manage** edits account aliases, pool
|
|
80
|
+
participation, model allowlists, and the per-model effort, context, and tool
|
|
81
|
+
settings. A context value only lowers the window a session plans against, never
|
|
82
|
+
above what the provider advertises; Codex and Claude support it, and it does not
|
|
83
|
+
enlarge the API's capacity.
|
|
85
84
|
|
|
86
85
|

|
|
87
86
|
|
|
@@ -89,85 +88,81 @@ it, and it does not enlarge the API's capacity.
|
|
|
89
88
|
|
|
90
89
|
### Quota while you work
|
|
91
90
|
|
|
92
|
-
The composer's stats row gains a **provider usage** pill showing the
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
The composer's stats row gains a **provider usage** pill showing the used
|
|
92
|
+
percentage and reset window for the provider of the session's current model. It
|
|
93
|
+
shows at most one provider; switching to a non-subscription model keeps the most
|
|
94
|
+
recent subscription selected in the mounted conversation view, or stays hidden
|
|
95
|
+
if there is none. **Always show** instead rotates through the providers that
|
|
96
|
+
report usage every 10 seconds while the current model has no quota source, so
|
|
97
|
+
the pill never disappears.
|
|
99
98
|
|
|
100
99
|

|
|
101
100
|
|
|
102
|
-
Click the pill to expand every provider and account that reports usage —
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
elapsed
|
|
113
|
-
turns
|
|
114
|
-
and
|
|
115
|
-
|
|
116
|
-
cursor without a pace warning. Choose Standard, Relaxed, or Remaining colors
|
|
117
|
-
in **Settings → Subscriptions**.
|
|
101
|
+
Click the pill to expand every provider and account that reports usage — the
|
|
102
|
+
default account is starred, and the current provider is listed first. A provider
|
|
103
|
+
with no usage endpoint, such as GitHub Copilot, has no row, and neither do
|
|
104
|
+
accounts without a usage window. Antigravity previews only the current model's
|
|
105
|
+
windows; the other model windows stay in a closed disclosure.
|
|
106
|
+
|
|
107
|
+
Quota bars include a dark elapsed-time cursor whenever the provider's timing
|
|
108
|
+
places the window in time, including at 0% used and for stale or old readings.
|
|
109
|
+
Compare the colored fill (quota used) with the cursor (time elapsed); hover for
|
|
110
|
+
the percentages and reset countdown. Standard coloring turns the fill orange
|
|
111
|
+
when a fresh reading leads elapsed time by 10 points, and Relaxed uses 15; 90%
|
|
112
|
+
used turns it red and takes priority. Windows without known timing omit the
|
|
113
|
+
cursor, and a stale or old reading keeps its cursor without a pace warning.
|
|
114
|
+
Choose Standard, Relaxed, or Remaining colors in **Settings → Subscriptions**.
|
|
118
115
|
|
|
119
116
|

|
|
120
117
|
|
|
121
118
|
#### Codex usage limit resets
|
|
122
119
|
|
|
123
|
-
The Codex account card shows banked full-reset credits and their expirations
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
The Codex account card shows banked full-reset credits and their expirations in
|
|
121
|
+
a closed disclosure. A failed optional lookup reports an error without hiding
|
|
122
|
+
ordinary quota windows. **Use…** selects the earliest-expiring available credit
|
|
123
|
+
and requires a fresh unscoped weekly reading of at least 80%, then an explicit
|
|
124
|
+
confirmation and acknowledgment. Confirmation expires after 60 seconds; the
|
|
125
|
+
server rechecks usage and credit availability before submission.
|
|
129
126
|
|
|
130
127
|
One reset consumes one credit and resets weekly and 5-hour limits. This
|
|
131
|
-
interface cannot undo it. An unconfirmed outcome blocks further redemption
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
128
|
+
interface cannot undo it. An unconfirmed outcome blocks further redemption for
|
|
129
|
+
that account in the current host process. Restarting clears that block, but must
|
|
130
|
+
not be used to bypass it: check credits and limits in Codex before retrying,
|
|
131
|
+
because the first submission may already have spent a credit. The private
|
|
132
|
+
endpoint is covered by offline fakes, not live-account checks. See the
|
|
133
|
+
[manual reset decision](.agents/notes/implemented/provider/2026-10-04-codex-manual-reset.md)
|
|
137
134
|
for the retry boundary and verification limits.
|
|
138
135
|
|
|
139
136
|
#### Claude usage limit resets
|
|
140
137
|
|
|
141
|
-
The Claude account card shows banked limit resets from Anthropic's
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
The Claude account card shows banked limit resets from Anthropic's `cedar_ember`
|
|
139
|
+
program, in the same closed disclosure Codex uses. It lists one row per grant,
|
|
140
|
+
not one per credit, and the summary counts remaining resets by summing
|
|
141
|
+
`resetsLeft` over grants that are neither expired nor paused. Each row states
|
|
142
|
+
whether that grant is available, not yet usable, paused, exhausted, or expired,
|
|
143
|
+
with its remaining count and when it lapses. That time is the grant's expiry: it
|
|
144
|
+
is not a window reset and does not move the elapsed-time cursor.
|
|
148
145
|
|
|
149
146
|
This is **display only**. `claimable` is shown as data on a text row, and the
|
|
150
147
|
page has no control that spends a Claude reset, because the response shape is
|
|
151
148
|
not an Anthropic contract. An ineligible account, a grant-less block, or a
|
|
152
|
-
rejected optional query leaves ordinary session and weekly windows untouched
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
rejected optional query leaves ordinary session and weekly windows untouched and
|
|
150
|
+
shows no list; a failed lookup shows a fixed sentence rather than the provider's
|
|
151
|
+
text. No live account was used to verify what Anthropic returns. See
|
|
155
152
|
[the evidence and limits](docs/claude-banked-resets.md) and the
|
|
156
153
|
[display decision](.agents/notes/implemented/provider/2026-10-08-claude-banked-reset-display.md).
|
|
157
154
|
|
|
158
155
|
## Install
|
|
159
156
|
|
|
160
|
-
Current source is tested with DSH `0.1.7-rc.2`, `0.2.0-rc.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
[docs/
|
|
168
|
-
|
|
169
|
-
layers. With `dsh` available, install the plugin into the web profile from
|
|
170
|
-
npm:
|
|
157
|
+
Current source is tested with DSH `0.1.7-rc.2`, `0.2.0-rc.2`, and `0.2.1-rc.2`.
|
|
158
|
+
The package's peers admit `>=0.1.7-rc.2 <0.3.0-0`: untested versions inside that
|
|
159
|
+
range install but are unsupported, and versions outside it need an explicit
|
|
160
|
+
`dsh plugin allow-version` exemption. `dsh plugin add` checks those ranges with
|
|
161
|
+
`includePrerelease` semantics, so the admitted set covers every host build from
|
|
162
|
+
`0.1.7-rc.2` through the whole `0.2.x` line, prereleases included, and blocks
|
|
163
|
+
the `0.3.0` line. See [docs/compatibility.md](docs/compatibility.md) for the
|
|
164
|
+
support window and [docs/testing.md](docs/testing.md) for the test layers. With
|
|
165
|
+
`dsh` available, install the plugin into the web profile from npm:
|
|
171
166
|
|
|
172
167
|
```sh
|
|
173
168
|
dsh plugin --profile web add dsh-subscriptions
|
|
@@ -180,47 +175,47 @@ dsh plugin --profile web add github:goodboys-ai/dsh-subscriptions
|
|
|
180
175
|
```
|
|
181
176
|
|
|
182
177
|
Git installs run this package's `prepare` script to build the host and browser
|
|
183
|
-
bundles. If a Git install stops with `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
178
|
+
bundles. If a Git install stops with `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED` (DSH
|
|
179
|
+
`0.1.7-rc.2` does this by default), add this package to the web profile's
|
|
180
|
+
`pnpm-workspace.yaml` (`~/.dsh/profiles/web/` unless `DSH_HOME` is set) and
|
|
181
|
+
repeat the command:
|
|
187
182
|
|
|
188
183
|
```yaml
|
|
189
184
|
allowBuilds:
|
|
190
185
|
'dsh-subscriptions': true
|
|
191
186
|
```
|
|
192
187
|
|
|
193
|
-
(If a previous Git install used the old scoped name, replace its
|
|
194
|
-
|
|
188
|
+
(If a previous Git install used the old scoped name, replace its `allowBuilds`
|
|
189
|
+
key with the one above.)
|
|
195
190
|
|
|
196
191
|
Restart `dsh web` after installation. Open **Settings → Subscriptions** to
|
|
197
|
-
connect providers, manage accounts and model lists, and inspect available
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
192
|
+
connect providers, manage accounts and model lists, and inspect available quota.
|
|
193
|
+
The session footer quota pill can be shown or hidden there for the current
|
|
194
|
+
browser. OpenCode Go, Kimi Code, and Ollama Cloud cards show usage when their
|
|
195
|
+
API keys are configured.
|
|
201
196
|
|
|
202
|
-
To update an installation, run the same `dsh plugin --profile web add` command
|
|
197
|
+
To update an installation, run the same `dsh plugin --profile web add` command
|
|
198
|
+
again and restart `dsh web`.
|
|
203
199
|
|
|
204
|
-
Without a version suffix, the npm command installs the `latest` dist-tag and
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
[release policy](docs/compatibility.md#plugin-versioning).
|
|
200
|
+
Without a version suffix, the npm command installs the `latest` dist-tag and the
|
|
201
|
+
GitHub command installs the current default branch at install time. Pin a
|
|
202
|
+
release by appending `@<version>` to the npm spec or the tag to the GitHub spec
|
|
203
|
+
(`#vX.Y.Z`); see the [release policy](docs/compatibility.md#plugin-versioning).
|
|
209
204
|
|
|
210
205
|
## Verification and limits
|
|
211
206
|
|
|
212
|
-
CI builds, tests, and boots a packed tarball on all supported DSH versions;
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
CI builds, tests, and boots a packed tarball on all supported DSH versions; it
|
|
208
|
+
does not run the GitHub source install's `prepare` step. Offline provider tests
|
|
209
|
+
check recorded API responses, so a passing CI run cannot prove that a provider
|
|
210
|
+
still accepts live sign-in or model requests. See [testing](docs/testing.md) for
|
|
211
|
+
the checks and their limits.
|
|
217
212
|
|
|
218
|
-
- **ChatGPT/Codex, Claude, Grok, GitHub Copilot, and Google Antigravity:**
|
|
219
|
-
|
|
213
|
+
- **ChatGPT/Codex, Claude, Grok, GitHub Copilot, and Google Antigravity:** The
|
|
214
|
+
port includes the tool-message and icon fixes tracked in
|
|
220
215
|
[upstream issue #117](https://github.com/V1ki/dsh-plugin-subscriptions/issues/117).
|
|
221
|
-
A manual check in an isolated `0.1.7-rc.2` web profile found the client
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
A manual check in an isolated `0.1.7-rc.2` web profile found the client bundle
|
|
217
|
+
served and the auth and usage-status RPCs answering. Live sign-in and model
|
|
218
|
+
requests on the supported DSH lines remain to be checked.
|
|
224
219
|
- **Cursor:** Browser sign-in and live model discovery were verified in an
|
|
225
220
|
isolated `0.1.7-rc.2` profile. A successful live model request remains to be
|
|
226
221
|
verified. Its transport comes from
|
|
@@ -230,33 +225,36 @@ that a provider still accepts live sign-in or model requests. See
|
|
|
230
225
|
- **OpenCode Go and Kimi Code:** Live usage responses were verified. Their API
|
|
231
226
|
keys stay on the DSH host; the browser receives configured status and quota
|
|
232
227
|
windows, not the keys.
|
|
233
|
-
- **Ollama Cloud:** Unit and fixture coverage only (chat wire, discovery
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
Cursor uses one connected account and a live model catalog. Its model
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
UI have been retired; an old plugin proxy config file is ignored.
|
|
228
|
+
- **Ollama Cloud:** Unit and fixture coverage only (chat wire, discovery mapping
|
|
229
|
+
and wire-id normalization, the settings store and its RPC endpoints, usage
|
|
230
|
+
parsing, web providers, host E2E fixtures). The card's rendering has no
|
|
231
|
+
browser test. Live chat, listing, usage, and web calls against `ollama.com`
|
|
232
|
+
remain to be verified with a real key.
|
|
233
|
+
|
|
234
|
+
Cursor uses one connected account and a live model catalog. Its model visibility
|
|
235
|
+
selection persists under the DSH home directory, and automatic display follows
|
|
236
|
+
newly discovered models. It ships no fallback model list and does not import the
|
|
237
|
+
local `cursor-agent` credential cache. Individual usage comes from Cursor
|
|
238
|
+
dashboard endpoints; the documented Admin API covers team usage.
|
|
239
|
+
|
|
240
|
+
The plugin follows DSH network settings. Its former proxy configuration and UI
|
|
241
|
+
have been retired; an old plugin proxy config file is ignored.
|
|
248
242
|
|
|
249
243
|
## Claude prompt-cache TTL
|
|
250
244
|
|
|
251
245
|
Set `claudePromptCacheTtl: '5m'` (default) or `'1h'` in the plugin config and
|
|
252
|
-
restart DSH.
|
|
253
|
-
|
|
254
|
-
hour
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
246
|
+
restart DSH. The Claude **Manage** dialog can override this for the Claude
|
|
247
|
+
route: its "Prompt cache lifetime" picker offers Follow config, 5 minutes, or 1
|
|
248
|
+
hour, and a saved choice applies from the next request without a restart. Follow
|
|
249
|
+
config leaves the config value in charge. This affects Claude only; other
|
|
250
|
+
providers keep their own caching. Five minutes omits the wire `ttl` field,
|
|
251
|
+
preserving the existing request. One hour adds `ttl: "1h"` to the tools+system
|
|
252
|
+
prefix and up to three conversation breakpoints. All marks share one TTL:
|
|
253
|
+
Anthropic rejects a one-hour mark after a five-minute mark. Requests classified
|
|
254
|
+
with `purpose` as compaction or session-title keep five minutes. Unclassified
|
|
255
|
+
calls, including subagents and calls from hosts that do not supply `purpose`,
|
|
256
|
+
follow the configured TTL. The TTL setting does not require a newer host
|
|
257
|
+
capability or dependency.
|
|
260
258
|
|
|
261
259
|
Cache reads have the same API price for either TTL. One-hour writes are priced
|
|
262
260
|
at 2× base input instead of 1.25×. They may pay off with reusable prefixes and
|
|
@@ -277,35 +275,58 @@ live-account verification of this fork.
|
|
|
277
275
|
|
|
278
276
|
**Settings → Subscriptions → Usage coloring** offers one browser-local dropdown:
|
|
279
277
|
|
|
280
|
-
- **Standard** (default): yellow when used quota leads elapsed time by at least
|
|
278
|
+
- **Standard** (default): yellow when used quota leads elapsed time by at least
|
|
279
|
+
10 percentage points.
|
|
281
280
|
- **Relaxed**: yellow at a lead of at least 15 points.
|
|
282
281
|
- **Remaining quota only**: no yellow pace warnings.
|
|
283
282
|
|
|
284
|
-
Every preset shows reported usage of 90% or more in red, before considering
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
283
|
+
Every preset shows reported usage of 90% or more in red, before considering
|
|
284
|
+
pace. For example, 40% used after 25% of a window is a 15-point lead, not a
|
|
285
|
+
consumption forecast. Preferences apply to all meters, survive reloads and
|
|
286
|
+
synchronize across tabs of the same origin. They change display only, never
|
|
287
|
+
account routing or quota enforcement.
|
|
288
|
+
|
|
289
|
+
A vertical marker shows elapsed time only for an explicit valid start/end
|
|
290
|
+
interval or a provider-verified fixed duration. A session/weekly label alone
|
|
291
|
+
does not establish a fixed window; rolling or unknown intervals have no marker.
|
|
292
|
+
Claude's recognized five-hour/seven-day buckets and Codex's reported quota
|
|
293
|
+
durations supply fixed-window metadata. Unknown timing falls back to green below
|
|
294
|
+
90%, without a marker or yellow warning.
|
|
295
|
+
|
|
296
|
+
The marker depends on the window's timing alone, not on the reading: it stays at
|
|
297
|
+
0% used, for an invalid percentage, and when a refresh failed or the reading is
|
|
298
|
+
more than five minutes old. Such a reading is not set against the current time,
|
|
299
|
+
so it gets no yellow pace warning and its tooltip omits the ahead/behind
|
|
300
|
+
comparison. It retains the last reported green/red color with an accessible
|
|
301
|
+
stale label; refresh to confirm it. Once the reset time has passed the window
|
|
302
|
+
has no position and the marker disappears. Invalid percentages show an
|
|
303
|
+
unavailable state without a fabricated fill. Tooltips explain remaining quota,
|
|
304
|
+
time progress and reset countdown where available. See the
|
|
305
|
+
[decision record](.agents/notes/implemented/architecture/2026-10-01-usage-pace-colors.md)
|
|
306
|
+
and the
|
|
307
|
+
[cursor note](.agents/notes/implemented/architecture/2026-10-06-usage-cursor-timing-only.md)
|
|
308
|
+
for rationale and verification limits.
|
|
289
309
|
|
|
290
310
|
### MiniMax subscription usage
|
|
291
311
|
|
|
292
|
-
Configure `MINIMAX_API_KEY` for the global service or
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
region's `/v1/token_plan/remains` endpoint and displays finite per-model
|
|
297
|
-
with API-provided start/end times. It does not add model routing or OAuth
|
|
298
|
-
Rows are labelled with the model name, and the plugin shows the windows
|
|
299
|
-
returns for each model. MiniMax documents a five-hour and a weekly
|
|
300
|
-
non-video models and only a weekly one for video. Standard
|
|
301
|
-
on time-based plans report an explicit remaining percentage
|
|
302
|
-
and that percentage is enough for a row. Unlimited,
|
|
303
|
-
unsupported quotas are omitted (a status-3 row also
|
|
304
|
-
does not include); if none remain, the card reports
|
|
305
|
-
inventing a percentage. Explicit remaining percentages
|
|
306
|
-
responses follow the official CLI's remaining-count
|
|
307
|
-
live-account response was used in verification, so
|
|
308
|
-
come from the account or the plan rather than from
|
|
312
|
+
Configure `MINIMAX_API_KEY` for the global service or `MINIMAX_CN_API_KEY` for
|
|
313
|
+
China, using DSH's standard model-key configuration. The plugin reuses those
|
|
314
|
+
credential references; no separate subscription ref is required. Quota reads
|
|
315
|
+
require subscription keys, not `sk-api-*` pay-as-you-go keys. The plugin reads
|
|
316
|
+
the region's `/v1/token_plan/remains` endpoint and displays finite per-model
|
|
317
|
+
quotas with API-provided start/end times. It does not add model routing or OAuth
|
|
318
|
+
login. Rows are labelled with the model name, and the plugin shows the windows
|
|
319
|
+
the API returns for each model. MiniMax documents a five-hour and a weekly
|
|
320
|
+
window for non-video models and only a weekly one for video. Standard
|
|
321
|
+
(non-video) models on time-based plans report an explicit remaining percentage
|
|
322
|
+
beside zero counts, and that percentage is enough for a row. Unlimited,
|
|
323
|
+
boosted-above-100% and unsupported quotas are omitted (a status-3 row also
|
|
324
|
+
covers a model the plan does not include); if none remain, the card reports
|
|
325
|
+
unavailable rather than inventing a percentage. Explicit remaining percentages
|
|
326
|
+
take priority; older responses follow the official CLI's remaining-count
|
|
327
|
+
compatibility convention. No live-account response was used in verification, so
|
|
328
|
+
a missing model may still come from the account or the plan rather than from
|
|
329
|
+
this plugin.
|
|
309
330
|
|
|
310
331
|
## Development
|
|
311
332
|
|
|
@@ -315,16 +336,27 @@ pnpm build
|
|
|
315
336
|
pnpm test
|
|
316
337
|
```
|
|
317
338
|
|
|
318
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for the PR workflow, test boundaries,
|
|
319
|
-
|
|
339
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the PR workflow, test boundaries, and
|
|
340
|
+
isolated DSH checks.
|
|
320
341
|
|
|
321
342
|
The tests and checks (unit and integration tests, the host-export and host
|
|
322
|
-
contract checks, the boot smoke, and the host E2E) are documented in
|
|
323
|
-
support window and release process
|
|
324
|
-
[docs/compatibility.md](docs/compatibility.md).
|
|
325
|
-
|
|
326
|
-
The package is published to npm as `dsh-subscriptions`, starting with the first
|
|
343
|
+
contract checks, the boot smoke, and the host E2E) are documented in
|
|
344
|
+
[docs/testing.md](docs/testing.md); the DSH support window and release process
|
|
345
|
+
in [docs/compatibility.md](docs/compatibility.md).
|
|
346
|
+
|
|
347
|
+
The package is published to npm as `dsh-subscriptions`, starting with the first
|
|
348
|
+
release under the new name (GitHub source installation remains supported). The
|
|
349
|
+
`cordis.patch.yml` bundle entry and browser module ID use the same package name.
|
|
350
|
+
Earlier releases were published as `@goodboys-ai/dsh-subscription-hub`; that
|
|
351
|
+
name is deprecated and points here. If the old scoped package is installed,
|
|
352
|
+
remove it before adding the new one — installing both registers the same
|
|
353
|
+
adapters twice and breaks plugin load.
|
|
327
354
|
|
|
328
355
|
## Origins
|
|
329
356
|
|
|
330
|
-
This project started from
|
|
357
|
+
This project started from
|
|
358
|
+
[V1ki/dsh-plugin-subscriptions](https://github.com/V1ki/dsh-plugin-subscriptions)
|
|
359
|
+
at `090d964` under its MIT license and now includes upstream `0.9.5`
|
|
360
|
+
(`75a8346`). The upstream English and Chinese READMEs are kept in
|
|
361
|
+
[`docs/upstream-README.md`](docs/upstream-README.md) and
|
|
362
|
+
[`docs/upstream-README.zh.md`](docs/upstream-README.zh.md).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
const PRIMARY_SERVICE = 'Claude Code-credentials';
|
|
@@ -8,19 +8,30 @@ function toSession(data) {
|
|
|
8
8
|
// Empty-string tokens (seen from a corrupted Keychain item left by a Claude
|
|
9
9
|
// Code logout) pass the typeof gate but are useless and would poison the
|
|
10
10
|
// auth store — a single such entry fails every provider's status read.
|
|
11
|
-
if (typeof data.accessToken !== 'string' ||
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
if (typeof data.accessToken !== 'string' ||
|
|
12
|
+
data.accessToken.length === 0 ||
|
|
13
|
+
typeof data.refreshToken !== 'string' ||
|
|
14
|
+
data.refreshToken.length === 0 ||
|
|
15
|
+
typeof data.expiresAt !== 'number' ||
|
|
16
|
+
!Number.isFinite(data.expiresAt)) {
|
|
14
17
|
return undefined;
|
|
15
18
|
}
|
|
16
|
-
const scopes = Array.isArray(data.scopes)
|
|
19
|
+
const scopes = Array.isArray(data.scopes)
|
|
20
|
+
? data.scopes.join(' ')
|
|
21
|
+
: typeof data.scopes === 'string'
|
|
22
|
+
? data.scopes
|
|
23
|
+
: DEFAULT_SCOPES;
|
|
17
24
|
return {
|
|
18
25
|
accessToken: data.accessToken,
|
|
19
26
|
refreshToken: data.refreshToken,
|
|
20
27
|
expiresAt: Math.trunc(data.expiresAt),
|
|
21
28
|
scopes,
|
|
22
|
-
...typeof data.emailAddress === 'string'
|
|
23
|
-
|
|
29
|
+
...(typeof data.emailAddress === 'string'
|
|
30
|
+
? { emailAddress: data.emailAddress }
|
|
31
|
+
: {}),
|
|
32
|
+
...(typeof data.subscriptionType === 'string'
|
|
33
|
+
? { subscriptionType: data.subscriptionType }
|
|
34
|
+
: {}),
|
|
24
35
|
};
|
|
25
36
|
}
|
|
26
37
|
function parseBlob(raw) {
|
|
@@ -117,7 +128,16 @@ export function writeBackClaudeCodeCredentials(next, expectedPriorAccessToken) {
|
|
|
117
128
|
return false;
|
|
118
129
|
const account = getKeychainAccountName() ?? PRIMARY_SERVICE;
|
|
119
130
|
try {
|
|
120
|
-
execFileSync('/usr/bin/security', [
|
|
131
|
+
execFileSync('/usr/bin/security', [
|
|
132
|
+
'add-generic-password',
|
|
133
|
+
'-s',
|
|
134
|
+
PRIMARY_SERVICE,
|
|
135
|
+
'-a',
|
|
136
|
+
account,
|
|
137
|
+
'-w',
|
|
138
|
+
updated,
|
|
139
|
+
'-U',
|
|
140
|
+
], {
|
|
121
141
|
timeout: 2000,
|
|
122
142
|
stdio: 'ignore',
|
|
123
143
|
});
|
|
@@ -163,7 +183,9 @@ export function writeBackClaudeCodeCredentials(next, expectedPriorAccessToken) {
|
|
|
163
183
|
*/
|
|
164
184
|
export async function refreshClaudeSynced(session, doRefresh) {
|
|
165
185
|
const fromSource = readClaudeCodeCredentials();
|
|
166
|
-
const base = fromSource !== undefined && fromSource.accessToken !== session.accessToken
|
|
186
|
+
const base = fromSource !== undefined && fromSource.accessToken !== session.accessToken
|
|
187
|
+
? fromSource
|
|
188
|
+
: session;
|
|
167
189
|
if (base.expiresAt > Date.now() + 60_000)
|
|
168
190
|
return base;
|
|
169
191
|
const next = await doRefresh(base);
|