dsh-subscriptions 0.2.2 → 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 +28 -32
- package/lib/auth/rpc.d.ts +10 -24
- package/lib/auth/rpc.js +18 -51
- 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 +61 -43
- package/lib/client/SpeedSelect.js +13 -12
- package/lib/client/SubscriptionUsageBadge.d.ts +1 -1
- package/lib/client/SubscriptionUsageBadge.js +1 -13
- package/lib/client/SubscriptionsSection.d.ts +2 -0
- package/lib/client/SubscriptionsSection.js +10 -4
- package/lib/client/locales.d.ts +12 -32
- package/lib/client/locales.js +14 -34
- package/lib/client/model-filter.d.ts +37 -0
- package/lib/client/model-filter.js +45 -0
- package/lib/client/subscription-card-styles.d.ts +1 -1
- package/lib/client/subscription-card-styles.js +1 -1
- package/lib/client/usage-window-filter.d.ts +7 -0
- package/lib/client/usage-window-filter.js +12 -0
- package/lib/client.js +374 -584
- package/lib/client.js.map +1 -1
- package/lib/index.js +249 -3322
- package/lib/provider-settings.d.ts +5 -0
- package/lib/provider-settings.js +21 -0
- package/lib/providers/ollama-settings.d.ts +1 -1
- package/lib/providers/ollama-settings.js +1 -1
- package/lib/translate/antigravity.js +10 -2
- package/package.json +2 -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
|
|
|
@@ -77,10 +77,17 @@ the composer's tool row: Standard or Fast, per session.
|
|
|
77
77
|

|
|
78
78
|
|
|
79
79
|
**Settings → Subscriptions → provider → Manage** edits account aliases, pool
|
|
80
|
-
participation, model allowlists, and the per-model effort,
|
|
81
|
-
settings. A context value only lowers the window a session
|
|
82
|
-
above what the provider advertises; Codex and Claude
|
|
83
|
-
enlarge the API's capacity.
|
|
80
|
+
participation, model allowlists, and the per-model effort, subagent speed,
|
|
81
|
+
context, and tool settings. A context value only lowers the window a session
|
|
82
|
+
plans against, never above what the provider advertises; Codex and Claude
|
|
83
|
+
support it, and it does not enlarge the API's capacity.
|
|
84
|
+
|
|
85
|
+
For Codex, **Subagent default speed** applies to subsequent subagent requests
|
|
86
|
+
using that model, regardless of the parent model. An explicit Speed choice in
|
|
87
|
+
the subagent session overrides the saved default, and a parent's choice never
|
|
88
|
+
propagates. The default survives restart; session overrides do not. Fast still
|
|
89
|
+
requires current model support, and requests without live subagent metadata use
|
|
90
|
+
Standard.
|
|
84
91
|
|
|
85
92
|

