dsh-subscriptions 0.2.3 → 0.3.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 +7 -19
- package/lib/auth/rpc.d.ts +2 -20
- package/lib/auth/rpc.js +3 -49
- package/lib/client/ProviderAccountManager.d.ts +1 -1
- package/lib/client/ProviderAccountManager.js +86 -110
- package/lib/client/ProviderModelEditor.d.ts +1 -1
- package/lib/client/ProviderModelEditor.js +2 -6
- package/lib/client/SubscriptionUsageBadge.d.ts +1 -1
- package/lib/client/SubscriptionUsageBadge.js +1 -13
- package/lib/client/SubscriptionsSection.js +1 -2
- package/lib/client/locales.d.ts +0 -32
- package/lib/client/locales.js +0 -32
- package/lib/client/model-filter.js +1 -1
- package/lib/client/subscription-card-styles.d.ts +1 -1
- package/lib/client/subscription-card-styles.js +1 -1
- package/lib/client.js +175 -489
- package/lib/client.js.map +1 -1
- package/lib/index.js +165 -3275
- package/lib/providers/ollama-settings.d.ts +1 -1
- package/lib/providers/ollama-settings.js +1 -1
- package/package.json +1 -7
- package/lib/client/CursorCard.d.ts +0 -9
- package/lib/client/CursorCard.js +0 -151
- package/lib/providers/cursor-adapter.d.ts +0 -50
- package/lib/providers/cursor-adapter.js +0 -304
- package/lib/providers/cursor-auth.d.ts +0 -43
- package/lib/providers/cursor-auth.js +0 -221
- package/lib/providers/cursor-model-settings.d.ts +0 -15
- package/lib/providers/cursor-model-settings.js +0 -60
- package/lib/providers/cursor-usage.d.ts +0 -9
- package/lib/providers/cursor-usage.js +0 -131
- package/vendor/cursor/LICENSE +0 -21
- package/vendor/cursor/index.d.ts +0 -18
- package/vendor/cursor/index.js +0 -3574
- package/vendor/cursor/proto.js +0 -254
package/README.md
CHANGED
|
@@ -10,9 +10,9 @@ reported quota in **Settings → Subscriptions**.
|
|
|
10
10
|
|
|
11
11
|
## What it adds
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
GitHub Copilot, Google Antigravity
|
|
15
|
-
|
|
13
|
+
- **Five subscription model sources:** Connect ChatGPT/Codex, Claude, Grok,
|
|
14
|
+
GitHub Copilot, or Google Antigravity and choose their models in DSH's picker.
|
|
15
|
+
These routes use account sign-in, without provider API keys.
|
|
16
16
|
- **Ollama Cloud key route:** Add the `ollama-cloud` route with an
|
|
17
17
|
`OLLAMA_API_KEY` credential. The route ships no model catalog: configure it on
|
|
18
18
|
the Settings → Subscriptions card, which fetches the cloud list, ticks the
|
|
@@ -46,10 +46,10 @@ reported quota in **Settings → Subscriptions**.
|
|
|
46
46
|
|
|
47
47
|
## Screenshots
|
|
48
48
|
|
|
49
|
-
Captured against DSH 0.2.0-rc.2 in the web UI with a local stub
|
|
50
|
-
provider responses, so each image shows a product state rather
|
|
51
|
-
account. Identities in the images are fabricated, and the quota
|
|
52
|
-
catalogs, and reset countdowns are sample data.
|
|
49
|
+
Captured against DSH 0.2.0-rc.2 and 0.2.1-rc.5 in the web UI with a local stub
|
|
50
|
+
serving frozen provider responses, so each image shows a product state rather
|
|
51
|
+
than a real account. Identities in the images are fabricated, and the quota
|
|
52
|
+
percentages, catalogs, and reset countdowns are sample data.
|
|
53
53
|
|
|
54
54
|
### Subscriptions
|
|
55
55
|
|
|
@@ -224,12 +224,6 @@ the checks and their limits.
|
|
|
224
224
|
A manual check in an isolated `0.1.7-rc.2` web profile found the client bundle
|
|
225
225
|
served and the auth and usage-status RPCs answering. Live sign-in and model
|
|
226
226
|
requests on the supported DSH lines remain to be checked.
|
|
227
|
-
- **Cursor:** Browser sign-in and live model discovery were verified in an
|
|
228
|
-
isolated `0.1.7-rc.2` profile. A successful live model request remains to be
|
|
229
|
-
verified. Its transport comes from
|
|
230
|
-
[orrinzeng/dsh-cursor-subscription](https://github.com/orrinzeng/dsh-cursor-subscription)
|
|
231
|
-
and uses an undocumented Cursor protocol; see the
|
|
232
|
-
[source note](docs/cursor-origin.md).
|
|
233
227
|
- **OpenCode Go and Kimi Code:** Live usage responses were verified. Their API
|
|
234
228
|
keys stay on the DSH host; the browser receives configured status and quota
|
|
235
229
|
windows, not the keys.
|
|
@@ -239,12 +233,6 @@ the checks and their limits.
|
|
|
239
233
|
browser test. Live chat, listing, usage, and web calls against `ollama.com`
|
|
240
234
|
remain to be verified with a real key.
|
|
241
235
|
|
|
242
|
-
Cursor uses one connected account and a live model catalog. Its model visibility
|
|
243
|
-
selection persists under the DSH home directory, and automatic display follows
|
|
244
|
-
newly discovered models. It ships no fallback model list and does not import the
|
|
245
|
-
local `cursor-agent` credential cache. Individual usage comes from Cursor
|
|
246
|
-
dashboard endpoints; the documented Admin API covers team usage.
|
|
247
|
-
|
|
248
236
|
The plugin follows DSH network settings. Its former proxy configuration and UI
|
|
249
237
|
have been retired; an old plugin proxy config file is ignored.
|
|
250
238
|
|
package/lib/auth/rpc.d.ts
CHANGED
|
@@ -12,7 +12,6 @@ import { type ProviderId } from './store.js';
|
|
|
12
12
|
import type { ProviderUsage } from '../providers/common.js';
|
|
13
13
|
import type { CliVersion } from '../providers/npm-cli-version.js';
|
|
14
14
|
import type { ExternalUsageSource, ExternalUsageStatus } from '../providers/external-usage-controller.js';
|
|
15
|
-
import type { CursorAuthStatus } from '../providers/cursor-auth.js';
|
|
16
15
|
/**
|
|
17
16
|
* Endpoint-name prefix under the shared `/api` channel: endpoint `status`
|
|
18
17
|
* is served at `/api/subscriptions-auth.status`. The browser half calls
|
|
@@ -23,7 +22,7 @@ export declare const SUBSCRIPTIONS_AUTH_PREFIX = "subscriptions-auth.";
|
|
|
23
22
|
* Every endpoint {@link dispatch} answers; each gets one exact Fetch route.
|
|
24
23
|
* Kept in one place so the route table and the switch cannot drift apart.
|
|
25
24
|
*/
|
|
26
|
-
export declare const SUBSCRIPTIONS_AUTH_ENDPOINTS: readonly ["providerSettings", "setProviderSettings", "status", "login", "manual", "cancel", "logout", "setDefault", "usage", "externalStatus", "externalUsage", "
|
|
25
|
+
export declare const SUBSCRIPTIONS_AUTH_ENDPOINTS: readonly ["providerSettings", "setProviderSettings", "status", "login", "manual", "cancel", "logout", "setDefault", "usage", "externalStatus", "externalUsage", "ollamaSettings", "ollamaSetSettings", "ollamaModels", "image", "video", "prepareReset", "consumeReset", "speed", "setSpeed", "modelDefaults", "setModelDefault"];
|
|
27
26
|
/** Decoded image bytes returned by the `image` endpoint. */
|
|
28
27
|
export interface ImageBytesResult {
|
|
29
28
|
mediaType: string;
|
|
@@ -189,22 +188,6 @@ export interface ExternalUsageRpcController {
|
|
|
189
188
|
status(): Promise<Record<ExternalUsageSource, ExternalUsageStatus>>;
|
|
190
189
|
usage(source: ExternalUsageSource, signal: AbortSignal): Promise<ProviderUsage>;
|
|
191
190
|
}
|
|
192
|
-
/** Cursor account actions; OAuth tokens remain in the host credential service. */
|
|
193
|
-
export interface CursorRpcController {
|
|
194
|
-
status(): Promise<CursorAuthStatus>;
|
|
195
|
-
login(): Promise<{
|
|
196
|
-
authorizeUrl: string;
|
|
197
|
-
}>;
|
|
198
|
-
cancel(): Promise<void>;
|
|
199
|
-
logout(): Promise<void>;
|
|
200
|
-
usage(signal: AbortSignal): Promise<ProviderUsage>;
|
|
201
|
-
models(force: boolean, signal: AbortSignal): Promise<{
|
|
202
|
-
id: string;
|
|
203
|
-
name: string;
|
|
204
|
-
}[]>;
|
|
205
|
-
settings(force: boolean, signal: AbortSignal): Promise<unknown>;
|
|
206
|
-
setSettings(input: unknown): Promise<void>;
|
|
207
|
-
}
|
|
208
191
|
/** One model in the Ollama Cloud picker catalog, with its capability flags. */
|
|
209
192
|
export interface OllamaModelView {
|
|
210
193
|
id: string;
|
|
@@ -280,7 +263,6 @@ export interface OllamaRpcController {
|
|
|
280
263
|
* @param modelDefaults - optional per-model default-effort state backing `modelDefaults`/`setModelDefault`.
|
|
281
264
|
* @param providerSettings - optional OAuth provider/account preferences.
|
|
282
265
|
* @param externalUsage - optional credential-backed quota readers.
|
|
283
|
-
* @param cursor - optional Cursor account and model-visibility actions.
|
|
284
266
|
* @param ollama - optional Ollama Cloud catalog and connection settings.
|
|
285
267
|
*/
|
|
286
|
-
export declare function registerAuthRpc(ctx: Context, controller: AuthController, speed: SpeedController, modelDefaults?: ModelDefaultsController | undefined, providerSettings?: ProviderSettingsController | undefined, externalUsage?: ExternalUsageRpcController | undefined,
|
|
268
|
+
export declare function registerAuthRpc(ctx: Context, controller: AuthController, speed: SpeedController, modelDefaults?: ModelDefaultsController | undefined, providerSettings?: ProviderSettingsController | undefined, externalUsage?: ExternalUsageRpcController | undefined, ollama?: OllamaRpcController | undefined): void;
|
package/lib/auth/rpc.js
CHANGED
|
@@ -32,14 +32,6 @@ export const SUBSCRIPTIONS_AUTH_ENDPOINTS = [
|
|
|
32
32
|
'usage',
|
|
33
33
|
'externalStatus',
|
|
34
34
|
'externalUsage',
|
|
35
|
-
'cursorStatus',
|
|
36
|
-
'cursorLogin',
|
|
37
|
-
'cursorCancel',
|
|
38
|
-
'cursorLogout',
|
|
39
|
-
'cursorUsage',
|
|
40
|
-
'cursorModels',
|
|
41
|
-
'cursorSettings',
|
|
42
|
-
'cursorSetSettings',
|
|
43
35
|
'ollamaSettings',
|
|
44
36
|
'ollamaSetSettings',
|
|
45
37
|
'ollamaModels',
|
|
@@ -284,7 +276,7 @@ function readSessionId(payload) {
|
|
|
284
276
|
throw new BadRequest('payload must be an object');
|
|
285
277
|
return readString(payload, 'sessionId');
|
|
286
278
|
}
|
|
287
|
-
async function dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage,
|
|
279
|
+
async function dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage, ollama) {
|
|
288
280
|
switch (endpoint) {
|
|
289
281
|
case 'providerSettings':
|
|
290
282
|
if (!providerSettings)
|
|
@@ -361,43 +353,6 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
361
353
|
}
|
|
362
354
|
return ok(await externalUsage.usage(source, signal));
|
|
363
355
|
}
|
|
364
|
-
case 'cursorStatus':
|
|
365
|
-
if (!cursor)
|
|
366
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
367
|
-
return ok(await cursor.status());
|
|
368
|
-
case 'cursorLogin':
|
|
369
|
-
if (!cursor)
|
|
370
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
371
|
-
return ok(await cursor.login());
|
|
372
|
-
case 'cursorCancel':
|
|
373
|
-
if (!cursor)
|
|
374
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
375
|
-
await cursor.cancel();
|
|
376
|
-
return ok({ ok: true });
|
|
377
|
-
case 'cursorLogout':
|
|
378
|
-
if (!cursor)
|
|
379
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
380
|
-
await cursor.logout();
|
|
381
|
-
return ok({ ok: true });
|
|
382
|
-
case 'cursorUsage':
|
|
383
|
-
if (!cursor)
|
|
384
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
385
|
-
return ok(await cursor.usage(signal));
|
|
386
|
-
case 'cursorModels':
|
|
387
|
-
if (!cursor)
|
|
388
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
389
|
-
return ok(await cursor.models(readForce(payload), signal));
|
|
390
|
-
case 'cursorSettings':
|
|
391
|
-
if (!cursor)
|
|
392
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
393
|
-
return ok(await cursor.settings(readForce(payload), signal));
|
|
394
|
-
case 'cursorSetSettings':
|
|
395
|
-
if (!cursor)
|
|
396
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
397
|
-
if (payload === null || typeof payload !== 'object')
|
|
398
|
-
throw new BadRequest('payload must be an object');
|
|
399
|
-
await cursor.setSettings(payload.settings);
|
|
400
|
-
return ok({ ok: true });
|
|
401
356
|
case 'ollamaSettings':
|
|
402
357
|
if (!ollama)
|
|
403
358
|
throw new BadRequest('Ollama settings are unavailable');
|
|
@@ -475,10 +430,9 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
475
430
|
* @param modelDefaults - optional per-model default-effort state backing `modelDefaults`/`setModelDefault`.
|
|
476
431
|
* @param providerSettings - optional OAuth provider/account preferences.
|
|
477
432
|
* @param externalUsage - optional credential-backed quota readers.
|
|
478
|
-
* @param cursor - optional Cursor account and model-visibility actions.
|
|
479
433
|
* @param ollama - optional Ollama Cloud catalog and connection settings.
|
|
480
434
|
*/
|
|
481
|
-
export function registerAuthRpc(ctx, controller, speed, modelDefaults = undefined, providerSettings = undefined, externalUsage = undefined,
|
|
435
|
+
export function registerAuthRpc(ctx, controller, speed, modelDefaults = undefined, providerSettings = undefined, externalUsage = undefined, ollama = undefined) {
|
|
482
436
|
// `connection` is not in this plugin's inject list (headless compositions
|
|
483
437
|
// lack it), so its startup order is unconstrained: defer registration until
|
|
484
438
|
// the service exists instead of probing once at apply time.
|
|
@@ -495,7 +449,7 @@ export function registerAuthRpc(ctx, controller, speed, modelDefaults = undefine
|
|
|
495
449
|
const connection = ctx.get('connection');
|
|
496
450
|
const handler = async (endpoint, payload, signal) => {
|
|
497
451
|
try {
|
|
498
|
-
return await dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage,
|
|
452
|
+
return await dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage, ollama);
|
|
499
453
|
}
|
|
500
454
|
catch (error) {
|
|
501
455
|
return failure(error);
|
|
@@ -2,7 +2,7 @@ import type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client';
|
|
|
2
2
|
import type { SubscriptionProvider } from './SubscriptionsSection.js';
|
|
3
3
|
import type { SubscriptionsKey } from './locales.js';
|
|
4
4
|
interface Props {
|
|
5
|
-
provider: SubscriptionProvider
|
|
5
|
+
provider: SubscriptionProvider;
|
|
6
6
|
name: string;
|
|
7
7
|
rpc: ConnectionHandle['rpc'];
|
|
8
8
|
t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string;
|
|
@@ -47,9 +47,7 @@ export function ProviderAccountManager({ provider, name, rpc, t, onClose, }) {
|
|
|
47
47
|
let current = true;
|
|
48
48
|
setLoading(true);
|
|
49
49
|
setError('');
|
|
50
|
-
void callSubscriptionsAuth(rpc, provider
|
|
51
|
-
? 'cursorSettings'
|
|
52
|
-
: 'providerSettings', { provider })
|
|
50
|
+
void callSubscriptionsAuth(rpc, 'providerSettings', { provider })
|
|
53
51
|
.then((data) => {
|
|
54
52
|
if (current) {
|
|
55
53
|
setCatalog(data);
|
|
@@ -94,43 +92,32 @@ export function ProviderAccountManager({ provider, name, rpc, t, onClose, }) {
|
|
|
94
92
|
setSaveError('');
|
|
95
93
|
let savedEfforts = 0;
|
|
96
94
|
try {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
95
|
+
for (const { model, effort } of models.efforts) {
|
|
96
|
+
await callSubscriptionsAuth(rpc, 'setModelDefault', {
|
|
97
|
+
provider,
|
|
98
|
+
model,
|
|
99
|
+
...(effort ? { effort } : {}),
|
|
100
|
+
});
|
|
101
|
+
savedEfforts++;
|
|
102
|
+
if (!alive.current)
|
|
103
|
+
return;
|
|
108
104
|
}
|
|
109
105
|
// Re-read before writing: another client may have saved since this
|
|
110
106
|
// dialog loaded, and a stale snapshot must never be written back.
|
|
111
|
-
const latest = await callSubscriptionsAuth(rpc, provider
|
|
112
|
-
? 'cursorSettings'
|
|
113
|
-
: 'providerSettings', { provider });
|
|
107
|
+
const latest = await callSubscriptionsAuth(rpc, 'providerSettings', { provider });
|
|
114
108
|
if (!alive.current)
|
|
115
109
|
return;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
// from the freshly re-read settings.
|
|
128
|
-
const withTtl = mergePromptCacheTtl(base, ttlDirty ? ttlDraft : latest.settings.promptCacheTtl);
|
|
129
|
-
await callSubscriptionsAuth(rpc, 'setProviderSettings', {
|
|
130
|
-
provider,
|
|
131
|
-
settings: mergeAccountChanges(withTtl, changes),
|
|
132
|
-
});
|
|
133
|
-
}
|
|
110
|
+
const base = models.settings === undefined
|
|
111
|
+
? latest.settings
|
|
112
|
+
: mergeLatestAccounts(models.settings, latest.settings);
|
|
113
|
+
// The editor's draft carries the TTL it loaded, so the dialog always
|
|
114
|
+
// replaces it: the picker's choice when touched, otherwise the value
|
|
115
|
+
// from the freshly re-read settings.
|
|
116
|
+
const withTtl = mergePromptCacheTtl(base, ttlDirty ? ttlDraft : latest.settings.promptCacheTtl);
|
|
117
|
+
await callSubscriptionsAuth(rpc, 'setProviderSettings', {
|
|
118
|
+
provider,
|
|
119
|
+
settings: mergeAccountChanges(withTtl, changes),
|
|
120
|
+
});
|
|
134
121
|
if (alive.current)
|
|
135
122
|
onClose();
|
|
136
123
|
}
|
|
@@ -155,81 +142,70 @@ export function ProviderAccountManager({ provider, name, rpc, t, onClose, }) {
|
|
|
155
142
|
maxWidth: 'calc(100vw - 32px)',
|
|
156
143
|
maxHeight: 'calc(100dvh - 32px)',
|
|
157
144
|
overflow: 'auto',
|
|
158
|
-
}, children: [_jsx("style", { children: providerSettingsCss }), _jsxs("div", { style: { ...stack, padding: 20 }, children: [_jsxs("header", { style: { ...actions, justifyContent: 'space-between' }, children: [_jsx("h2", { id: title, style: { margin: 0 }, children: t('accountsTitle', { provider: name }) }), _jsx("button", { type: "button", autoFocus: true, disabled: saving, onClick: onClose, children: t('imageClose') })] }), _jsx("p", { id: description, className: "dsh-subscription-hint", children: t(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
next.add(model.id);
|
|
223
|
-
else
|
|
224
|
-
next.delete(model.id);
|
|
225
|
-
edit(account.key, {
|
|
226
|
-
...preferences,
|
|
227
|
-
poolModels: [...next],
|
|
228
|
-
});
|
|
229
|
-
} }), ' ', model.name, model.unavailable &&
|
|
230
|
-
` (${t('modelsUnavailable')})`] }, model.id))), models.length === 0 && (_jsx("p", { className: "dsh-subscription-hint", children: t('accountsNoModels') }))] })] })] })] }, account.key));
|
|
231
|
-
})] })), (provider !== 'cursor-subscription' ||
|
|
232
|
-
(catalog?.accounts.length ?? 0) > 0) && (_jsx(ProviderModelEditor, { ref: editor, provider: provider, rpc: rpc, t: t, disabled: saving, onDirtyChange: setModelsDirty })), provider === 'claude' && catalog && (_jsxs("div", { style: {
|
|
145
|
+
}, children: [_jsx("style", { children: providerSettingsCss }), _jsxs("div", { style: { ...stack, padding: 20 }, children: [_jsxs("header", { style: { ...actions, justifyContent: 'space-between' }, children: [_jsx("h2", { id: title, style: { margin: 0 }, children: t('accountsTitle', { provider: name }) }), _jsx("button", { type: "button", autoFocus: true, disabled: saving, onClick: onClose, children: t('imageClose') })] }), _jsx("p", { id: description, className: "dsh-subscription-hint", children: t('accountsHint') }), error && _jsx("p", { role: "alert", children: error }), loading && (_jsx("p", { role: "status", className: "dsh-subscription-hint", children: t('accountsLoading') })), !loading && !catalog && (_jsx("button", { type: "button", onClick: () => setAttempt((value) => value + 1), children: t('modelDefaultsRetry') })), catalog && (_jsxs("fieldset", { disabled: saving || loading, style: { ...stack, border: 0, margin: 0, padding: 0 }, children: [catalog.accounts.length === 0 && (_jsx("p", { className: "dsh-subscription-hint", children: t('accountsEmpty') })), catalog.accounts.map((account) => {
|
|
146
|
+
const preferences = changes[account.key] ??
|
|
147
|
+
catalog.settings.accounts?.[account.key] ??
|
|
148
|
+
{};
|
|
149
|
+
const selected = accountPoolSelection(preferences, account.models);
|
|
150
|
+
const models = accountModelRows(account, preferences);
|
|
151
|
+
return (_jsxs("fieldset", { style: {
|
|
152
|
+
...stack,
|
|
153
|
+
border,
|
|
154
|
+
borderRadius: 'var(--dsw-radius-lg, 12px)',
|
|
155
|
+
padding: 14,
|
|
156
|
+
margin: 0,
|
|
157
|
+
}, children: [_jsx("legend", { style: {
|
|
158
|
+
padding: '0 6px',
|
|
159
|
+
overflowWrap: 'anywhere',
|
|
160
|
+
maxWidth: '100%',
|
|
161
|
+
}, children: account.label }), account.unavailable && (_jsx("p", { className: "dsh-subscription-hint", children: t('accountsCatalogUnavailable') })), _jsxs("label", { style: { ...stack, gap: 6 }, children: [_jsx("span", { className: "dsh-subscription-label", children: t('accountsAlias') }), _jsx("input", { value: preferences.alias ?? '', placeholder: account.label, onChange: (event) => {
|
|
162
|
+
const next = { ...preferences };
|
|
163
|
+
if (event.target.value.trim())
|
|
164
|
+
next.alias = event.target.value;
|
|
165
|
+
else
|
|
166
|
+
delete next.alias;
|
|
167
|
+
edit(account.key, next);
|
|
168
|
+
} })] }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: preferences.poolEnabled !== false, onChange: (event) => edit(account.key, {
|
|
169
|
+
...preferences,
|
|
170
|
+
poolEnabled: event.target.checked,
|
|
171
|
+
}) }), ' ', t('accountsPoolEnabled')] }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: preferences.independentEntry === true, onChange: (event) => edit(account.key, {
|
|
172
|
+
...preferences,
|
|
173
|
+
independentEntry: event.target.checked,
|
|
174
|
+
}) }), ' ', t('accountsIndependent')] }), _jsx("p", { className: "dsh-subscription-hint", children: t('accountsIndependentHint') }), _jsxs("details", { children: [_jsxs("summary", { style: { cursor: 'pointer', fontSize: 13 }, children: [t('accountsModels'), " \u00B7", ' ', preferences.poolModels === undefined
|
|
175
|
+
? t('accountsModelsAll')
|
|
176
|
+
: t('accountsModelsCount', {
|
|
177
|
+
count: preferences.poolModels.length,
|
|
178
|
+
})] }), _jsxs("div", { style: { ...stack, marginTop: 12 }, children: [_jsx("p", { className: "dsh-subscription-hint", children: t('accountsModelsHint') }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: preferences.poolModels === undefined, onChange: (event) => {
|
|
179
|
+
const next = { ...preferences };
|
|
180
|
+
if (event.target.checked)
|
|
181
|
+
delete next.poolModels;
|
|
182
|
+
else
|
|
183
|
+
next.poolModels = account.models.map((model) => model.id);
|
|
184
|
+
edit(account.key, next);
|
|
185
|
+
} }), ' ', t('accountsModelsAutomatic')] }), _jsxs("div", { style: actions, children: [_jsx("button", { type: "button", onClick: () => edit(account.key, {
|
|
186
|
+
...preferences,
|
|
187
|
+
poolModels: models.map((model) => model.id),
|
|
188
|
+
}), children: t('modelsSelectAll') }), _jsx("button", { type: "button", onClick: () => edit(account.key, {
|
|
189
|
+
...preferences,
|
|
190
|
+
poolModels: [],
|
|
191
|
+
}), children: t('modelsSelectNone') })] }), _jsxs("div", { style: {
|
|
192
|
+
...stack,
|
|
193
|
+
gap: 8,
|
|
194
|
+
maxHeight: 240,
|
|
195
|
+
overflowY: 'auto',
|
|
196
|
+
}, children: [models.map((model) => (_jsxs("label", { style: { overflowWrap: 'anywhere' }, children: [_jsx("input", { type: "checkbox", checked: selected.has(model.id), onChange: (event) => {
|
|
197
|
+
const next = new Set(selected);
|
|
198
|
+
if (event.target.checked)
|
|
199
|
+
next.add(model.id);
|
|
200
|
+
else
|
|
201
|
+
next.delete(model.id);
|
|
202
|
+
edit(account.key, {
|
|
203
|
+
...preferences,
|
|
204
|
+
poolModels: [...next],
|
|
205
|
+
});
|
|
206
|
+
} }), ' ', model.name, model.unavailable &&
|
|
207
|
+
` (${t('modelsUnavailable')})`] }, model.id))), models.length === 0 && (_jsx("p", { className: "dsh-subscription-hint", children: t('accountsNoModels') }))] })] })] })] }, account.key));
|
|
208
|
+
})] })), _jsx(ProviderModelEditor, { ref: editor, provider: provider, rpc: rpc, t: t, disabled: saving, onDirtyChange: setModelsDirty }), provider === 'claude' && catalog && (_jsxs("div", { style: {
|
|
233
209
|
...stack,
|
|
234
210
|
gap: 6,
|
|
235
211
|
borderTop: border,
|
|
@@ -3,7 +3,7 @@ import type { ProviderPreferences } from '../provider-settings.js';
|
|
|
3
3
|
import type { SubscriptionProvider } from './SubscriptionsSection.js';
|
|
4
4
|
import type { SubscriptionsKey } from './locales.js';
|
|
5
5
|
interface Props {
|
|
6
|
-
provider: SubscriptionProvider
|
|
6
|
+
provider: SubscriptionProvider;
|
|
7
7
|
rpc: ConnectionHandle['rpc'];
|
|
8
8
|
t: (key: SubscriptionsKey, params?: Record<string, unknown>) => string;
|
|
9
9
|
/** Freeze the editor while the owning dialog submits. */
|
|
@@ -48,9 +48,7 @@ export const ProviderModelEditor = forwardRef(function ProviderModelEditor({ pro
|
|
|
48
48
|
setBusy(true);
|
|
49
49
|
setError('');
|
|
50
50
|
try {
|
|
51
|
-
const data = await callSubscriptionsAuth(rpc, provider
|
|
52
|
-
? 'cursorSettings'
|
|
53
|
-
: 'providerSettings', { provider, force });
|
|
51
|
+
const data = await callSubscriptionsAuth(rpc, 'providerSettings', { provider, force });
|
|
54
52
|
if (generation.current === request)
|
|
55
53
|
reset(data);
|
|
56
54
|
}
|
|
@@ -124,9 +122,7 @@ export const ProviderModelEditor = forwardRef(function ProviderModelEditor({ pro
|
|
|
124
122
|
});
|
|
125
123
|
const selected = new Set(draft.visibleModels ??
|
|
126
124
|
[...allModels, ...missing].map((model) => model.id));
|
|
127
|
-
return (_jsxs("div", { style: { borderTop: border, marginTop: 12, paddingTop: 12 }, children: [_jsx("h3", { style: { margin: 0 }, children: t('modelsEdit') }), _jsxs("div", { style: { display: 'grid', gap: 12, marginTop: 12 }, children: [_jsx("p", { className: "dsh-subscription-hint", children: t(
|
|
128
|
-
? 'cursorManageHint'
|
|
129
|
-
: 'modelsHint') }), error && _jsx("p", { role: "alert", children: error }), _jsxs("div", { style: actions, children: [_jsx("button", { type: "button", className: "dsh-subscription-quiet", disabled: busy || disabled || dirty, onClick: () => {
|
|
125
|
+
return (_jsxs("div", { style: { borderTop: border, marginTop: 12, paddingTop: 12 }, children: [_jsx("h3", { style: { margin: 0 }, children: t('modelsEdit') }), _jsxs("div", { style: { display: 'grid', gap: 12, marginTop: 12 }, children: [_jsx("p", { className: "dsh-subscription-hint", children: t('modelsHint') }), error && _jsx("p", { role: "alert", children: error }), _jsxs("div", { style: actions, children: [_jsx("button", { type: "button", className: "dsh-subscription-quiet", disabled: busy || disabled || dirty, onClick: () => {
|
|
130
126
|
void load(true);
|
|
131
127
|
}, children: t('usageRefresh') }), busy && _jsx("span", { role: "status", children: t('modelDefaultsLoading') })] }), !busy && catalog && (_jsxs("fieldset", { disabled: busy || disabled, style: {
|
|
132
128
|
border: 0,
|
|
@@ -48,7 +48,7 @@ export interface ProviderUsageDisplay {
|
|
|
48
48
|
/** The account the collapsed pill reads: the default one, else the first listed. */
|
|
49
49
|
export declare function pillAccountOf(d: ProviderUsageDisplay): AccountUsageDisplay;
|
|
50
50
|
/** Brand display names (short form for the compact badge). */
|
|
51
|
-
export type BadgeProvider = SubscriptionProvider | '
|
|
51
|
+
export type BadgeProvider = SubscriptionProvider | 'opencode-go' | 'kimi-coding' | 'minimax' | 'minimax-cn' | 'ollama-cloud';
|
|
52
52
|
export interface UsageRosterEntry {
|
|
53
53
|
provider: BadgeProvider;
|
|
54
54
|
account: AccountStatus;
|
|
@@ -60,7 +60,6 @@ const PROVIDER_NAMES = {
|
|
|
60
60
|
grok: 'Grok',
|
|
61
61
|
copilot: 'Copilot',
|
|
62
62
|
antigravity: 'Antigravity',
|
|
63
|
-
'cursor-subscription': 'Cursor',
|
|
64
63
|
'opencode-go': 'OpenCode Go',
|
|
65
64
|
'kimi-coding': 'Kimi Code',
|
|
66
65
|
minimax: 'MiniMax',
|
|
@@ -110,9 +109,8 @@ export function groupUsageDisplays(roster, windowsOf, plans) {
|
|
|
110
109
|
}
|
|
111
110
|
/** Read each account source independently so a failing endpoint cannot hide the others. */
|
|
112
111
|
export async function loadBadgeRoster(rpc) {
|
|
113
|
-
const [subscriptions,
|
|
112
|
+
const [subscriptions, external] = await Promise.allSettled([
|
|
114
113
|
callSubscriptionsAuth(rpc, 'status', {}),
|
|
115
|
-
callSubscriptionsAuth(rpc, 'cursorStatus', {}),
|
|
116
114
|
callSubscriptionsAuth(rpc, 'externalStatus', {}),
|
|
117
115
|
]);
|
|
118
116
|
const roster = [];
|
|
@@ -130,14 +128,6 @@ export async function loadBadgeRoster(rpc) {
|
|
|
130
128
|
roster.push({ provider, account });
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
|
-
if (cursor.status === 'fulfilled') {
|
|
134
|
-
refreshed.add('cursor-subscription');
|
|
135
|
-
if (cursor.value.authenticated)
|
|
136
|
-
roster.push({
|
|
137
|
-
provider: 'cursor-subscription',
|
|
138
|
-
account: { key: 'cursor', isDefault: true },
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
131
|
if (external.status === 'fulfilled') {
|
|
142
132
|
for (const [source, provider] of [
|
|
143
133
|
['opencode-go', 'opencode-go'],
|
|
@@ -157,8 +147,6 @@ export async function loadBadgeRoster(rpc) {
|
|
|
157
147
|
return { roster, refreshed };
|
|
158
148
|
}
|
|
159
149
|
export async function usageOf(rpc, { provider, account }) {
|
|
160
|
-
if (provider === 'cursor-subscription')
|
|
161
|
-
return callSubscriptionsAuth(rpc, 'cursorUsage', {});
|
|
162
150
|
if (provider === 'opencode-go' ||
|
|
163
151
|
provider === 'kimi-coding' ||
|
|
164
152
|
provider === 'minimax' ||
|
|
@@ -19,7 +19,6 @@ import { visibleUsageWindows } from './usage-window-filter.js';
|
|
|
19
19
|
import { ProviderAccountManager } from './ProviderAccountManager.js';
|
|
20
20
|
import { providerSettingsCss } from './provider-settings-styles.js';
|
|
21
21
|
import { ExternalUsageCards } from './ExternalUsageCards.js';
|
|
22
|
-
import { CursorCard } from './CursorCard.js';
|
|
23
22
|
import { OllamaCard } from './OllamaCard.js';
|
|
24
23
|
import { UsageMeter } from './UsageMeter.js';
|
|
25
24
|
import { ResetCreditsDisclosure, ResetCreditsErrorLine, showsResetCredits, } from './reset-credits-view.js';
|
|
@@ -720,7 +719,7 @@ export function SubscriptionsSection(props) {
|
|
|
720
719
|
})) }), _jsx("button", { type: "button", onClick: () => {
|
|
721
720
|
void submitManual(id);
|
|
722
721
|
}, children: t('submit') })] })] }))] }, id));
|
|
723
|
-
}), _jsx(
|
|
722
|
+
}), _jsx(OllamaCard, { rpc: rpc, t: t }), _jsx(ExternalUsageCards, { rpc: rpc, t: t }), managedProvider && (_jsx(ProviderAccountManager, { provider: managedProvider.id, name: managedProvider.name, rpc: rpc, t: t, onClose: () => {
|
|
724
723
|
setManagedProvider(undefined);
|
|
725
724
|
void refresh();
|
|
726
725
|
} })), _jsx("style", { children: '.subscriptions-reset-dialog::backdrop { background: var(--dsw-alias-bg-mask-1, #0006); backdrop-filter: var(--dsw-mask-blur, none); }' }), _jsx("dialog", { ref: resetDialogRef, className: "subscriptions-reset-dialog", "aria-labelledby": "subscriptions-reset-title", onCancel: () => setResetConfirmation(undefined), onClose: () => setResetConfirmation(undefined), style: {
|
package/lib/client/locales.d.ts
CHANGED
|
@@ -148,22 +148,6 @@ export declare const en: {
|
|
|
148
148
|
externalUsageApiKey: string;
|
|
149
149
|
externalUsageConfigure: string;
|
|
150
150
|
externalUsageUnavailable: string;
|
|
151
|
-
cursorTitle: string;
|
|
152
|
-
cursorOpenLogin: string;
|
|
153
|
-
cursorWaiting: string;
|
|
154
|
-
cursorConnected: string;
|
|
155
|
-
cursorManageTitle: string;
|
|
156
|
-
cursorManageSignIn: string;
|
|
157
|
-
cursorAccountsHint: string;
|
|
158
|
-
cursorManageHint: string;
|
|
159
|
-
cursorFilterModels: string;
|
|
160
|
-
cursorModelsLoading: string;
|
|
161
|
-
cursorModelsError: string;
|
|
162
|
-
cursorModelsCount: string;
|
|
163
|
-
cursorIncluded: string;
|
|
164
|
-
cursorModels: string;
|
|
165
|
-
cursorOtherModels: string;
|
|
166
|
-
cursorIncludedRequests: string;
|
|
167
151
|
modelDefaultsTitle: string;
|
|
168
152
|
modelDefaultsHint: string;
|
|
169
153
|
modelDefaultsFollowProvider: string;
|
|
@@ -394,22 +378,6 @@ export declare const zh: {
|
|
|
394
378
|
externalUsageApiKey: string;
|
|
395
379
|
externalUsageConfigure: string;
|
|
396
380
|
externalUsageUnavailable: string;
|
|
397
|
-
cursorTitle: string;
|
|
398
|
-
cursorOpenLogin: string;
|
|
399
|
-
cursorWaiting: string;
|
|
400
|
-
cursorConnected: string;
|
|
401
|
-
cursorManageTitle: string;
|
|
402
|
-
cursorManageSignIn: string;
|
|
403
|
-
cursorAccountsHint: string;
|
|
404
|
-
cursorManageHint: string;
|
|
405
|
-
cursorFilterModels: string;
|
|
406
|
-
cursorModelsLoading: string;
|
|
407
|
-
cursorModelsError: string;
|
|
408
|
-
cursorModelsCount: string;
|
|
409
|
-
cursorIncluded: string;
|
|
410
|
-
cursorModels: string;
|
|
411
|
-
cursorOtherModels: string;
|
|
412
|
-
cursorIncludedRequests: string;
|
|
413
381
|
modelDefaultsTitle: string;
|
|
414
382
|
modelDefaultsHint: string;
|
|
415
383
|
modelDefaultsFollowProvider: string;
|