|
|
86
93
|
|
|
@@ -154,15 +161,16 @@ text. No live account was used to verify what Anthropic returns. See
|
|
|
154
161
|
|
|
155
162
|
## Install
|
|
156
163
|
|
|
157
|
-
Current source is tested with DSH `0.1.7-rc.2`, `0.2.0-rc.2`,
|
|
158
|
-
The package's peers admit `>=0.1.7-rc.2 <0.3.0-0`: untested
|
|
159
|
-
range install but are unsupported, and versions outside it
|
|
160
|
-
`dsh plugin allow-version` exemption. `dsh plugin add` checks
|
|
161
|
-
`includePrerelease` semantics, so the admitted set covers
|
|
162
|
-
`0.1.7-rc.2` through the whole `0.2.x` line, prereleases
|
|
163
|
-
the `0.3.0` line. See
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
Current source is tested with DSH `0.1.7-rc.2`, `0.2.0-rc.2`, `0.2.1-rc.2`, and
|
|
165
|
+
`0.2.1-rc.5`. The package's peers admit `>=0.1.7-rc.2 <0.3.0-0`: untested
|
|
166
|
+
versions inside that range install but are unsupported, and versions outside it
|
|
167
|
+
need an explicit `dsh plugin allow-version` exemption. `dsh plugin add` checks
|
|
168
|
+
those ranges with `includePrerelease` semantics, so the admitted set covers
|
|
169
|
+
every host build from `0.1.7-rc.2` through the whole `0.2.x` line, prereleases
|
|
170
|
+
included, and blocks the `0.3.0` line. See
|
|
171
|
+
[docs/compatibility.md](docs/compatibility.md) for the support window and
|
|
172
|
+
[docs/testing.md](docs/testing.md) for the test layers. With `dsh` available,
|
|
173
|
+
install the plugin into the web profile from npm:
|
|
166
174
|
|
|
167
175
|
```sh
|
|
168
176
|
dsh plugin --profile web add dsh-subscriptions
|
|
@@ -216,12 +224,6 @@ the checks and their limits.
|
|
|
216
224
|
A manual check in an isolated `0.1.7-rc.2` web profile found the client bundle
|
|
217
225
|
served and the auth and usage-status RPCs answering. Live sign-in and model
|
|
218
226
|
requests on the supported DSH lines remain to be checked.
|
|
219
|
-
- **Cursor:** Browser sign-in and live model discovery were verified in an
|
|
220
|
-
isolated `0.1.7-rc.2` profile. A successful live model request remains to be
|
|
221
|
-
verified. Its transport comes from
|
|
222
|
-
[orrinzeng/dsh-cursor-subscription](https://github.com/orrinzeng/dsh-cursor-subscription)
|
|
223
|
-
and uses an undocumented Cursor protocol; see the
|
|
224
|
-
[source note](docs/cursor-origin.md).
|
|
225
227
|
- **OpenCode Go and Kimi Code:** Live usage responses were verified. Their API
|
|
226
228
|
keys stay on the DSH host; the browser receives configured status and quota
|
|
227
229
|
windows, not the keys.
|
|
@@ -231,12 +233,6 @@ the checks and their limits.
|
|
|
231
233
|
browser test. Live chat, listing, usage, and web calls against `ollama.com`
|
|
232
234
|
remain to be verified with a real key.
|
|
233
235
|
|
|
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
236
|
The plugin follows DSH network settings. Its former proxy configuration and UI
|
|
241
237
|
have been retired; an old plugin proxy config file is ignored.
|
|
242
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;
|
|
@@ -38,15 +37,15 @@ export interface VideoBytesResult {
|
|
|
38
37
|
export type SpeedTier = 'standard' | 'fast';
|
|
39
38
|
/** `speed` endpoint value: the session's choice plus the visibility list. */
|
|
40
39
|
export interface SpeedState {
|
|
41
|
-
/**
|
|
40
|
+
/** Explicit session speed, or the subagent's model default when supplied. */
|
|
42
41
|
tier: SpeedTier;
|
|
43
42
|
/** Codex model ids whose catalog advertises a fast tier. */
|
|
44
43
|
fastModels: string[];
|
|
45
44
|
}
|
|
46
|
-
/**
|
|
45
|
+
/** Session overrides plus persisted subagent model defaults. */
|
|
47
46
|
export interface SpeedController {
|
|
48
|
-
/**
|
|
49
|
-
speed(sessionId: string): Promise<SpeedState>;
|
|
47
|
+
/** Pass the current Codex model to resolve a subagent's default speed. */
|
|
48
|
+
speed(sessionId: string, model?: string): Promise<SpeedState>;
|
|
50
49
|
/** Set one session's speed tier. */
|
|
51
50
|
setSpeed(sessionId: string, tier: SpeedTier): Promise<void>;
|
|
52
51
|
}
|
|
@@ -65,6 +64,8 @@ export interface AccountStatus {
|
|
|
65
64
|
}
|
|
66
65
|
/** Login state of one provider, as rendered by the Settings page. */
|
|
67
66
|
export interface ProviderStatus {
|
|
67
|
+
/** Saved picker visibility, attached by the status RPC from local preferences. */
|
|
68
|
+
visibleModels?: string[];
|
|
68
69
|
/** Whether a login attempt is currently waiting for its code. */
|
|
69
70
|
busy: boolean;
|
|
70
71
|
/** Logged-in accounts, default first. */
|
|
@@ -110,6 +111,8 @@ export interface ProviderAccountCatalog {
|
|
|
110
111
|
}
|
|
111
112
|
/** Provider and account preference operations behind providerSettings/setProviderSettings. */
|
|
112
113
|
export interface ProviderSettingsController {
|
|
114
|
+
/** Local picker selection, without triggering model discovery. */
|
|
115
|
+
visibleModels?(provider: ProviderId): string[] | undefined;
|
|
113
116
|
get(provider: ProviderId, force: boolean): Promise<unknown>;
|
|
114
117
|
set(provider: ProviderId, settings: unknown): Promise<void>;
|
|
115
118
|
}
|
|
@@ -185,22 +188,6 @@ export interface ExternalUsageRpcController {
|
|
|
185
188
|
status(): Promise<Record<ExternalUsageSource, ExternalUsageStatus>>;
|
|
186
189
|
usage(source: ExternalUsageSource, signal: AbortSignal): Promise<ProviderUsage>;
|
|
187
190
|
}
|
|
188
|
-
/** Cursor account actions; OAuth tokens remain in the host credential service. */
|
|
189
|
-
export interface CursorRpcController {
|
|
190
|
-
status(): Promise<CursorAuthStatus>;
|
|
191
|
-
login(): Promise<{
|
|
192
|
-
authorizeUrl: string;
|
|
193
|
-
}>;
|
|
194
|
-
cancel(): Promise<void>;
|
|
195
|
-
logout(): Promise<void>;
|
|
196
|
-
usage(signal: AbortSignal): Promise<ProviderUsage>;
|
|
197
|
-
models(force: boolean, signal: AbortSignal): Promise<{
|
|
198
|
-
id: string;
|
|
199
|
-
name: string;
|
|
200
|
-
}[]>;
|
|
201
|
-
settings(force: boolean, signal: AbortSignal): Promise<unknown>;
|
|
202
|
-
setSettings(input: unknown): Promise<void>;
|
|
203
|
-
}
|
|
204
191
|
/** One model in the Ollama Cloud picker catalog, with its capability flags. */
|
|
205
192
|
export interface OllamaModelView {
|
|
206
193
|
id: string;
|
|
@@ -276,7 +263,6 @@ export interface OllamaRpcController {
|
|
|
276
263
|
* @param modelDefaults - optional per-model default-effort state backing `modelDefaults`/`setModelDefault`.
|
|
277
264
|
* @param providerSettings - optional OAuth provider/account preferences.
|
|
278
265
|
* @param externalUsage - optional credential-backed quota readers.
|
|
279
|
-
* @param cursor - optional Cursor account and model-visibility actions.
|
|
280
266
|
* @param ollama - optional Ollama Cloud catalog and connection settings.
|
|
281
267
|
*/
|
|
282
|
-
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)
|
|
@@ -309,7 +301,18 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
309
301
|
detail: error instanceof Error ? error.message : String(error),
|
|
310
302
|
})),
|
|
311
303
|
]));
|
|
312
|
-
return ok({
|
|
304
|
+
return ok({
|
|
305
|
+
providers: Object.fromEntries(entries.map(([provider, status]) => {
|
|
306
|
+
const visibleModels = providerSettings?.visibleModels?.(provider);
|
|
307
|
+
return [
|
|
308
|
+
provider,
|
|
309
|
+
{
|
|
310
|
+
...status,
|
|
311
|
+
...(visibleModels === undefined ? {} : { visibleModels }),
|
|
312
|
+
},
|
|
313
|
+
];
|
|
314
|
+
})),
|
|
315
|
+
});
|
|
313
316
|
}
|
|
314
317
|
case 'login': {
|
|
315
318
|
const provider = readProvider(payload);
|
|
@@ -350,43 +353,6 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
350
353
|
}
|
|
351
354
|
return ok(await externalUsage.usage(source, signal));
|
|
352
355
|
}
|
|
353
|
-
case 'cursorStatus':
|
|
354
|
-
if (!cursor)
|
|
355
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
356
|
-
return ok(await cursor.status());
|
|
357
|
-
case 'cursorLogin':
|
|
358
|
-
if (!cursor)
|
|
359
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
360
|
-
return ok(await cursor.login());
|
|
361
|
-
case 'cursorCancel':
|
|
362
|
-
if (!cursor)
|
|
363
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
364
|
-
await cursor.cancel();
|
|
365
|
-
return ok({ ok: true });
|
|
366
|
-
case 'cursorLogout':
|
|
367
|
-
if (!cursor)
|
|
368
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
369
|
-
await cursor.logout();
|
|
370
|
-
return ok({ ok: true });
|
|
371
|
-
case 'cursorUsage':
|
|
372
|
-
if (!cursor)
|
|
373
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
374
|
-
return ok(await cursor.usage(signal));
|
|
375
|
-
case 'cursorModels':
|
|
376
|
-
if (!cursor)
|
|
377
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
378
|
-
return ok(await cursor.models(readForce(payload), signal));
|
|
379
|
-
case 'cursorSettings':
|
|
380
|
-
if (!cursor)
|
|
381
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
382
|
-
return ok(await cursor.settings(readForce(payload), signal));
|
|
383
|
-
case 'cursorSetSettings':
|
|
384
|
-
if (!cursor)
|
|
385
|
-
throw new BadRequest('Cursor account is unavailable');
|
|
386
|
-
if (payload === null || typeof payload !== 'object')
|
|
387
|
-
throw new BadRequest('payload must be an object');
|
|
388
|
-
await cursor.setSettings(payload.settings);
|
|
389
|
-
return ok({ ok: true });
|
|
390
356
|
case 'ollamaSettings':
|
|
391
357
|
if (!ollama)
|
|
392
358
|
throw new BadRequest('Ollama settings are unavailable');
|
|
@@ -433,7 +399,9 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
433
399
|
case 'video':
|
|
434
400
|
return ok(await controller.readVideo(readVideoName(payload), signal));
|
|
435
401
|
case 'speed':
|
|
436
|
-
return ok(await speed.speed(readSessionId(payload)
|
|
402
|
+
return ok(await speed.speed(readSessionId(payload), payload.model === undefined
|
|
403
|
+
? undefined
|
|
404
|
+
: readString(payload, 'model')));
|
|
437
405
|
case 'setSpeed':
|
|
438
406
|
await speed.setSpeed(readSessionId(payload), readSpeedTier(payload));
|
|
439
407
|
return ok({ ok: true });
|
|
@@ -462,10 +430,9 @@ async function dispatch(controller, speed, modelDefaults, endpoint, payload, sig
|
|
|
462
430
|
* @param modelDefaults - optional per-model default-effort state backing `modelDefaults`/`setModelDefault`.
|
|
463
431
|
* @param providerSettings - optional OAuth provider/account preferences.
|
|
464
432
|
* @param externalUsage - optional credential-backed quota readers.
|
|
465
|
-
* @param cursor - optional Cursor account and model-visibility actions.
|
|
466
433
|
* @param ollama - optional Ollama Cloud catalog and connection settings.
|
|
467
434
|
*/
|
|
468
|
-
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) {
|
|
469
436
|
// `connection` is not in this plugin's inject list (headless compositions
|
|
470
437
|
// lack it), so its startup order is unconstrained: defer registration until
|
|
471
438
|
// the service exists instead of probing once at apply time.
|
|
@@ -482,7 +449,7 @@ export function registerAuthRpc(ctx, controller, speed, modelDefaults = undefine
|
|
|
482
449
|
const connection = ctx.get('connection');
|
|
483
450
|
const handler = async (endpoint, payload, signal) => {
|
|
484
451
|
try {
|
|
485
|
-
return await dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage,
|
|
452
|
+
return await dispatch(controller, speed, modelDefaults, endpoint, payload, signal, providerSettings, externalUsage, ollama);
|
|
486
453
|
}
|
|
487
454
|
catch (error) {
|
|
488
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. */
|