@mars-sea/dsh-commandcode-provider 0.11.14 → 0.11.17
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/CHANGELOG.md +38 -0
- package/README.md +8 -26
- package/README.zh-CN.md +8 -26
- package/lib/client.js +355 -659
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +293 -469
- package/lib/index.js +755 -1669
- package/lib/index.js.map +1 -1
- package/package.json +37 -39
package/lib/client.js
CHANGED
|
@@ -40,16 +40,12 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
/**
|
|
41
41
|
* Backoff before re-reading a directory whose FIRST read failed, in millis.
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* a live Host to fire, and the namespace only re-mounts on a page reload. So a
|
|
50
|
-
* failure with NOTHING held retries on this bounded ladder; a failure with a
|
|
51
|
-
* held view keeps it (no retry — the page is already showing the last good
|
|
52
|
-
* document, and `tests/settings-scope.test.ts` pins that).
|
|
43
|
+
* Only a failure with NOTHING held retries. With no view the scope keeps its
|
|
44
|
+
* initial `{ status: 'loading', writable: false }` snapshot and the settings
|
|
45
|
+
* page renders fully disabled, while the forwarded invalidation signals need a
|
|
46
|
+
* live Host to fire and the namespace only re-mounts on a reload. A failure
|
|
47
|
+
* with a held view retries nothing — the page already shows the last good
|
|
48
|
+
* document (`tests/settings-scope.test.ts` pins both).
|
|
53
49
|
*/
|
|
54
50
|
const SETTINGS_DESCRIBE_RETRY_MS = [
|
|
55
51
|
1e3,
|
|
@@ -95,10 +91,6 @@ window.__ModuleLoader__.load({
|
|
|
95
91
|
retryHandle;
|
|
96
92
|
retries = 0;
|
|
97
93
|
disposed = false;
|
|
98
|
-
/**
|
|
99
|
-
* @param resolveRemote - Reads the inject-captured `remote.settings` namespace.
|
|
100
|
-
* @param timer - Retry timer seam (see {@link SETTINGS_DESCRIBE_RETRY_MS}).
|
|
101
|
-
*/
|
|
102
94
|
constructor(resolveRemote, timer = REAL_SETTINGS_TIMER) {
|
|
103
95
|
this.resolveRemote = resolveRemote;
|
|
104
96
|
this.timer = timer;
|
|
@@ -229,9 +221,8 @@ window.__ModuleLoader__.load({
|
|
|
229
221
|
};
|
|
230
222
|
/**
|
|
231
223
|
* One namespace's derived scope over the shared mirror, plus its serialized
|
|
232
|
-
* Host writes
|
|
233
|
-
* (`getSnapshot` / `subscribe` / `set` / `unset`)
|
|
234
|
-
* needs no changes for either generation.
|
|
224
|
+
* Host writes — the face `CommandCodeSettingsController` consumes
|
|
225
|
+
* (`getSnapshot` / `subscribe` / `set` / `unset`).
|
|
235
226
|
*/
|
|
236
227
|
var RemoteSettingsScope = class {
|
|
237
228
|
resolveRemote;
|
|
@@ -392,22 +383,17 @@ window.__ModuleLoader__.load({
|
|
|
392
383
|
*
|
|
393
384
|
* Subscribes the two signals that can move the Host view — the forwarded
|
|
394
385
|
* `settings/document-updated` invalidation and (when the client exposes it)
|
|
395
|
-
* `connection/reset` — kicks the first describe read, and derives the
|
|
396
|
-
*
|
|
386
|
+
* `connection/reset` — kicks the first describe read, and derives the namespace
|
|
387
|
+
* row on every mirror change.
|
|
397
388
|
*
|
|
398
|
-
* `resolveRemote`
|
|
399
|
-
* {@link SettingsRemoteResolver})
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* into a served one; a profile that never mounts the namespace leaves the page
|
|
405
|
-
* in its degraded (`unavailable`, read-only) state instead of throwing.
|
|
389
|
+
* `resolveRemote` must be the INJECT-CAPTURED namespace (see
|
|
390
|
+
* {@link SettingsRemoteResolver}), and the caller that owns that inject calls
|
|
391
|
+
* {@link ManagedSettingsScope.refresh} once the namespace lands — that is what
|
|
392
|
+
* turns the first, namespace-less read into a served one. A profile that never
|
|
393
|
+
* mounts the namespace leaves the page in its degraded (`unavailable`,
|
|
394
|
+
* read-only) state instead of throwing.
|
|
406
395
|
*
|
|
407
|
-
* @param context - The client context slice (only the declared `remote` service is read).
|
|
408
396
|
* @param namespace - Settings namespace (profile entry id) this scope binds.
|
|
409
|
-
* @param resolveRemote - Reads the inject-captured `remote.settings` namespace.
|
|
410
|
-
* @returns The scope plus the refresh/dispose handles the entry wires into its fiber.
|
|
411
397
|
*/
|
|
412
398
|
function createSettingsScope(context, namespace, resolveRemote, timer = REAL_SETTINGS_TIMER) {
|
|
413
399
|
const mirror = new SettingsDescribeMirror(resolveRemote, timer);
|
|
@@ -444,38 +430,22 @@ window.__ModuleLoader__.load({
|
|
|
444
430
|
//#endregion
|
|
445
431
|
//#region src/client/settings.ts
|
|
446
432
|
/**
|
|
447
|
-
* Browser controller for the "Command Code" settings page.
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
* (a `settings.section` entry, id `commandcode`). It exists because the
|
|
451
|
-
* Models page renders an unknown-adapter-family card for the `commandcode`
|
|
452
|
-
* provider and deliberately disables its submit — the API key cannot be
|
|
453
|
-
* configured there. This page owns the connection facts the plugin resolves
|
|
454
|
-
* per request:
|
|
433
|
+
* Browser controller for the "Command Code" settings page (a `settings.section`
|
|
434
|
+
* entry, id `commandcode`). React-free: it only produces the state face
|
|
435
|
+
* `section.tsx` renders, so node tests can drive it.
|
|
455
436
|
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* - API base -> the `llm-commandcode` settings namespace (`apiBase`), same
|
|
461
|
-
* namespace the Models page card addresses.
|
|
462
|
-
* - Timeouts, behavior switches, model visibility -> the same namespace,
|
|
463
|
-
* staged and written on save.
|
|
464
|
-
* - Accounts -> `accounts`, `activeAccount`, `modelAccountRules` and the
|
|
465
|
-
* per-account credentials, committed immediately.
|
|
466
|
-
*
|
|
467
|
-
* The controller mirrors the plugin-card pattern from the harness's own
|
|
468
|
-
* settings UI: it binds the `llm-commandcode` namespace through a
|
|
469
|
-
* `SettingsScope` — this plugin's own binding of `remote.settings` (see
|
|
470
|
-
* `./settings-scope.ts`; the harness's `settingsScope` wrapper existed only
|
|
471
|
-
* through 0.1.6 and was removed with the 0.1.7 settings rewrite, while the
|
|
472
|
-
* wire underneath spans every supported release) — keeps a staged draft of
|
|
473
|
-
* edits, and writes them on save through `scope.set` / the credentials
|
|
474
|
-
* domain. The Host stays the single fact source; the snapshot is republished
|
|
475
|
-
* after each accepted write.
|
|
437
|
+
* Two write paths with different contracts:
|
|
438
|
+
* - The staged form (connection facts, behavior switches, model visibility,
|
|
439
|
+
* plus the Models-page card's default key draft) lands on `save()`.
|
|
440
|
+
* - Account management commits IMMEDIATELY and serially.
|
|
476
441
|
*
|
|
477
|
-
*
|
|
478
|
-
* the
|
|
442
|
+
* The API key is written through the CREDENTIALS domain under the reference the
|
|
443
|
+
* plugin resolves (`apiKeyEnv`), never through the settings document, so the
|
|
444
|
+
* literal cannot leak into a document; the control only reports whether one is
|
|
445
|
+
* configured. Everything else rides the `llm-commandcode` namespace through this
|
|
446
|
+
* plugin's own `SettingsScope` over `remote.settings` (see `./settings-scope.ts`).
|
|
447
|
+
* The Host stays the single fact source; the snapshot is republished after each
|
|
448
|
+
* accepted write.
|
|
479
449
|
*/
|
|
480
450
|
/** The settings namespace the plugin registers (host half, src/index.ts). */
|
|
481
451
|
const COMMANDCODE_NS = "llm-commandcode";
|
|
@@ -500,8 +470,7 @@ window.__ModuleLoader__.load({
|
|
|
500
470
|
* save, and an optional inclusive `bounds` range rejects out-of-range values
|
|
501
471
|
* with a specific reason (the Host schema would reject them at save time with
|
|
502
472
|
* only a generic failure — catching it here names the problem while typing).
|
|
503
|
-
* Decimals pass
|
|
504
|
-
* millisecond value is harmless even if pointless.
|
|
473
|
+
* Decimals pass, like the Host schema's `z.number()`.
|
|
505
474
|
*/
|
|
506
475
|
function numberField$1(field, bounds) {
|
|
507
476
|
return {
|
|
@@ -530,24 +499,6 @@ window.__ModuleLoader__.load({
|
|
|
530
499
|
}
|
|
531
500
|
};
|
|
532
501
|
}
|
|
533
|
-
/** A field limited to fixed string choices; an empty draft clears it. */
|
|
534
|
-
function choiceField(field, choices) {
|
|
535
|
-
return {
|
|
536
|
-
field,
|
|
537
|
-
format: (value) => typeof value === "string" && choices.includes(value) ? value : "",
|
|
538
|
-
parse: (text) => {
|
|
539
|
-
const trimmed = text.trim();
|
|
540
|
-
if (trimmed === "") return { kind: "clear" };
|
|
541
|
-
return choices.includes(trimmed) ? {
|
|
542
|
-
kind: "set",
|
|
543
|
-
value: trimmed
|
|
544
|
-
} : {
|
|
545
|
-
kind: "invalid",
|
|
546
|
-
reason: "format"
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
502
|
/**
|
|
552
503
|
* A boolean field, staged as the strings `'true'`/`'false'` (an empty draft
|
|
553
504
|
* clears it). The component renders a toggle and only ever stages these two
|
|
@@ -576,14 +527,6 @@ window.__ModuleLoader__.load({
|
|
|
576
527
|
};
|
|
577
528
|
}
|
|
578
529
|
const MAX_TIMEOUT_MS = 2147483647;
|
|
579
|
-
/** The command guard's auto-approve levels, strictest first. */
|
|
580
|
-
const COMMAND_GUARD_LEVEL_CHOICES = [
|
|
581
|
-
"high",
|
|
582
|
-
"medium",
|
|
583
|
-
"low"
|
|
584
|
-
];
|
|
585
|
-
/** The level an unset `commandGuardLevel` reads as on the Host. */
|
|
586
|
-
const COMMAND_GUARD_DEFAULT_LEVEL_CHOICE = "medium";
|
|
587
530
|
/** The fields this page edits inside the `llm-commandcode` namespace. */
|
|
588
531
|
const SECTION_FIELDS = [
|
|
589
532
|
textField("apiBase"),
|
|
@@ -602,8 +545,6 @@ window.__ModuleLoader__.load({
|
|
|
602
545
|
booleanField$1("filterModelsByPlan"),
|
|
603
546
|
booleanField$1("webSearch"),
|
|
604
547
|
booleanField$1("showSidebarQuota"),
|
|
605
|
-
booleanField$1("commandGuard"),
|
|
606
|
-
choiceField("commandGuardLevel", COMMAND_GUARD_LEVEL_CHOICES),
|
|
607
548
|
booleanField$1("zdr")
|
|
608
549
|
];
|
|
609
550
|
/** Whether two model-id lists are equal as sets (order-insensitive). */
|
|
@@ -643,17 +584,12 @@ window.__ModuleLoader__.load({
|
|
|
643
584
|
}
|
|
644
585
|
/**
|
|
645
586
|
* Controller bridging the `llm-commandcode` scope and the credentials domain
|
|
646
|
-
* onto the page.
|
|
587
|
+
* onto the page. See the module header for the two write paths.
|
|
647
588
|
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
* per-account models) commits IMMEDIATELY and serially. A new account had to
|
|
653
|
-
* be saved before browser sign-in could target it (the Host refuses a login
|
|
654
|
-
* for a reference the stored `accounts` list does not name), which turned
|
|
655
|
-
* "add an account" into edit → save → sign in; committing each operation
|
|
656
|
-
* removes that dance and keeps unrelated staged edits out of it.
|
|
589
|
+
* Account ops commit immediately, so a new account can be created, signed into
|
|
590
|
+
* and pinned in one gesture — the Host refuses a login for a reference the
|
|
591
|
+
* stored `accounts` list does not name, so a staged row could not be signed
|
|
592
|
+
* into at all.
|
|
657
593
|
*/
|
|
658
594
|
var CommandCodeSettingsController = class {
|
|
659
595
|
scope;
|
|
@@ -663,13 +599,11 @@ window.__ModuleLoader__.load({
|
|
|
663
599
|
listeners = /* @__PURE__ */ new Set();
|
|
664
600
|
disposers = [];
|
|
665
601
|
disposed = false;
|
|
666
|
-
/** The credential reference the default account resolves. */
|
|
667
602
|
credentialRef = DEFAULT_API_KEY_REF;
|
|
668
603
|
/** Host-reported configured/writable state per credential reference. */
|
|
669
604
|
credentialStates = /* @__PURE__ */ new Map();
|
|
670
605
|
/** Staged visible-model allowlist (undefined = no draft). */
|
|
671
606
|
visibleModelsDraft = void 0;
|
|
672
|
-
/** The catalog the model editors offer (Host-side). */
|
|
673
607
|
catalogModels = [];
|
|
674
608
|
catalogFailed = false;
|
|
675
609
|
saving = false;
|
|
@@ -679,10 +613,6 @@ window.__ModuleLoader__.load({
|
|
|
679
613
|
accountQueue = Promise.resolve();
|
|
680
614
|
accountPending = 0;
|
|
681
615
|
accountFailed = void 0;
|
|
682
|
-
/**
|
|
683
|
-
* @param scope - bound scope for the `llm-commandcode` namespace.
|
|
684
|
-
* @param api - credentials wire face.
|
|
685
|
-
*/
|
|
686
616
|
constructor(scope, api) {
|
|
687
617
|
this.scope = scope;
|
|
688
618
|
this.api = api;
|
|
@@ -748,8 +678,6 @@ window.__ModuleLoader__.load({
|
|
|
748
678
|
filterModelsByPlan: this.field("filterModelsByPlan"),
|
|
749
679
|
webSearch: this.field("webSearch"),
|
|
750
680
|
showSidebarQuota: this.field("showSidebarQuota"),
|
|
751
|
-
commandGuard: this.field("commandGuard"),
|
|
752
|
-
commandGuardLevel: this.field("commandGuardLevel"),
|
|
753
681
|
zdr: this.field("zdr"),
|
|
754
682
|
sidebarQuota: this.sectionValue("showSidebarQuota") === true,
|
|
755
683
|
activeAccount: typeof active === "string" ? active : "",
|
|
@@ -973,9 +901,8 @@ window.__ModuleLoader__.load({
|
|
|
973
901
|
return target === "default" ? this.credentialRef : target;
|
|
974
902
|
}
|
|
975
903
|
/**
|
|
976
|
-
* The first free `<credentialRef>_<n>` reference
|
|
977
|
-
*
|
|
978
|
-
* consistent with the default slot.
|
|
904
|
+
* The first free `<credentialRef>_<n>` reference, so a renamed `apiKeyEnv`
|
|
905
|
+
* yields `MY_KEY_2`-style refs consistent with the default slot.
|
|
979
906
|
*/
|
|
980
907
|
nextAccountRef() {
|
|
981
908
|
const used = /* @__PURE__ */ new Set([this.credentialRef, ...this.storedExtras().map((extra) => extra.ref)]);
|
|
@@ -1133,10 +1060,10 @@ window.__ModuleLoader__.load({
|
|
|
1133
1060
|
if (changed) this.publish();
|
|
1134
1061
|
}
|
|
1135
1062
|
/**
|
|
1136
|
-
* Fetch the model catalog
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1063
|
+
* Fetch the model catalog through the Host Remote. Runs once at construction;
|
|
1064
|
+
* call again (e.g. from the client entry once the Remote mount lands) to
|
|
1065
|
+
* (re)try — a later success clears a prior failure flag, so the editors
|
|
1066
|
+
* recover without a page reload.
|
|
1140
1067
|
*/
|
|
1141
1068
|
refreshCatalog() {
|
|
1142
1069
|
const models = this.api.models;
|
|
@@ -1355,11 +1282,9 @@ window.__ModuleLoader__.load({
|
|
|
1355
1282
|
return String(value);
|
|
1356
1283
|
}
|
|
1357
1284
|
/**
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1360
|
-
* `
|
|
1361
|
-
* The `%` suffix is appended by the caller (the card and the dashboard line
|
|
1362
|
-
* both compose it).
|
|
1285
|
+
* Success-rate percentage (already in percent units, e.g. 99.96): at most two
|
|
1286
|
+
* decimals, trailing zeros trimmed — `100` stays `100`, not `100.00`, and
|
|
1287
|
+
* `99.965552876334` becomes `99.97`. The `%` suffix is the caller's job.
|
|
1363
1288
|
*/
|
|
1364
1289
|
function formatSuccessRate(value) {
|
|
1365
1290
|
return String(Number(value.toFixed(2)));
|
|
@@ -1402,15 +1327,12 @@ window.__ModuleLoader__.load({
|
|
|
1402
1327
|
};
|
|
1403
1328
|
/**
|
|
1404
1329
|
* Cache over the `commandcode/prices` Remote, with a bounded transient-retry
|
|
1405
|
-
* budget. Public API mirrors
|
|
1406
|
-
* `
|
|
1407
|
-
* restarts the budget when the
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
* poll), and a MANUAL `ensure()` still fetches after that budget is spent. A
|
|
1412
|
-
* PERMANENT failure — the Host serving no such endpoint — is terminal for the
|
|
1413
|
-
* binding and is only cleared by `reload()`.
|
|
1330
|
+
* budget (three retries at 1/2/4 s — bounded, not a poll). Public API mirrors
|
|
1331
|
+
* {@link CommandCodeUsageController}: `state()`, `subscribe` and `ensure()`;
|
|
1332
|
+
* `reload()` additionally drops the cache and restarts the budget when the
|
|
1333
|
+
* Host namespace rebinds. A MANUAL `ensure()` still fetches after the budget
|
|
1334
|
+
* is spent, and a PERMANENT failure — the Host serving no such endpoint — is
|
|
1335
|
+
* terminal for the binding until `reload()`.
|
|
1414
1336
|
*/
|
|
1415
1337
|
var CommandCodePricesController = class {
|
|
1416
1338
|
remote;
|
|
@@ -1444,12 +1366,9 @@ window.__ModuleLoader__.load({
|
|
|
1444
1366
|
}
|
|
1445
1367
|
/**
|
|
1446
1368
|
* Fetch the table unless it is already loaded, permanent, or in flight — and
|
|
1447
|
-
* unless a bounded retry already owns the next attempt.
|
|
1448
|
-
*
|
|
1449
|
-
*
|
|
1450
|
-
* lands or rebinds, and a manual refresh. Nothing in the composer calls it, so
|
|
1451
|
-
* a mounted readout does not trigger a fetch of its own — it renders whatever
|
|
1452
|
-
* the table's state currently is.
|
|
1369
|
+
* unless a bounded retry already owns the next attempt. Only the client
|
|
1370
|
+
* entry calls this (on rebind and on a manual refresh), so a mounted readout
|
|
1371
|
+
* renders the current state instead of triggering a fetch of its own.
|
|
1453
1372
|
*/
|
|
1454
1373
|
ensure() {
|
|
1455
1374
|
if (this.disposed || this.permanent || this.inFlight || this.current.status === "ready") return;
|
|
@@ -1575,12 +1494,11 @@ window.__ModuleLoader__.load({
|
|
|
1575
1494
|
this.remote = remote;
|
|
1576
1495
|
this.pollMs = pollMs;
|
|
1577
1496
|
}
|
|
1578
|
-
/** Subscribe to state projections.
|
|
1497
|
+
/** Subscribe to state projections. */
|
|
1579
1498
|
subscribe(listener) {
|
|
1580
1499
|
this.listeners.add(listener);
|
|
1581
1500
|
return () => this.listeners.delete(listener);
|
|
1582
1501
|
}
|
|
1583
|
-
/** Build the current panel state face. */
|
|
1584
1502
|
state() {
|
|
1585
1503
|
return {
|
|
1586
1504
|
phase: this.phase,
|
|
@@ -1773,9 +1691,9 @@ window.__ModuleLoader__.load({
|
|
|
1773
1691
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1774
1692
|
}
|
|
1775
1693
|
/**
|
|
1776
|
-
* The per-reason copy for a failed
|
|
1777
|
-
*
|
|
1778
|
-
*
|
|
1694
|
+
* The per-reason copy for a failed attempt. Shared by the settings page's login
|
|
1695
|
+
* panel and the Models-page card's login row — the same reason can surface from
|
|
1696
|
+
* either.
|
|
1779
1697
|
*/
|
|
1780
1698
|
function loginFailureCopy(reason, t) {
|
|
1781
1699
|
if (reason === "denied") return t("loginDenied");
|
|
@@ -1788,8 +1706,8 @@ window.__ModuleLoader__.load({
|
|
|
1788
1706
|
}
|
|
1789
1707
|
/**
|
|
1790
1708
|
* The hint text + class for one login panel state, shared by the settings
|
|
1791
|
-
* page's
|
|
1792
|
-
* can never drift apart. Pure: no timers, no state
|
|
1709
|
+
* page's login panel and the Models-page card's login row so both surfaces
|
|
1710
|
+
* can never drift apart. Pure: no timers, no state.
|
|
1793
1711
|
*/
|
|
1794
1712
|
function loginHint(state, t) {
|
|
1795
1713
|
if (state.phase === "starting" || state.phase === "waiting") return {
|
|
@@ -1830,16 +1748,16 @@ window.__ModuleLoader__.load({
|
|
|
1830
1748
|
/** The wire namespace all Command Code endpoints share. */
|
|
1831
1749
|
const REMOTE_NAMESPACE = "commandcode";
|
|
1832
1750
|
/**
|
|
1833
|
-
* Build the validator helpers one endpoint uses. `prefix` names the
|
|
1834
|
-
*
|
|
1835
|
-
*
|
|
1836
|
-
* bodies.
|
|
1751
|
+
* Build the validator helpers one endpoint uses. `prefix` names the endpoint
|
|
1752
|
+
* in the rejection message (e.g. `commandcode/report result:`), so each wire
|
|
1753
|
+
* file keeps its own diagnostic phrasing while sharing the helper bodies.
|
|
1837
1754
|
*
|
|
1838
1755
|
* The helpers return the reject call directly in the failure branch: since
|
|
1839
1756
|
* `reject` is typed `never`, the ternary's union collapses to the success type
|
|
1840
1757
|
* without relying on TypeScript's control-flow analysis of a never-returning
|
|
1841
1758
|
* call (which only recognizes function declarations, not the destructured
|
|
1842
|
-
* arrow `reject` callers receive from this factory).
|
|
1759
|
+
* arrow `reject` callers receive from this factory). Callers that need the
|
|
1760
|
+
* narrowing in an `if` must therefore assign inside the positive branch.
|
|
1843
1761
|
*/
|
|
1844
1762
|
function makeBoundaryValidator(prefix) {
|
|
1845
1763
|
const reject = (field) => {
|
|
@@ -1867,10 +1785,8 @@ window.__ModuleLoader__.load({
|
|
|
1867
1785
|
}
|
|
1868
1786
|
/**
|
|
1869
1787
|
* Build one strict invocation descriptor. Every Command Code Remote shares the
|
|
1870
|
-
* `commandcode` namespace, the `commandcodeUsage` service, and a strict
|
|
1871
|
-
*
|
|
1872
|
-
* schema differ — so the boilerplate lives here once and each endpoint supplies
|
|
1873
|
-
* only its own facts.
|
|
1788
|
+
* `commandcode` namespace, the `commandcodeUsage` service, and a strict result
|
|
1789
|
+
* — only the endpoint, method, result type symbol, and schema differ.
|
|
1874
1790
|
*/
|
|
1875
1791
|
function makeRemoteDescriptor(endpoint, method, typeSymbol, schema) {
|
|
1876
1792
|
return {
|
|
@@ -1894,7 +1810,6 @@ window.__ModuleLoader__.load({
|
|
|
1894
1810
|
* so rejection messages name the offending boundary.
|
|
1895
1811
|
*/
|
|
1896
1812
|
const { reject: reject$1, record: record$1, stringField: stringField$1, numberField, booleanField } = makeBoundaryValidator("commandcode/report result:");
|
|
1897
|
-
/** Validate one window-limit block (`fiveHour` / `weekly`). */
|
|
1898
1813
|
/**
|
|
1899
1814
|
* Parse one quota window, or undefined when the frame carries no such window.
|
|
1900
1815
|
*
|
|
@@ -2174,9 +2089,9 @@ window.__ModuleLoader__.load({
|
|
|
2174
2089
|
/**
|
|
2175
2090
|
* Model-select helpers for the settings page's model editors (browser half).
|
|
2176
2091
|
*
|
|
2177
|
-
* The routing-rule editor and the visible-models filter both pick catalog
|
|
2178
|
-
*
|
|
2179
|
-
*
|
|
2092
|
+
* The routing-rule editor and the visible-models filter both pick catalog models
|
|
2093
|
+
* through the same checkbox multi-select dropdown (`ModelMultiSelect` in
|
|
2094
|
+
* section.tsx). The dropdown's data shaping — search filtering, stale-id
|
|
2180
2095
|
* detection, tier grouping — lives here, React-free, so node tests can drive
|
|
2181
2096
|
* it directly.
|
|
2182
2097
|
*
|
|
@@ -2189,10 +2104,8 @@ window.__ModuleLoader__.load({
|
|
|
2189
2104
|
*/
|
|
2190
2105
|
/**
|
|
2191
2106
|
* Minimum plan tier → dropdown section heading. Mirrors the Host-side
|
|
2192
|
-
* `KNOWN_PLANS`
|
|
2193
|
-
*
|
|
2194
|
-
* Covers every tier key `KNOWN_PLANS` uses today; an unknown tier key falls
|
|
2195
|
-
* back to the raw key rather than vanishing the row.
|
|
2107
|
+
* `KNOWN_PLANS` tiers + `PLAN_LABELS` in src/capabilities.ts; an unknown tier
|
|
2108
|
+
* key falls back to the raw key rather than vanishing the row.
|
|
2196
2109
|
*/
|
|
2197
2110
|
const TIER_HEADINGS = {
|
|
2198
2111
|
go: "Go",
|
|
@@ -2222,14 +2135,11 @@ window.__ModuleLoader__.load({
|
|
|
2222
2135
|
return model.id.toLowerCase().includes(needle) || model.name.toLowerCase().includes(needle);
|
|
2223
2136
|
}
|
|
2224
2137
|
/**
|
|
2225
|
-
* Build the dropdown options: the catalog (already in picker order) plus
|
|
2226
|
-
*
|
|
2227
|
-
*
|
|
2228
|
-
*
|
|
2229
|
-
*
|
|
2230
|
-
* When `query` is non-blank, catalog rows are filtered by
|
|
2231
|
-
* {@link matchesModelQuery}; stale rows are kept only while they match too,
|
|
2232
|
-
* so a search for a live model does not surface unrelated stale ids.
|
|
2138
|
+
* Build the dropdown options: the catalog (already in picker order) plus any
|
|
2139
|
+
* selected ids the catalog no longer carries, flagged stale so a saved
|
|
2140
|
+
* selection never silently loses an entry. Stale rows survive a non-blank
|
|
2141
|
+
* {@link matchesModelQuery} search only while they match too, so a search for
|
|
2142
|
+
* a live model does not surface unrelated stale ids.
|
|
2233
2143
|
*/
|
|
2234
2144
|
function buildModelSelectOptions(catalog, selected, query = "") {
|
|
2235
2145
|
const catalogIds = new Set(catalog.map((model) => model.id));
|
|
@@ -2256,12 +2166,10 @@ window.__ModuleLoader__.load({
|
|
|
2256
2166
|
return options;
|
|
2257
2167
|
}
|
|
2258
2168
|
/**
|
|
2259
|
-
* Group dropdown options under plan-tier headings (`tierOf` maps a model id
|
|
2260
|
-
*
|
|
2261
|
-
*
|
|
2262
|
-
*
|
|
2263
|
-
* repeats, so a catalog interleaving two tiers still renders one section
|
|
2264
|
-
* per tier.
|
|
2169
|
+
* Group dropdown options under plan-tier headings (`tierOf` maps a model id to
|
|
2170
|
+
* its heading, or undefined for unmapped models — see {@link tierHeadingFor}).
|
|
2171
|
+
* Live rows keep their relative order and repeats merge, so a catalog
|
|
2172
|
+
* interleaving two tiers still renders one section per tier.
|
|
2265
2173
|
*/
|
|
2266
2174
|
function groupModelSelectOptions(options, tierOf) {
|
|
2267
2175
|
const groups = [];
|
|
@@ -2291,13 +2199,11 @@ window.__ModuleLoader__.load({
|
|
|
2291
2199
|
}
|
|
2292
2200
|
/**
|
|
2293
2201
|
* Whether the catalog is trustworthy enough to call an unlisted selection
|
|
2294
|
-
* "retired". FALSE while the first fetch is
|
|
2295
|
-
*
|
|
2296
|
-
* stale
|
|
2297
|
-
* empties the allowlist.
|
|
2298
|
-
*
|
|
2299
|
-
* model being retired at once, and the explicit "show all" entry covers the
|
|
2300
|
-
* user who really wants to clear the list.
|
|
2202
|
+
* "retired". FALSE while the first fetch is in flight, after a failure, and
|
|
2203
|
+
* for a loaded-but-empty catalog — an empty list makes every selected id look
|
|
2204
|
+
* stale, which would turn the one-click stale cleanup into a button that
|
|
2205
|
+
* silently empties the allowlist. Users who really want it cleared have the
|
|
2206
|
+
* explicit "show all" entry.
|
|
2301
2207
|
*/
|
|
2302
2208
|
function catalogIsReady(readiness) {
|
|
2303
2209
|
return readiness.catalogIds.length > 0 && !readiness.catalogFailed;
|
|
@@ -2313,7 +2219,7 @@ window.__ModuleLoader__.load({
|
|
|
2313
2219
|
}
|
|
2314
2220
|
//#endregion
|
|
2315
2221
|
//#region package.json
|
|
2316
|
-
var version = "0.11.
|
|
2222
|
+
var version = "0.11.17";
|
|
2317
2223
|
var repository = {
|
|
2318
2224
|
"type": "git",
|
|
2319
2225
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -2321,17 +2227,15 @@ window.__ModuleLoader__.load({
|
|
|
2321
2227
|
//#endregion
|
|
2322
2228
|
//#region src/client/version.ts
|
|
2323
2229
|
/**
|
|
2324
|
-
* The plugin's own version, read from package.json at build time.
|
|
2325
|
-
*
|
|
2326
|
-
*
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2329
|
-
* sync. Rendered as a muted footer line on the settings page so a user can
|
|
2330
|
-
* report the exact build they run.
|
|
2230
|
+
* The plugin's own version, read from package.json at build time. The client
|
|
2231
|
+
* bundle inlines the JSON import (rolldown resolves it during the tsdown
|
|
2232
|
+
* build; node tests read it through tsx), so the rendered value always matches
|
|
2233
|
+
* the published package version with no second constant to keep in sync —
|
|
2234
|
+
* rendered as a muted footer line so a user can report the exact build.
|
|
2331
2235
|
*
|
|
2332
2236
|
* @module dsh-commandcode-provider/client/version
|
|
2333
2237
|
*/
|
|
2334
|
-
/** The published package version
|
|
2238
|
+
/** The published package version. */
|
|
2335
2239
|
const PLUGIN_VERSION = version;
|
|
2336
2240
|
/**
|
|
2337
2241
|
* This package's GitHub releases page, derived from the repository field so
|
|
@@ -2351,14 +2255,12 @@ window.__ModuleLoader__.load({
|
|
|
2351
2255
|
*/
|
|
2352
2256
|
const NPM_LATEST_URL = "https://registry.npmjs.org/@mars-sea%2Fdsh-commandcode-provider/latest";
|
|
2353
2257
|
/**
|
|
2354
|
-
* Compare two version strings (`major.minor.patch[-pre]`)
|
|
2355
|
-
*
|
|
2258
|
+
* Compare two version strings (`major.minor.patch[-pre]`): negative when `a`
|
|
2259
|
+
* sorts before `b`, positive when after, zero when equal.
|
|
2356
2260
|
*
|
|
2357
|
-
* Tolerant by design
|
|
2358
|
-
* count as `0`, and semver prerelease rules apply
|
|
2359
|
-
*
|
|
2360
|
-
* shorter identifier list sorts first). Enough for release tags; not a full
|
|
2361
|
-
* semver validator.
|
|
2261
|
+
* Tolerant by design — a leading `v` is stripped, unparsable numeric parts
|
|
2262
|
+
* count as `0`, and semver prerelease rules apply. Enough for release tags,
|
|
2263
|
+
* not a full semver validator.
|
|
2362
2264
|
*/
|
|
2363
2265
|
function compareVersions(a, b) {
|
|
2364
2266
|
const left = splitVersion(a);
|
|
@@ -2494,21 +2396,17 @@ window.__ModuleLoader__.load({
|
|
|
2494
2396
|
* React component for the "Command Code" settings page (browser half).
|
|
2495
2397
|
*
|
|
2496
2398
|
* Renders as a `settings.section` entry — a page at the same settings-nav
|
|
2497
|
-
* level as General / Models / Plugins.
|
|
2498
|
-
* renders this body inside the content column. All copy comes from the
|
|
2399
|
+
* level as General / Models / Plugins. All copy comes from the
|
|
2499
2400
|
* `settings.commandcode` locale namespace; all state comes from the
|
|
2500
2401
|
* `CommandCodeSettingsController` injected by the slot registration.
|
|
2501
2402
|
*
|
|
2502
|
-
* Layout, top to bottom:
|
|
2503
|
-
*
|
|
2504
|
-
*
|
|
2505
|
-
*
|
|
2506
|
-
*
|
|
2507
|
-
*
|
|
2508
|
-
*
|
|
2509
|
-
* Sections 2–5 are flat groups of rows (title and description left, control
|
|
2510
|
-
* right, as on the harness's own settings pages), a staged form written by
|
|
2511
|
-
* the floating save bar.
|
|
2403
|
+
* Layout, top to bottom: Accounts (one card per account, status, quota,
|
|
2404
|
+
* actions and dedicated models — every operation commits immediately), Models
|
|
2405
|
+
* (plan filter + visible-model allowlist), Privacy & security (ZDR),
|
|
2406
|
+
* Integrations & display (web search, sidebar quota card), and a collapsed
|
|
2407
|
+
* Advanced card (API base + network limits). Everything below Accounts is a
|
|
2408
|
+
* flat group of rows (title/description left, control right) inside the staged
|
|
2409
|
+
* form the floating save bar writes.
|
|
2512
2410
|
*
|
|
2513
2411
|
* Styles are injected once by the client entry (see src/client/index.ts) and
|
|
2514
2412
|
* class-prefixed `cc-` to stay local.
|
|
@@ -2645,53 +2543,6 @@ window.__ModuleLoader__.load({
|
|
|
2645
2543
|
})] })
|
|
2646
2544
|
});
|
|
2647
2545
|
}
|
|
2648
|
-
/**
|
|
2649
|
-
* One fixed-choice field rendered as a segmented control. The staged text is
|
|
2650
|
-
* one of `options`' values or `''` (unset → `defaultValue`); picking the
|
|
2651
|
-
* default while unset stages nothing new.
|
|
2652
|
-
*/
|
|
2653
|
-
function SegmentedField({ label, hint, state, disabled, options, defaultValue, className, onEdit, onReset, t }) {
|
|
2654
|
-
const current = state.text === "" ? defaultValue : state.text;
|
|
2655
|
-
const index = Math.max(0, options.findIndex((option) => option.value === current));
|
|
2656
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingRow, {
|
|
2657
|
-
title: label,
|
|
2658
|
-
tag: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OverrideTag, {
|
|
2659
|
-
state,
|
|
2660
|
-
t
|
|
2661
|
-
}),
|
|
2662
|
-
description: hint,
|
|
2663
|
-
...className === void 0 ? {} : { className },
|
|
2664
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldOverride, {
|
|
2665
|
-
label,
|
|
2666
|
-
state,
|
|
2667
|
-
disabled,
|
|
2668
|
-
t,
|
|
2669
|
-
onReset
|
|
2670
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2671
|
-
className: "cc-segmented",
|
|
2672
|
-
role: "radiogroup",
|
|
2673
|
-
"aria-label": label,
|
|
2674
|
-
style: {
|
|
2675
|
-
"--cc-segment-count": options.length,
|
|
2676
|
-
"--cc-segment-index": index
|
|
2677
|
-
},
|
|
2678
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2679
|
-
className: "cc-segmentIndicator",
|
|
2680
|
-
"aria-hidden": "true"
|
|
2681
|
-
}), options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2682
|
-
type: "button",
|
|
2683
|
-
role: "radio",
|
|
2684
|
-
"aria-checked": current === option.value,
|
|
2685
|
-
className: "cc-segment",
|
|
2686
|
-
disabled,
|
|
2687
|
-
onClick: () => {
|
|
2688
|
-
if (current !== option.value) onEdit(option.value);
|
|
2689
|
-
},
|
|
2690
|
-
children: option.label
|
|
2691
|
-
}, option.value))]
|
|
2692
|
-
})] })
|
|
2693
|
-
});
|
|
2694
|
-
}
|
|
2695
2546
|
/** One stat tile in the account card's summary grid. */
|
|
2696
2547
|
function UsageStat({ label, value, sub }) {
|
|
2697
2548
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2760,10 +2611,7 @@ window.__ModuleLoader__.load({
|
|
|
2760
2611
|
]
|
|
2761
2612
|
});
|
|
2762
2613
|
}
|
|
2763
|
-
/**
|
|
2764
|
-
* One pool account's facts (identity, totals, credits, window limits)
|
|
2765
|
-
* rendered inside an account row's details.
|
|
2766
|
-
*/
|
|
2614
|
+
/** One pool account's facts (identity, totals, credits, window limits). */
|
|
2767
2615
|
function AccountReport({ entry, fetchedAt, t, summaryOnly = false, headless = false }) {
|
|
2768
2616
|
const report = entry.report;
|
|
2769
2617
|
const account = report.account;
|
|
@@ -2919,16 +2767,12 @@ window.__ModuleLoader__.load({
|
|
|
2919
2767
|
return t("usageNetworkHint");
|
|
2920
2768
|
}
|
|
2921
2769
|
/**
|
|
2922
|
-
* A checkbox multi-select dropdown for picking catalog models (the
|
|
2923
|
-
*
|
|
2924
|
-
*
|
|
2925
|
-
*
|
|
2926
|
-
*
|
|
2927
|
-
*
|
|
2928
|
-
* under plan-tier headings in picker order. Selected ids the catalog no
|
|
2929
|
-
* longer carries still render — flagged stale — so a saved selection never
|
|
2930
|
-
* silently loses an entry, and the VisibleModelsCard offers a one-click
|
|
2931
|
-
* cleanup.
|
|
2770
|
+
* A checkbox multi-select dropdown for picking catalog models (the routing-rule
|
|
2771
|
+
* rows and the visible-models filter share it). The trigger shows the selection
|
|
2772
|
+
* count; the Menu lists every catalog model, grouping under plan-tier headings
|
|
2773
|
+
* and flagging selected ids the catalog no longer carries as stale, so a saved
|
|
2774
|
+
* selection never silently loses an entry (the VisibleModelsCard offers a
|
|
2775
|
+
* one-click cleanup).
|
|
2932
2776
|
*
|
|
2933
2777
|
* With `deferCommit` the toggles collect in a local draft that is handed to
|
|
2934
2778
|
* `onSelect` once, when the menu closes: the per-account picker writes
|
|
@@ -3118,64 +2962,23 @@ window.__ModuleLoader__.load({
|
|
|
3118
2962
|
});
|
|
3119
2963
|
}
|
|
3120
2964
|
/**
|
|
3121
|
-
* Privacy & security: the
|
|
3122
|
-
*
|
|
3123
|
-
* text to a decision model with no ZDR upstream and can skip an approval the
|
|
3124
|
-
* user would otherwise have seen, so both start off.
|
|
2965
|
+
* Privacy & security: the opt-in that changes where data goes. ZDR restricts
|
|
2966
|
+
* which upstream serves a request, so it starts off.
|
|
3125
2967
|
*/
|
|
3126
2968
|
function PrivacyCard({ state, disabled, t, onEdit, onReset }) {
|
|
3127
|
-
|
|
3128
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsGroup, {
|
|
2969
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsGroup, {
|
|
3129
2970
|
title: t("privacyTitle"),
|
|
3130
|
-
children:
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
}),
|
|
3142
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
3143
|
-
id: "cc-command-guard",
|
|
3144
|
-
label: t("commandGuard"),
|
|
3145
|
-
hint: t("commandGuardHint"),
|
|
3146
|
-
state: state.commandGuard,
|
|
3147
|
-
disabled,
|
|
3148
|
-
defaultChecked: false,
|
|
3149
|
-
onEdit: (text) => onEdit("commandGuard", text),
|
|
3150
|
-
onReset: () => onReset("commandGuard"),
|
|
3151
|
-
t
|
|
3152
|
-
}),
|
|
3153
|
-
showGuardLevel ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SegmentedField, {
|
|
3154
|
-
className: "cc-rowNested",
|
|
3155
|
-
label: t("commandGuardLevel"),
|
|
3156
|
-
hint: t("commandGuardLevelHint"),
|
|
3157
|
-
state: state.commandGuardLevel,
|
|
3158
|
-
disabled,
|
|
3159
|
-
options: [
|
|
3160
|
-
{
|
|
3161
|
-
value: "high",
|
|
3162
|
-
label: t("commandGuardLevelHigh")
|
|
3163
|
-
},
|
|
3164
|
-
{
|
|
3165
|
-
value: "medium",
|
|
3166
|
-
label: t("commandGuardLevelMedium")
|
|
3167
|
-
},
|
|
3168
|
-
{
|
|
3169
|
-
value: "low",
|
|
3170
|
-
label: t("commandGuardLevelLow")
|
|
3171
|
-
}
|
|
3172
|
-
],
|
|
3173
|
-
defaultValue: COMMAND_GUARD_DEFAULT_LEVEL_CHOICE,
|
|
3174
|
-
onEdit: (text) => onEdit("commandGuardLevel", text),
|
|
3175
|
-
onReset: () => onReset("commandGuardLevel"),
|
|
3176
|
-
t
|
|
3177
|
-
}) : null
|
|
3178
|
-
]
|
|
2971
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
2972
|
+
id: "cc-zdr",
|
|
2973
|
+
label: t("zdr"),
|
|
2974
|
+
hint: t("zdrHint"),
|
|
2975
|
+
state: state.zdr,
|
|
2976
|
+
disabled,
|
|
2977
|
+
defaultChecked: false,
|
|
2978
|
+
onEdit: (text) => onEdit("zdr", text),
|
|
2979
|
+
onReset: () => onReset("zdr"),
|
|
2980
|
+
t
|
|
2981
|
+
})
|
|
3179
2982
|
});
|
|
3180
2983
|
}
|
|
3181
2984
|
/** Integrations & display: surfaces outside chat that reuse this provider. */
|
|
@@ -3424,7 +3227,7 @@ window.__ModuleLoader__.load({
|
|
|
3424
3227
|
className: "cc-input",
|
|
3425
3228
|
type: secret && !visible ? "password" : "text",
|
|
3426
3229
|
"aria-label": label,
|
|
3427
|
-
autoComplete: "
|
|
3230
|
+
autoComplete: "new-password",
|
|
3428
3231
|
spellCheck: false,
|
|
3429
3232
|
autoFocus: true,
|
|
3430
3233
|
placeholder,
|
|
@@ -3927,9 +3730,8 @@ window.__ModuleLoader__.load({
|
|
|
3927
3730
|
}
|
|
3928
3731
|
/**
|
|
3929
3732
|
* The unified account card: every account the pool rotates through, one row
|
|
3930
|
-
* each, with its status and quota inline
|
|
3931
|
-
*
|
|
3932
|
-
* facts no longer have to be cross-read across three surfaces.
|
|
3733
|
+
* each, with its status and quota inline — so one account's facts no longer
|
|
3734
|
+
* have to be cross-read across separate surfaces.
|
|
3933
3735
|
*/
|
|
3934
3736
|
function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh }) {
|
|
3935
3737
|
const [adding, setAdding] = (0, react.useState)(false);
|
|
@@ -4278,7 +4080,6 @@ window.__ModuleLoader__.load({
|
|
|
4278
4080
|
}
|
|
4279
4081
|
//#endregion
|
|
4280
4082
|
//#region src/client/login-row.tsx
|
|
4281
|
-
/** The sign-in alternative to pasting a key (settings page + Models card). */
|
|
4282
4083
|
function LoginRow({ state, targetRef, disabled, disabledHint, t, onBegin, onCancel }) {
|
|
4283
4084
|
const { visible: visibleState, busyElsewhere } = loginStateForTarget(state, targetRef);
|
|
4284
4085
|
const busy = visibleState.phase === "starting" || visibleState.phase === "waiting";
|
|
@@ -4329,11 +4130,11 @@ window.__ModuleLoader__.load({
|
|
|
4329
4130
|
* Find the official editor card among the slot outlet's siblings, or null
|
|
4330
4131
|
* while it is closed. The Models page renders the editor as an immediate
|
|
4331
4132
|
* sibling of the outlet wrapper — after it in a provider row (the target of
|
|
4332
|
-
* the row's 编辑 toggle), before it in the first-run setup
|
|
4333
|
-
*
|
|
4334
|
-
*
|
|
4335
|
-
*
|
|
4336
|
-
*
|
|
4133
|
+
* the row's 编辑 toggle), before it in the first-run setup and add-provider
|
|
4134
|
+
* cards, where it is always open. The editor is the only such sibling whose
|
|
4135
|
+
* CSS module class carries the `editor` stem (`<hash>_editor`); the row header
|
|
4136
|
+
* and the add card's provider select never do, so the lookup needs no hash
|
|
4137
|
+
* knowledge.
|
|
4337
4138
|
*/
|
|
4338
4139
|
function adjacentEditorCard(wrapper) {
|
|
4339
4140
|
if (wrapper === null) return null;
|
|
@@ -4358,14 +4159,14 @@ window.__ModuleLoader__.load({
|
|
|
4358
4159
|
apiKeyWritable: snapshot.apiKeyWritable
|
|
4359
4160
|
};
|
|
4360
4161
|
}
|
|
4361
|
-
/**
|
|
4162
|
+
/** Credential-state badge: the solid pill when set, the muted outline when not. */
|
|
4362
4163
|
function StatusBadge({ ok, okLabel, pendingLabel }) {
|
|
4363
4164
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4364
4165
|
className: ok ? "cc-badge" : "cc-badgeMuted",
|
|
4365
4166
|
children: ok ? okLabel : pendingLabel
|
|
4366
4167
|
});
|
|
4367
4168
|
}
|
|
4368
|
-
/**
|
|
4169
|
+
/** The key paste field, with the show/hide toggle over it. */
|
|
4369
4170
|
function CardKeyField({ state, disabled, t, onEdit }) {
|
|
4370
4171
|
const [visible, setVisible] = (0, react.useState)(false);
|
|
4371
4172
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -4392,7 +4193,7 @@ window.__ModuleLoader__.load({
|
|
|
4392
4193
|
id: "cc-card-api-key",
|
|
4393
4194
|
className: "cc-input",
|
|
4394
4195
|
type: visible ? "text" : "password",
|
|
4395
|
-
autoComplete: "
|
|
4196
|
+
autoComplete: "new-password",
|
|
4396
4197
|
spellCheck: false,
|
|
4397
4198
|
value: state.text,
|
|
4398
4199
|
disabled,
|
|
@@ -4407,16 +4208,12 @@ window.__ModuleLoader__.load({
|
|
|
4407
4208
|
}
|
|
4408
4209
|
/**
|
|
4409
4210
|
* The slot component body. Dispatched on every Command Code provider card of
|
|
4410
|
-
* the Models page (saved row, first-run setup posture,
|
|
4411
|
-
* draft).
|
|
4211
|
+
* the Models page (saved row, first-run setup posture, add-provider draft).
|
|
4412
4212
|
*
|
|
4413
|
-
* Closed (the official 编辑 toggle off)
|
|
4414
|
-
*
|
|
4415
|
-
*
|
|
4416
|
-
*
|
|
4417
|
-
* watches for it, hides the shell (it carries only the settings.yaml hint and
|
|
4418
|
-
* a disabled apply for this namespace), and shows the real controls — badges,
|
|
4419
|
-
* API-key field, sign-in, discard/save.
|
|
4213
|
+
* Closed (the official 编辑 toggle off) it renders nothing: the row head the
|
|
4214
|
+
* Models page owns already names the provider and shows the credential dot, so
|
|
4215
|
+
* a page full of providers stays compact. Open, it hides that editor shell and
|
|
4216
|
+
* shows the real controls — badges, API-key field, sign-in, discard/save.
|
|
4420
4217
|
*/
|
|
4421
4218
|
function CommandCodeProviderCard(props) {
|
|
4422
4219
|
const { t } = props;
|
|
@@ -4663,9 +4460,9 @@ window.__ModuleLoader__.load({
|
|
|
4663
4460
|
return Math.abs(value) < .01 ? formatMoneyExact(value) : formatMoney(value);
|
|
4664
4461
|
}
|
|
4665
4462
|
/**
|
|
4666
|
-
* What a figure shows when the endpoint that carries it did not report one.
|
|
4667
|
-
*
|
|
4668
|
-
*
|
|
4463
|
+
* What a figure shows when the endpoint that carries it did not report one. A
|
|
4464
|
+
* dash, never a zero: the panel exists to state what the account has spent, so
|
|
4465
|
+
* "we were not told" has to look different from "nothing".
|
|
4669
4466
|
*/
|
|
4670
4467
|
const UNREPORTED = "—";
|
|
4671
4468
|
/** Local reset time; empty when the endpoint reported none. */
|
|
@@ -4714,18 +4511,17 @@ window.__ModuleLoader__.load({
|
|
|
4714
4511
|
* Build the monthly credit view from the two endpoints that carry it.
|
|
4715
4512
|
*
|
|
4716
4513
|
* The limit is the PLAN's credit total, not the billing endpoint's
|
|
4717
|
-
* `monthlyCredits`
|
|
4718
|
-
* {@link PanelMonthlyView})
|
|
4719
|
-
*
|
|
4514
|
+
* `monthlyCredits` (that field is a remaining balance — see
|
|
4515
|
+
* {@link PanelMonthlyView}), so a plan that publishes no total still shows its
|
|
4516
|
+
* balances, just without a ratio.
|
|
4720
4517
|
*
|
|
4721
4518
|
* The trap this guards: a MISSING balance is not a consumed one. The billing
|
|
4722
4519
|
* endpoint is one of four the report fetches in parallel, so it fails on its
|
|
4723
|
-
* own while the plan still arrives
|
|
4724
|
-
*
|
|
4725
|
-
*
|
|
4726
|
-
*
|
|
4727
|
-
*
|
|
4728
|
-
* too. Every derived figure stays a placeholder until the balance reported.
|
|
4520
|
+
* own while the plan still arrives, and reading the absent balance as 0 turns
|
|
4521
|
+
* that partial failure into `limit - 0 = limit` — a confident "100% used" for
|
|
4522
|
+
* an account that may have spent nothing. The official CLI draws no meter unless
|
|
4523
|
+
* the credits payload is present at all (`hasCreditsInfo`); every derived figure
|
|
4524
|
+
* here stays a placeholder until the balance reported.
|
|
4729
4525
|
*/
|
|
4730
4526
|
function monthlyView(report) {
|
|
4731
4527
|
const credits = report.credits;
|
|
@@ -4835,10 +4631,10 @@ window.__ModuleLoader__.load({
|
|
|
4835
4631
|
};
|
|
4836
4632
|
}
|
|
4837
4633
|
/**
|
|
4838
|
-
* Every panel string, resolved once per projection through the translator.
|
|
4839
|
-
*
|
|
4840
|
-
*
|
|
4841
|
-
*
|
|
4634
|
+
* Every panel string, resolved once per projection through the translator. One
|
|
4635
|
+
* object with all keys (rather than per-field lookups in the components) keeps
|
|
4636
|
+
* the copy table and the render sites in lockstep: a key cannot be read from
|
|
4637
|
+
* `text` unless {@link PANEL_KEYS} declares it.
|
|
4842
4638
|
*/
|
|
4843
4639
|
function panelStrings(t) {
|
|
4844
4640
|
const out = {};
|
|
@@ -4908,9 +4704,9 @@ window.__ModuleLoader__.load({
|
|
|
4908
4704
|
};
|
|
4909
4705
|
}
|
|
4910
4706
|
/**
|
|
4911
|
-
* How often the panel re-reads the report while a surface is mounted. The
|
|
4912
|
-
*
|
|
4913
|
-
*
|
|
4707
|
+
* How often the panel re-reads the report while a surface is mounted. The quota
|
|
4708
|
+
* windows move slowly and one report costs four upstream calls, so this is a
|
|
4709
|
+
* background freshness tick, not a live meter.
|
|
4914
4710
|
*/
|
|
4915
4711
|
const PANEL_AUTO_REFRESH_MS = 12e4;
|
|
4916
4712
|
/** The default timer (the client bundle runs in a browser; node tests inject one). */
|
|
@@ -4927,21 +4723,18 @@ window.__ModuleLoader__.load({
|
|
|
4927
4723
|
/** Pending timer handle of the running loop. */
|
|
4928
4724
|
let handle;
|
|
4929
4725
|
/**
|
|
4930
|
-
* Start the shared auto refresh. One fetch when the surface appears (the
|
|
4931
|
-
*
|
|
4932
|
-
*
|
|
4933
|
-
* stays mounted.
|
|
4726
|
+
* Start the shared auto refresh. One fetch when the surface appears (the sidebar
|
|
4727
|
+
* row is the point of the panel — it must be current, not wait for a click), then
|
|
4728
|
+
* a tick every {@link PANEL_AUTO_REFRESH_MS} while a surface stays mounted.
|
|
4934
4729
|
*
|
|
4935
|
-
* Reference-counted: the sidebar entry and the dashboard can be mounted at
|
|
4936
|
-
*
|
|
4937
|
-
*
|
|
4938
|
-
*
|
|
4939
|
-
* against the settings page's own refresh.
|
|
4730
|
+
* Reference-counted: the sidebar entry and the dashboard can be mounted at once,
|
|
4731
|
+
* so only the first start fetches and only the last stop halts the loop. Every
|
|
4732
|
+
* tick goes through `usage.refresh()`, which collapses a concurrent fetch onto
|
|
4733
|
+
* the in-flight one. Returns the disposer that drops this surface's reference.
|
|
4940
4734
|
*
|
|
4941
4735
|
* @param usage - the shared usage controller.
|
|
4942
4736
|
* @param isConfigured - whether a credential exists right now (re-read per tick).
|
|
4943
4737
|
* @param timer - timer seam for tests.
|
|
4944
|
-
* @returns the disposer that drops this surface's reference.
|
|
4945
4738
|
*/
|
|
4946
4739
|
function startPanelAutoRefresh(usage, isConfigured, timer = REAL_TIMER) {
|
|
4947
4740
|
references += 1;
|
|
@@ -4972,26 +4765,20 @@ window.__ModuleLoader__.load({
|
|
|
4972
4765
|
//#endregion
|
|
4973
4766
|
//#region src/client/panel-view.tsx
|
|
4974
4767
|
/**
|
|
4975
|
-
* React components for the Command Code plans & quota panel
|
|
4976
|
-
*
|
|
4768
|
+
* React components for the Command Code plans & quota panel: the sidebar footer
|
|
4769
|
+
* card and the dashboard it opens in the center column.
|
|
4977
4770
|
*
|
|
4978
4771
|
* Both render one {@link PanelView} projected by `./panel.ts` — no fact is
|
|
4979
4772
|
* derived here. Strings arrive already localized in `view.text`: the slots
|
|
4980
4773
|
* declare the `panel.commandcode` locale namespace, so the renderer hands this
|
|
4981
|
-
* component a `t` seat that is passed into `buildPanelView
|
|
4982
|
-
*
|
|
4983
|
-
* surfaces re-render without an extra channel).
|
|
4774
|
+
* component a `t` seat that is passed into `buildPanelView`, and a language
|
|
4775
|
+
* switch mints a new `t` identity, which re-renders both surfaces.
|
|
4984
4776
|
*
|
|
4985
|
-
* The footer card is the panel's home
|
|
4986
|
-
*
|
|
4987
|
-
*
|
|
4988
|
-
*
|
|
4989
|
-
*
|
|
4990
|
-
* owns, this entry owns its whole surface and therefore calls `open()` itself.
|
|
4991
|
-
*
|
|
4992
|
-
* Styles ride the stylesheet `./panel-styles.ts` returns, injected once by
|
|
4993
|
-
* the client entry; classes are `ccp-` prefixed to stay clear of the settings
|
|
4994
|
-
* page's `cc-` set.
|
|
4777
|
+
* The footer card is the panel's home — the shell renders it in the foot area
|
|
4778
|
+
* directly above the Settings seat, and unlike a `sidebar.panellist` row (whose
|
|
4779
|
+
* chrome and label the SHELL owns) this entry owns its whole surface and
|
|
4780
|
+
* therefore calls `open()` itself. Styles ride the stylesheet
|
|
4781
|
+
* `./panel-styles.ts` returns; classes are `ccp-` prefixed.
|
|
4995
4782
|
*
|
|
4996
4783
|
* @module dsh-commandcode-provider/client/panel-view
|
|
4997
4784
|
*/
|
|
@@ -5409,27 +5196,24 @@ window.__ModuleLoader__.load({
|
|
|
5409
5196
|
}
|
|
5410
5197
|
/**
|
|
5411
5198
|
* The sidebar footer card, registered into `sidebar.footer.action` — the list
|
|
5412
|
-
* the shell renders in the
|
|
5413
|
-
*
|
|
5414
|
-
*
|
|
5199
|
+
* the shell renders in the foot area directly ABOVE the Settings seat, so the
|
|
5200
|
+
* panel reads as a bottom-pinned sibling of Settings rather than a global panel
|
|
5201
|
+
* icon at the top of the column.
|
|
5415
5202
|
*
|
|
5416
|
-
* The shell wraps nothing here, so this component owns the surface: the
|
|
5417
|
-
*
|
|
5418
|
-
*
|
|
5419
|
-
*
|
|
5420
|
-
*
|
|
5421
|
-
*
|
|
5422
|
-
*
|
|
5423
|
-
* matching the shell's own rail geometry. `wide` comes from the shell as an
|
|
5424
|
-
* owner prop — unlike the old `sidebar.panellist` row, this slot really does
|
|
5425
|
-
* supply it.
|
|
5203
|
+
* The shell wraps nothing here, so this component owns the surface: the button,
|
|
5204
|
+
* its chrome and its accessible name. Expanded, it draws the title row and one
|
|
5205
|
+
* block per quota window (5-hour, then weekly) — the window's own spend and
|
|
5206
|
+
* limit, its percentage and its bar — and nothing else, because those two
|
|
5207
|
+
* windows are the figures an account runs into, so the period total stays in the
|
|
5208
|
+
* tooltip. In the 56px rail it collapses to a 36px icon button carrying the ring,
|
|
5209
|
+
* matching the shell's own rail geometry; `wide` comes from the shell.
|
|
5426
5210
|
*
|
|
5427
5211
|
* Rendering is gated on the settings page's `showSidebarQuota` toggle, which
|
|
5428
5212
|
* defaults OFF: a fresh install shows no quota surface in the sidebar and runs
|
|
5429
5213
|
* no background poll. The gate reads the STORED document (the settings
|
|
5430
|
-
* controller's `sidebarQuota` fact), so an unsaved draft cannot show the card
|
|
5431
|
-
* while a landed save flips it live. The entry
|
|
5432
|
-
* render decision,
|
|
5214
|
+
* controller's `sidebarQuota` fact), so an unsaved draft cannot show the card
|
|
5215
|
+
* while a landed save flips it live. The entry stays REGISTERED — this is a
|
|
5216
|
+
* render decision, so nothing churns the slot ledger.
|
|
5433
5217
|
*/
|
|
5434
5218
|
function CommandCodeFooterEntry(props) {
|
|
5435
5219
|
const visible = props.useCommandCodeSettings((snapshot) => snapshot.sidebarQuota);
|
|
@@ -5530,13 +5314,13 @@ window.__ModuleLoader__.load({
|
|
|
5530
5314
|
return time.getUTCDay() !== 0 && time.getUTCDay() !== 6 && windows.some(([start, end]) => time.getUTCHours() >= start && time.getUTCHours() < end);
|
|
5531
5315
|
}
|
|
5532
5316
|
/**
|
|
5533
|
-
* All prompt billing buckets determine a request's band, never cumulative
|
|
5317
|
+
* All prompt billing buckets determine a request's band, never cumulative
|
|
5318
|
+
* session input.
|
|
5534
5319
|
*
|
|
5535
5320
|
* A tiered model returns the matching band and does NOT then apply `peak`: the
|
|
5536
|
-
* page publishes those two dimensions independently
|
|
5537
|
-
*
|
|
5538
|
-
*
|
|
5539
|
-
* choice, not a verified upstream rule.
|
|
5321
|
+
* page publishes those two dimensions independently and no row carries both
|
|
5322
|
+
* today, so the combination becoming real is visible before it reaches a user.
|
|
5323
|
+
* This ordering is a latent choice, not a verified upstream rule.
|
|
5540
5324
|
*/
|
|
5541
5325
|
function requestRates(price, at, contextTokens, table) {
|
|
5542
5326
|
const tier = price.contextTiers?.find((tier) => tier.maxContext === void 0 || contextTokens <= tier.maxContext);
|
|
@@ -5572,31 +5356,27 @@ window.__ModuleLoader__.load({
|
|
|
5572
5356
|
/**
|
|
5573
5357
|
* Session-cost view model for the composer readout.
|
|
5574
5358
|
*
|
|
5575
|
-
*
|
|
5576
|
-
*
|
|
5577
|
-
*
|
|
5578
|
-
*
|
|
5579
|
-
*
|
|
5580
|
-
*
|
|
5581
|
-
*
|
|
5582
|
-
* The figures it prices are the session's DURABLE cumulative buckets, which is
|
|
5583
|
-
* what the composer's own "N tokens" pill reads too (`tokenUsage`), so the two
|
|
5584
|
-
* surfaces can never disagree about how much was used. Dollars are computed
|
|
5585
|
-
* here because Command Code publishes per-token rates and bills against
|
|
5586
|
-
* dollar-denominated windows; the account's own reported `totalCost` is a
|
|
5587
|
-
* billing PERIOD figure, not this session's.
|
|
5359
|
+
* JSX-free and React-free, mirroring `./panel.ts`: it turns the session's token
|
|
5360
|
+
* accounting plus the Host's price table into one presentation value AND the
|
|
5361
|
+
* exact text the two surfaces of the harness's token-usage UI receive — the
|
|
5362
|
+
* amount appended to the shipped pill, and the rows appended to the shipped
|
|
5363
|
+
* usage dialog. Node tests therefore drive the whole calculation, and every
|
|
5364
|
+
* user-visible string, without a DOM.
|
|
5588
5365
|
*
|
|
5589
|
-
*
|
|
5366
|
+
* It prices the session's DURABLE cumulative buckets, which is what the
|
|
5367
|
+
* composer's own "N tokens" pill reads too (`tokenUsage`), so the two surfaces
|
|
5368
|
+
* can never disagree about how much was used. Dollars are computed here because
|
|
5369
|
+
* Command Code publishes per-token rates and bills against dollar-denominated
|
|
5370
|
+
* windows; the account's own reported `totalCost` is a billing PERIOD figure,
|
|
5371
|
+
* not this session's.
|
|
5590
5372
|
*
|
|
5591
|
-
*
|
|
5592
|
-
*
|
|
5593
|
-
*
|
|
5594
|
-
*
|
|
5595
|
-
*
|
|
5596
|
-
*
|
|
5597
|
-
*
|
|
5598
|
-
* model, or all-zero buckets renders nothing at all — a confident `$0.00`
|
|
5599
|
-
* would be a lie, and this module never returns one.
|
|
5373
|
+
* Three rules are load-bearing: only Command Code usage is priced (a session
|
|
5374
|
+
* served by another provider must render nothing, never a Command Code
|
|
5375
|
+
* estimate); a missing rate is never invented (the pricing page publishes a
|
|
5376
|
+
* cache-WRITE rate for only some models, so unpriced cache-write tokens are
|
|
5377
|
+
* surfaced as such rather than charged at a guessed multiple of the input rate);
|
|
5378
|
+
* and unpriceable means invisible — a confident `$0.00` would be a lie, and
|
|
5379
|
+
* this module never returns one.
|
|
5600
5380
|
*
|
|
5601
5381
|
* @module dsh-commandcode-provider/client/session-cost
|
|
5602
5382
|
*/
|
|
@@ -5621,15 +5401,12 @@ window.__ModuleLoader__.load({
|
|
|
5621
5401
|
* between its own items.
|
|
5622
5402
|
*/
|
|
5623
5403
|
separator: "·",
|
|
5624
|
-
/** The heading the tooltip leads with. */
|
|
5625
5404
|
panelTitle: "Session cost",
|
|
5626
5405
|
/** Marks an estimate from published rates rather than an invoice. */
|
|
5627
5406
|
approximate: "≈",
|
|
5628
|
-
/** Tooltip line for the unpriced cache-write tokens. */
|
|
5629
5407
|
unpricedCacheWrite: "cache write tokens have no published rate",
|
|
5630
5408
|
/** Tooltip line naming the rate half in force. */
|
|
5631
5409
|
peakRates: "peak rates",
|
|
5632
|
-
/** Tooltip line naming the rate half in force. */
|
|
5633
5410
|
offPeakRates: "off-peak rates",
|
|
5634
5411
|
/** Tooltip line explaining the approximate marker. */
|
|
5635
5412
|
approximateNote: "estimate from published rates, not the provider invoice",
|
|
@@ -5690,8 +5467,8 @@ window.__ModuleLoader__.load({
|
|
|
5690
5467
|
*
|
|
5691
5468
|
* The panel's `money()` convention (2 decimals, 4 below a cent) is right for
|
|
5692
5469
|
* billing windows, but a live session total starts far below a cent, where
|
|
5693
|
-
* `toFixed(4)` would print a flat `$0.0000` —
|
|
5694
|
-
*
|
|
5470
|
+
* `toFixed(4)` would print a flat `$0.0000` — broken rather than small. So a
|
|
5471
|
+
* total under $0.0001 is stated as a bound instead.
|
|
5695
5472
|
*/
|
|
5696
5473
|
function sessionCostAmount(total) {
|
|
5697
5474
|
if (!Number.isFinite(total) || total <= 0) return formatMoney(0);
|
|
@@ -5899,15 +5676,14 @@ window.__ModuleLoader__.load({
|
|
|
5899
5676
|
* and never the outlet's parent, because the parent is the composer footer,
|
|
5900
5677
|
* which holds the `ContextMeter` as well, and that meter's trigger is itself a
|
|
5901
5678
|
* `button[aria-haspopup="dialog"]` rendered AFTER the dock. A parent-scoped
|
|
5902
|
-
* "last trigger wins" would
|
|
5903
|
-
* instead of the token pill.
|
|
5679
|
+
* "last trigger wins" would append the cost to the context ring instead.
|
|
5904
5680
|
*/
|
|
5905
5681
|
const STATS_ROOT = "[data-composer-stats]";
|
|
5906
5682
|
/**
|
|
5907
5683
|
* The shipped token-usage dialog's `<dl>`. Unique WITHIN one `StatsPills`
|
|
5908
|
-
* render
|
|
5909
|
-
* markup,
|
|
5910
|
-
*
|
|
5684
|
+
* render (the per-message turn-usage panel has its own dialog with different
|
|
5685
|
+
* markup), but not across the document once two composers are live — see
|
|
5686
|
+
* {@link resolveDialog}.
|
|
5911
5687
|
*/
|
|
5912
5688
|
const USAGE_DIALOG = "[data-session-stats-usage]";
|
|
5913
5689
|
/**
|
|
@@ -5917,8 +5693,8 @@ window.__ModuleLoader__.load({
|
|
|
5917
5693
|
*/
|
|
5918
5694
|
const DIALOG_TRIGGER = "button[aria-haspopup=\"dialog\"]";
|
|
5919
5695
|
/**
|
|
5920
|
-
* Stable id for the hidden node the appended cost is described by. The pill's
|
|
5921
|
-
*
|
|
5696
|
+
* Stable id for the hidden node the appended cost is described by. The pill's own
|
|
5697
|
+
* `aria-label` is recomputed by the harness on every render and cannot be
|
|
5922
5698
|
* extended, so a description is how the cost reaches assistive technology.
|
|
5923
5699
|
*/
|
|
5924
5700
|
const A11Y_ID = "dsh-commandcode-session-cost";
|
|
@@ -6040,11 +5816,9 @@ window.__ModuleLoader__.load({
|
|
|
6040
5816
|
* registration order. {@link STATS_ROOT} narrows that to the stats row where
|
|
6041
5817
|
* the markup marks it; where it does not, the outlet is already the narrowest
|
|
6042
5818
|
* correct container, because the composer footer's `ContextMeter` sits BESIDE
|
|
6043
|
-
* the outlet rather than inside it.
|
|
6044
|
-
*
|
|
6045
|
-
*
|
|
6046
|
-
* what makes this lookup per-composer, and a second composer can be live at
|
|
6047
|
-
* once (the sidebar can mount an embedded Conversation).
|
|
5819
|
+
* the outlet rather than inside it. A missing scope is "no pill", never a
|
|
5820
|
+
* document-wide search: the outlet is what makes this lookup per-composer, and
|
|
5821
|
+
* two composers can be live at once.
|
|
6048
5822
|
*/
|
|
6049
5823
|
resolvePillButton() {
|
|
6050
5824
|
const scope = this.scope();
|
|
@@ -6176,20 +5950,18 @@ window.__ModuleLoader__.load({
|
|
|
6176
5950
|
*
|
|
6177
5951
|
* The dialog is portaled onto `body`, so unlike the pill it cannot be scoped
|
|
6178
5952
|
* from this entry, and the attribute is unique per DIALOG rather than per
|
|
6179
|
-
* document. While one composer was guaranteed
|
|
6180
|
-
* exact
|
|
6181
|
-
* in the sidebar, so a second composer —
|
|
6182
|
-
*
|
|
5953
|
+
* document. While one composer was guaranteed a document-level lookup was
|
|
5954
|
+
* exact; 0.1.6-alpha.2 ended that guarantee by mounting an embedded
|
|
5955
|
+
* Conversation in the sidebar, so a second composer — its own session, dock and
|
|
5956
|
+
* dialog — can be live and open at the same time.
|
|
6183
5957
|
*
|
|
6184
5958
|
* There is no DOM link from a dialog back to its trigger (the portaled panel
|
|
6185
|
-
* carries no id and no `aria-controls`), so
|
|
6186
|
-
*
|
|
6187
|
-
*
|
|
6188
|
-
*
|
|
6189
|
-
*
|
|
6190
|
-
*
|
|
6191
|
-
* follows, applied one level up: a dialog we cannot prove is ours is left
|
|
6192
|
-
* alone.
|
|
5959
|
+
* carries no id and no `aria-controls`), so document order says nothing about
|
|
5960
|
+
* ownership. The shape confirmation in {@link dialogShapeMatches} would usually
|
|
5961
|
+
* reject the stranger, but it compares against THIS entry's counts, so a
|
|
5962
|
+
* coincidentally matching dialog would be priced with another session's
|
|
5963
|
+
* figures. Ambiguity is therefore answered by declining to decorate at all:
|
|
5964
|
+
* a dialog we cannot prove is ours is left alone.
|
|
6193
5965
|
*/
|
|
6194
5966
|
resolveDialog() {
|
|
6195
5967
|
if (this.dialogHost?.isConnected === true) return this.dialogHost;
|
|
@@ -6231,12 +6003,11 @@ window.__ModuleLoader__.load({
|
|
|
6231
6003
|
/**
|
|
6232
6004
|
* Whether the dialog really holds the rows this session's buckets predict.
|
|
6233
6005
|
*
|
|
6234
|
-
* The shipped labels belong to the `chat` locale
|
|
6235
|
-
*
|
|
6236
|
-
*
|
|
6237
|
-
*
|
|
6238
|
-
*
|
|
6239
|
-
* dialog is not what this view describes, and nothing is decorated.
|
|
6006
|
+
* The shipped labels belong to the `chat` locale and differ per language, so rows
|
|
6007
|
+
* are matched by POSITION, and this is what makes that safe: the row count must
|
|
6008
|
+
* agree, the cache-hit row must be the percentage it is, and every other value
|
|
6009
|
+
* must carry exactly the token count of the bucket predicted for it. A mismatch
|
|
6010
|
+
* means the dialog is not what this view describes, and nothing is decorated.
|
|
6240
6011
|
*/
|
|
6241
6012
|
function dialogShapeMatches(pairs, plan, prices) {
|
|
6242
6013
|
if (pairs.length !== plan.length) return false;
|
|
@@ -6269,13 +6040,13 @@ window.__ModuleLoader__.load({
|
|
|
6269
6040
|
/**
|
|
6270
6041
|
* The dock outlet this entry renders inside, i.e. what it scopes itself from.
|
|
6271
6042
|
*
|
|
6272
|
-
* The OUTLET
|
|
6273
|
-
*
|
|
6274
|
-
*
|
|
6275
|
-
*
|
|
6276
|
-
*
|
|
6277
|
-
*
|
|
6278
|
-
*
|
|
6043
|
+
* The OUTLET, not its parent. The outlet is one `display:contents` div holding
|
|
6044
|
+
* exactly this slot's entries (the shipped `stats` cell and ours), so it is the
|
|
6045
|
+
* narrowest container that is still per-composer. Its parent is NOT: from
|
|
6046
|
+
* 0.1.6-alpha.2 the composer stacks the dock inside a footer that also holds the
|
|
6047
|
+
* `ContextMeter`, whose trigger is another `button[aria-haspopup="dialog"]`
|
|
6048
|
+
* rendered after the dock — scoping to the parent would let the cost land on the
|
|
6049
|
+
* context ring.
|
|
6279
6050
|
*/
|
|
6280
6051
|
const DOCK_ANCHOR = "[data-slot=\"conversation.composer.dock\"]";
|
|
6281
6052
|
/** Module-level constant so the marker's `style` prop never diffs. */
|
|
@@ -6339,44 +6110,37 @@ window.__ModuleLoader__.load({
|
|
|
6339
6110
|
* Stylesheet for the Command Code settings page — and the Models-page provider
|
|
6340
6111
|
* card, which shares its `cc-` classes.
|
|
6341
6112
|
*
|
|
6342
|
-
* Returned as a string
|
|
6343
|
-
*
|
|
6344
|
-
*
|
|
6345
|
-
*
|
|
6346
|
-
*
|
|
6347
|
-
*
|
|
6348
|
-
*
|
|
6349
|
-
*
|
|
6350
|
-
*
|
|
6351
|
-
* hardcoded values. Classes are `cc-` prefixed to stay clear of the panel's
|
|
6352
|
-
* `ccp-` set.
|
|
6113
|
+
* Returned as a string, not injected here, so importing this module has no DOM
|
|
6114
|
+
* side effect: `./index.ts` installs it once under {@link PAGE_CSS_ID}. It is a
|
|
6115
|
+
* module of its own rather than a literal in the entry so `tests/styles.test.ts`
|
|
6116
|
+
* can audit every rule without importing the React tree (which pulls
|
|
6117
|
+
* `*.module.css` through the primitives package and needs a loader registered
|
|
6118
|
+
* first). The rules are GLOBAL CSS, so containment is a contract (issue #48):
|
|
6119
|
+
* every selector is qualified by one of our own `cc-` classes. Colours are
|
|
6120
|
+
* harness theme aliases with neutral fallbacks, and the `cc-` prefix keeps
|
|
6121
|
+
* these clear of the panel's `ccp-` set.
|
|
6353
6122
|
*
|
|
6354
6123
|
* @module dsh-commandcode-provider/client/page-styles
|
|
6355
6124
|
*/
|
|
6356
6125
|
/**
|
|
6357
|
-
* Stylesheet id
|
|
6126
|
+
* Stylesheet id — the `data-plugin-css` value that makes injection idempotent.
|
|
6358
6127
|
*
|
|
6359
|
-
* The
|
|
6360
|
-
* (`PANEL_CSS_ID`
|
|
6361
|
-
*
|
|
6362
|
-
* the plugin inject the same rules twice and would misreport the owner in the
|
|
6363
|
-
* DOM. The two ids must also stay distinct from each other — they key two
|
|
6364
|
-
* separate style tags, and a shared id would make the second injection a no-op
|
|
6365
|
-
* that silently drops one stylesheet.
|
|
6128
|
+
* The prefix must match this package's real name and the panel stylesheet's
|
|
6129
|
+
* (`PANEL_CSS_ID`); the two ids must also stay DISTINCT, since they key two
|
|
6130
|
+
* separate style tags and a shared id would make the second injection a no-op.
|
|
6366
6131
|
*/
|
|
6367
6132
|
const PAGE_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css";
|
|
6368
6133
|
/**
|
|
6369
6134
|
* The settings-page stylesheet.
|
|
6370
6135
|
*
|
|
6371
6136
|
* The metrics are the harness's own settings pages', read out of the 0.1.7
|
|
6372
|
-
* bundles so the page sits beside General and Models without looking foreign:
|
|
6373
|
-
*
|
|
6137
|
+
* bundles so the page sits beside General and Models without looking foreign: a
|
|
6138
|
+
* row is 16px of padding over a 0.5px border-l2 hairline, its title 14/22
|
|
6374
6139
|
* label-primary and its description 12/18 label-tertiary, the control on the
|
|
6375
6140
|
* right. Selectors and buttons are capsules (36px / 28px compact), inputs are
|
|
6376
6141
|
* 32px with an 8px radius and a 0.5px border-l4 edge, a card is a 0.5px
|
|
6377
6142
|
* border-l4 outline with a 16px radius, and a nested panel is a
|
|
6378
|
-
* bg-module-platform fill with a 12px radius. Errors use state-error-primary
|
|
6379
|
-
* the platform's error colour (label-error is its text-only sibling).
|
|
6143
|
+
* bg-module-platform fill with a 12px radius. Errors use state-error-primary.
|
|
6380
6144
|
*/
|
|
6381
6145
|
const PAGE_CSS = `
|
|
6382
6146
|
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex}
|
|
@@ -6384,7 +6148,6 @@ window.__ModuleLoader__.load({
|
|
|
6384
6148
|
.cc-intro{margin:4px 0 0;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}
|
|
6385
6149
|
.cc-readOnly{margin:8px 0 0;color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-tertiary));font-size:12px;line-height:18px}
|
|
6386
6150
|
.cc-spacer{flex:1}
|
|
6387
|
-
/* Groups: a heading over hairline-separated rows, no card surface. */
|
|
6388
6151
|
.cc-group{flex-direction:column;display:flex;margin-top:28px}
|
|
6389
6152
|
.cc-groupHead{align-items:center;gap:8px;display:flex;min-height:28px;padding-bottom:4px}
|
|
6390
6153
|
.cc-groupTitle{margin:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}
|
|
@@ -6395,7 +6158,6 @@ window.__ModuleLoader__.load({
|
|
|
6395
6158
|
.cc-rows{flex-direction:column;display:flex}
|
|
6396
6159
|
.cc-row{align-items:center;gap:8px;display:flex;padding:16px 0;border-bottom:.5px solid var(--dsw-alias-border-l2)}
|
|
6397
6160
|
.cc-rows>.cc-row:last-child{border-bottom:0}
|
|
6398
|
-
.cc-rowNested{padding-left:16px}
|
|
6399
6161
|
.cc-rowFlush{padding:0;border-bottom:0}
|
|
6400
6162
|
.cc-rowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:32px;display:flex}
|
|
6401
6163
|
.cc-rowTitleLine{align-items:center;gap:8px;display:flex;min-width:0}
|
|
@@ -6407,19 +6169,15 @@ window.__ModuleLoader__.load({
|
|
|
6407
6169
|
.cc-rowControl{flex:none;align-items:center;justify-content:flex-end;gap:8px;display:inline-flex;max-width:60%}
|
|
6408
6170
|
.cc-rowInput{width:200px}
|
|
6409
6171
|
.cc-rowInputWide{width:280px}
|
|
6410
|
-
/* The platform's link button: a compact capsule with no fill until hovered. */
|
|
6411
6172
|
.cc-linkButton{box-sizing:border-box;flex:none;align-items:center;display:inline-flex;height:28px;padding:0 10px;border:0;border-radius:14px;background:0 0;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px;line-height:18px;white-space:nowrap;cursor:pointer}
|
|
6412
6173
|
.cc-linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}
|
|
6413
6174
|
.cc-linkButton:disabled{cursor:default;opacity:.4}
|
|
6414
6175
|
.cc-linkButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
|
|
6415
|
-
/* Tags: the platform Tag's capsule (11/17, weight 500). */
|
|
6416
6176
|
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
6417
6177
|
.cc-badge,.cc-badgeMuted{flex:none;align-items:center;display:inline-flex;white-space:nowrap;border-radius:999px;corner-shape:round;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6418
6178
|
.cc-badge{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}
|
|
6419
6179
|
.cc-badgeMuted{border:.5px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}
|
|
6420
6180
|
.cc-badgeWarn{background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary))}
|
|
6421
|
-
/* The stacked field (the Models-page provider card and the account forms):
|
|
6422
|
-
* the platform SettingsForm field's metrics. */
|
|
6423
6181
|
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
6424
6182
|
.cc-field+.cc-field{border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
6425
6183
|
.cc-fieldHead{align-items:center;gap:8px;display:flex}
|
|
@@ -6432,10 +6190,7 @@ window.__ModuleLoader__.load({
|
|
|
6432
6190
|
.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
6433
6191
|
.cc-input:disabled{opacity:.6;cursor:default}
|
|
6434
6192
|
.cc-inputInvalid{border-color:var(--dsw-alias-state-error-primary)}
|
|
6435
|
-
.cc-invalid{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}
|
|
6436
6193
|
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}
|
|
6437
|
-
/* The model multi-select trigger: the platform's selector capsule (the
|
|
6438
|
-
* language / permission pickers on General). */
|
|
6439
6194
|
.cc-modelSelectAnchor{flex-direction:column;align-items:stretch;gap:6px;display:inline-flex;min-width:160px}
|
|
6440
6195
|
.cc-selector{box-sizing:border-box;align-items:center;gap:12px;display:inline-flex;height:36px;padding:0 14px;border:0;border-radius:18px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}
|
|
6441
6196
|
.cc-selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
@@ -6449,51 +6204,34 @@ window.__ModuleLoader__.load({
|
|
|
6449
6204
|
.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}
|
|
6450
6205
|
.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}
|
|
6451
6206
|
.cc-checkRow:hover{cursor:pointer}
|
|
6452
|
-
/* A hand-drawn box
|
|
6453
|
-
*
|
|
6454
|
-
*
|
|
6455
|
-
*
|
|
6456
|
-
*
|
|
6457
|
-
*
|
|
6458
|
-
*
|
|
6459
|
-
* outline is a border-l3 hairline: border-l2 (#ffffff1f in dark) leaves an
|
|
6460
|
-
* unchecked box all but invisible against the menu surface. */
|
|
6207
|
+
/* A hand-drawn box, not the platform's accent-color checkbox: the native
|
|
6208
|
+
* control's colours come from color-scheme, which the theme sets once at BOOT
|
|
6209
|
+
* and never re-applies in-session, so a native box can paint light-chrome white
|
|
6210
|
+
* on a dark page. The mark rides a brand-primary fill, so it takes the brand
|
|
6211
|
+
* foreground (the only pairing that survives dark mode's near-white brand), and
|
|
6212
|
+
* the outline is a border-l3 hairline because border-l2 leaves an unchecked box
|
|
6213
|
+
* invisible against the menu surface. */
|
|
6461
6214
|
.cc-check{box-sizing:border-box;appearance:none;flex-shrink:0;width:16px;height:16px;margin:0;border:1px solid var(--dsw-alias-border-l3);border-radius:4px;background:0 0;position:relative}
|
|
6462
6215
|
.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
6463
6216
|
.cc-check:checked::after{content:'';position:absolute;top:3px;left:5px;width:3px;height:7px;border:solid var(--dsw-alias-label-primary-foreground,#fff);border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
|
|
6464
6217
|
.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6465
|
-
/* The platform SegmentedControl: a translucent track and one raised pill that
|
|
6466
|
-
* slides under the picked segment. Segments are equal grid tracks, so the
|
|
6467
|
-
* indicator's width and offset follow from the count and the index alone. */
|
|
6468
|
-
.cc-segmented{position:relative;display:inline-grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:2px;padding:3px;border-radius:9px;background:var(--dsw-alias-interactive-bg-hover)}
|
|
6469
|
-
.cc-segmentIndicator{position:absolute;top:3px;left:3px;width:calc((100% - 6px - 2px * (var(--cc-segment-count) - 1)) / var(--cc-segment-count));height:calc(100% - 6px);border-radius:7px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-soft,0 1px 2px rgba(0,0,0,.12));transform:translateX(calc(var(--cc-segment-index) * (100% + 2px)));transition:transform .16s ease;pointer-events:none}
|
|
6470
|
-
.cc-segment{box-sizing:border-box;position:relative;z-index:1;height:28px;padding:0 16px;border:0;border-radius:7px;background:0 0;color:var(--dsw-alias-label-secondary);font:inherit;font-size:13px;font-weight:500;line-height:20px;white-space:nowrap;cursor:pointer;transition:color .12s ease}
|
|
6471
|
-
.cc-segment:hover:not(:disabled),.cc-segment[aria-checked=true]{color:var(--dsw-alias-label-primary)}
|
|
6472
|
-
.cc-segment:disabled{cursor:default;opacity:.4}
|
|
6473
|
-
.cc-segment:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}
|
|
6474
6218
|
/* Modelled on the platform's own Switch primitive (ui-primitives
|
|
6475
|
-
* Switch.module.css): a 36x20 capsule
|
|
6476
|
-
* 16px thumb across the 32px content box.
|
|
6477
|
-
*
|
|
6478
|
-
*
|
|
6479
|
-
*
|
|
6480
|
-
*
|
|
6481
|
-
*
|
|
6482
|
-
*
|
|
6483
|
-
* thumb vanishes on the checked track in dark mode; the brand foreground is the
|
|
6484
|
-
* token the platform paints on that fill. (3) --dsw-alias-border-l3 as the off
|
|
6485
|
-
* track: border-l2 (#ffffff1f in dark) leaves it indistinguishable from the
|
|
6486
|
-
* page. */
|
|
6219
|
+
* Switch.module.css): a 36x20 capsule padding its track by 2px and sliding a
|
|
6220
|
+
* 16px thumb across the 32px content box. Three things are load-bearing.
|
|
6221
|
+
* (1) corner-shape:round on BOTH track and thumb — the theme sets a global
|
|
6222
|
+
* superellipse corner shape, which squares a capsule's ends off around a round
|
|
6223
|
+
* thumb. (2) No literal colours: brand-primary INVERTS between the modes, so a
|
|
6224
|
+
* hardcoded white thumb vanishes on the checked track in dark mode; the brand
|
|
6225
|
+
* foreground is what the platform paints on that fill. (3) border-l3 as the
|
|
6226
|
+
* off track — border-l2 leaves it indistinguishable from the page. */
|
|
6487
6227
|
.cc-toggle{box-sizing:border-box;appearance:none;flex-shrink:0;width:36px;height:20px;margin:0;padding:2px;border:0;border-radius:10px;corner-shape:round;background:var(--dsw-alias-border-l3);cursor:pointer;position:relative}
|
|
6488
6228
|
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
6489
6229
|
.cc-toggle::after{content:'';display:block;width:16px;height:16px;border-radius:50%;corner-shape:round;background:var(--dsw-alias-label-primary-foreground);transition:transform .12s ease}
|
|
6490
|
-
/* 32px content box minus the 16px thumb. */
|
|
6491
6230
|
.cc-toggle:checked::after{transform:translateX(16px)}
|
|
6492
6231
|
.cc-toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
6493
6232
|
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
6494
6233
|
.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:7px;height:7px;margin-right:6px;margin-bottom:3px;transform:rotate(45deg);transition:transform .15s ease}
|
|
6495
6234
|
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
6496
|
-
/* Accounts: one outlined card per account, the Models page's provider card. */
|
|
6497
6235
|
.cc-accountMode{align-items:center;gap:4px;display:flex;margin:-4px 0 12px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
6498
6236
|
.cc-accountList{flex-direction:column;gap:8px;display:flex}
|
|
6499
6237
|
.cc-accountList+.cc-addButton,.cc-accountList+.cc-addPanel{margin-top:8px}
|
|
@@ -6506,7 +6244,7 @@ window.__ModuleLoader__.load({
|
|
|
6506
6244
|
.cc-iconButton{flex-shrink:0;align-items:center;justify-content:center;display:inline-flex;width:28px;height:28px;padding:0;background:0 0;border:0;border-radius:6px;color:var(--dsw-alias-label-tertiary);cursor:pointer}
|
|
6507
6245
|
.cc-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
6508
6246
|
.cc-iconButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
|
|
6509
|
-
/* Three dots from one element: the dot
|
|
6247
|
+
/* Three dots from one element: the dot plus two box-shadow copies. */
|
|
6510
6248
|
.cc-kebab{width:3px;height:3px;border-radius:50%;corner-shape:round;background:currentColor;box-shadow:0 -5px 0 currentColor,0 5px 0 currentColor}
|
|
6511
6249
|
.cc-tabDot{flex-shrink:0;width:8px;height:8px;border-radius:50%;corner-shape:round}
|
|
6512
6250
|
.cc-tabDotOk{background:var(--dsw-alias-state-success-primary)}
|
|
@@ -6528,20 +6266,16 @@ window.__ModuleLoader__.load({
|
|
|
6528
6266
|
.cc-confirmText{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;line-height:22px}
|
|
6529
6267
|
.cc-dangerButton{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}
|
|
6530
6268
|
.cc-dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}
|
|
6531
|
-
/* Adding an account: the Models page's dashed add button, opening a filled
|
|
6532
|
-
* panel in its place. */
|
|
6533
6269
|
.cc-addButton{box-sizing:border-box;align-items:center;justify-content:center;gap:6px;display:flex;width:100%;height:44px;border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;cursor:pointer}
|
|
6534
6270
|
.cc-addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
6535
6271
|
.cc-addButton:disabled{cursor:default;opacity:.4}
|
|
6536
6272
|
.cc-addButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
|
|
6537
|
-
/* A plus from two crossed bars. */
|
|
6538
6273
|
.cc-addGlyph{position:relative;width:12px;height:12px}
|
|
6539
6274
|
.cc-addGlyph::before,.cc-addGlyph::after{content:'';position:absolute;background:currentColor;border-radius:1px}
|
|
6540
6275
|
.cc-addGlyph::before{left:0;right:0;top:5.25px;height:1.5px}
|
|
6541
6276
|
.cc-addGlyph::after{top:0;bottom:0;left:5.25px;width:1.5px}
|
|
6542
6277
|
.cc-addPanel{flex-direction:column;gap:12px;display:flex;padding:14px 16px;border-radius:12px;background:var(--dsw-alias-bg-module-platform)}
|
|
6543
6278
|
.cc-panelTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}
|
|
6544
|
-
/* Account report: stat tiles are filled panels, like the platform's editors. */
|
|
6545
6279
|
.cc-accountReport{flex-direction:column;gap:14px;display:flex}
|
|
6546
6280
|
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
6547
6281
|
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:14px;font-weight:500;line-height:22px}
|
|
@@ -6549,10 +6283,9 @@ window.__ModuleLoader__.load({
|
|
|
6549
6283
|
.cc-usagePlan{flex:none;white-space:nowrap;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:999px;corner-shape:round;padding:0 7px;font-size:11px;font-weight:500;line-height:17px}
|
|
6550
6284
|
.cc-usagePlanStatus{flex:none;margin:0;white-space:nowrap;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
6551
6285
|
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}
|
|
6552
|
-
/* Two fixed grids
|
|
6553
|
-
*
|
|
6554
|
-
*
|
|
6555
|
-
* in a narrow details panel. */
|
|
6286
|
+
/* Two fixed grids, not one auto-fit track: auto-fit wrapped the four activity
|
|
6287
|
+
* tiles 3 + 1 at the details' width. The activity row folds to 2 × 2 in a
|
|
6288
|
+
* narrow details panel. */
|
|
6556
6289
|
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
6557
6290
|
.cc-usageStatsActivity{grid-template-columns:repeat(4,minmax(0,1fr))}
|
|
6558
6291
|
.cc-usageStatsBalance{grid-template-columns:repeat(3,minmax(0,1fr))}
|
|
@@ -6580,31 +6313,25 @@ window.__ModuleLoader__.load({
|
|
|
6580
6313
|
.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}
|
|
6581
6314
|
.cc-usageBlockedDetail{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px;word-break:break-word}
|
|
6582
6315
|
.cc-version{margin:32px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
6583
|
-
/* The update hint rides the footer version line, quiet until hovered. */
|
|
6584
6316
|
.cc-versionLink{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
6585
6317
|
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
6586
|
-
/* The Models-page provider panel root: unstyled by design — the row card the
|
|
6587
|
-
* Models page owns supplies the surface, the panel only stacks its controls. */
|
|
6588
6318
|
.cc-providerCard{flex-direction:column;display:flex}
|
|
6589
6319
|
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
6590
6320
|
.cc-failed{display:inline-block;max-width:260px;min-width:0;color:var(--dsw-alias-state-error-primary);margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px}
|
|
6591
|
-
/* The authorization link is the only link-coloured element on a login row. */
|
|
6592
6321
|
.cc-loginLink{color:var(--dsw-alias-link,var(--dsw-alias-brand-primary));text-decoration:none;font-size:12px;line-height:18px}
|
|
6593
6322
|
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
6594
6323
|
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
6595
6324
|
.cc-loginError{color:var(--dsw-alias-state-error-primary)}
|
|
6596
6325
|
/* The floating save bar: a centered capsule pinned to the bottom of the
|
|
6597
|
-
* settings scrollport. The dock is a zero-height sticky strip at the end of
|
|
6598
|
-
*
|
|
6599
|
-
*
|
|
6600
|
-
*
|
|
6601
|
-
*
|
|
6602
|
-
*
|
|
6603
|
-
*
|
|
6604
|
-
*
|
|
6605
|
-
*
|
|
6606
|
-
* are concentric: a 44px capsule around 36px capsule buttons inset by 4px, so
|
|
6607
|
-
* the gap around each button is even. */
|
|
6326
|
+
* settings scrollport. The dock is a zero-height sticky strip at the end of the
|
|
6327
|
+
* page, so the bar overlays the scrolling content instead of taking a row of
|
|
6328
|
+
* its own; while shown, the section reserves room at its end so the last line
|
|
6329
|
+
* can scroll clear. Hidden, it sinks and fades, and visibility (switched after
|
|
6330
|
+
* the transition) takes its buttons out of the tab order. Its surface is an
|
|
6331
|
+
* elevated layer (bg-layer-1 over the settings panel's layer-2) with the
|
|
6332
|
+
* platform's prominent elevation and no stroke, and its corners are concentric
|
|
6333
|
+
* (a 44px capsule around 36px buttons inset by 4px) so the gap around each
|
|
6334
|
+
* button is even. */
|
|
6608
6335
|
.cc-sectionWithBar{padding-bottom:80px}
|
|
6609
6336
|
.cc-saveBarDock{position:sticky;bottom:0;z-index:2;height:0;pointer-events:none}
|
|
6610
6337
|
.cc-saveBar{--cc-saveBar-tone:var(--dsw-alias-state-warn-primary,#d97706);position:absolute;left:50%;bottom:20px;box-sizing:border-box;width:max-content;max-width:calc(100% - 24px);align-items:center;gap:10px;display:flex;height:44px;padding:4px 4px 4px 16px;border:0;border-radius:22px;corner-shape:round;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-elevation-prominent,0 12px 32px -8px rgba(0,0,0,.24),0 2px 8px rgba(0,0,0,.08));opacity:0;visibility:hidden;transform:translate(-50%,12px);transition:opacity .16s ease,transform .16s ease,visibility 0s linear .16s}
|
|
@@ -6623,7 +6350,7 @@ window.__ModuleLoader__.load({
|
|
|
6623
6350
|
.cc-saveBarGhost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
6624
6351
|
.cc-saveBarPrimary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}
|
|
6625
6352
|
.cc-saveBarPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary)))}
|
|
6626
|
-
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle::after,.cc-usageBarFill,.cc-saveBar,.cc-saveBarShown
|
|
6353
|
+
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle::after,.cc-usageBarFill,.cc-saveBar,.cc-saveBarShown{transition:none}}
|
|
6627
6354
|
`;
|
|
6628
6355
|
//#endregion
|
|
6629
6356
|
//#region src/client/panel-styles.ts
|
|
@@ -6631,70 +6358,48 @@ window.__ModuleLoader__.load({
|
|
|
6631
6358
|
* Stylesheet for the Command Code plans & quota panel (the sidebar footer card
|
|
6632
6359
|
* and the dashboard it opens).
|
|
6633
6360
|
*
|
|
6634
|
-
* Returned as a string
|
|
6635
|
-
*
|
|
6636
|
-
*
|
|
6637
|
-
* (`./page-styles.ts`) uses, and removes it again when the plugin's fiber
|
|
6638
|
-
* unwinds.
|
|
6361
|
+
* Returned as a string, not injected here, so importing this module has no DOM
|
|
6362
|
+
* side effect: `./index.ts` installs it once under {@link PANEL_CSS_ID} and
|
|
6363
|
+
* removes it when the fiber unwinds.
|
|
6639
6364
|
*
|
|
6640
|
-
* These rules are GLOBAL CSS
|
|
6641
|
-
*
|
|
6642
|
-
*
|
|
6643
|
-
*
|
|
6644
|
-
*
|
|
6645
|
-
*
|
|
6646
|
-
*
|
|
6647
|
-
* Every colour comes from a harness theme alias with a neutral fallback, so
|
|
6648
|
-
* the panel follows the active theme (light/dark and any brand pack) without
|
|
6649
|
-
* hardcoded values. Classes are `ccp-` prefixed to stay clear of the settings
|
|
6650
|
-
* page's `cc-` set.
|
|
6365
|
+
* These rules are GLOBAL CSS, so containment is a contract (issue #48): every
|
|
6366
|
+
* selector is qualified by one of our own `ccp-` classes except the sidebar
|
|
6367
|
+
* anchor below, which carries its justification in place. `tests/styles.test.ts`
|
|
6368
|
+
* audits both stylesheets against the real foreign class stems. Colours are
|
|
6369
|
+
* harness theme aliases with neutral fallbacks; the `ccp-` prefix keeps these
|
|
6370
|
+
* clear of the settings page's `cc-` set.
|
|
6651
6371
|
*
|
|
6652
6372
|
* @module dsh-commandcode-provider/client/panel-styles
|
|
6653
6373
|
*/
|
|
6654
6374
|
/**
|
|
6655
|
-
* Stylesheet id
|
|
6375
|
+
* Stylesheet id — the `data-plugin-css` value that makes injection idempotent.
|
|
6656
6376
|
*
|
|
6657
|
-
* The
|
|
6658
|
-
* (`PAGE_CSS_ID`
|
|
6659
|
-
*
|
|
6660
|
-
* the plugin inject the same rules twice and would misreport the owner in the
|
|
6661
|
-
* DOM. The two ids must also stay distinct from each other — they key two
|
|
6662
|
-
* separate style tags, and a shared id would make the second injection a no-op
|
|
6663
|
-
* that silently drops one stylesheet.
|
|
6377
|
+
* The prefix must match this package's real name and the settings-page sheet's
|
|
6378
|
+
* (`PAGE_CSS_ID`); the two ids must also stay DISTINCT, since they key two
|
|
6379
|
+
* separate style tags and a shared id would make the second injection a no-op.
|
|
6664
6380
|
*/
|
|
6665
6381
|
const PANEL_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodePanel.module.css";
|
|
6666
6382
|
/** The panel stylesheet. */
|
|
6667
6383
|
const PANEL_CSS = `
|
|
6668
6384
|
/* ------------------------------------------------- sidebar footer card */
|
|
6669
|
-
/* The shell
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
step and a hairline border.
|
|
6674
|
-
|
|
6675
|
-
The shell's container is a flex ROW whose occupants (this card and ui-cordis's
|
|
6676
|
-
footer chip) each declare a full-width line and shrink-proof flex, so as a row
|
|
6677
|
-
it would overflow the column: this card's flex:0 0 auto cannot shrink, and the
|
|
6678
|
-
chip's width:100% basis would absorb the whole overflow and collapse to
|
|
6679
|
-
nothing. Both were written for a full-width line, which is exactly what a
|
|
6680
|
-
column gives them. Matched by the CSS-module class STEM — never a hashed name
|
|
6681
|
-
— so a dsh that renames it degrades to the shell's own row rather than
|
|
6682
|
-
breaking.
|
|
6385
|
+
/* The shell renders this list ABOVE the Settings seat, so the card is the
|
|
6386
|
+
sidebar's bottom-most content, and supplies no chrome: the entry IS the
|
|
6387
|
+
button. Deliberately quiet — a surface beside Settings should read as part of
|
|
6388
|
+
the column — with one hover step and a hairline border.
|
|
6683
6389
|
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6390
|
+
The shell's container is a flex ROW whose occupants each declare a full-width
|
|
6391
|
+
line and shrink-proof flex, so as a row it would overflow the column: this
|
|
6392
|
+
card cannot shrink and the neighbouring chip would absorb the overflow and
|
|
6393
|
+
collapse to nothing. The first rule is that fix, and THE ANCHOR IS
|
|
6394
|
+
LOAD-BEARING (issue #48): "footerActions" is not a stem this shell owns alone
|
|
6395
|
+
— dsh-client-ui-user-questions renders the ask-user-question dialog's button
|
|
6396
|
+
row as Mbwy4a_footerActions, and the unanchored rule stacked THAT row's
|
|
6689
6397
|
side-by-side buttons on every page. "footArea" is declared by
|
|
6690
|
-
dsh-client-ui-sidebar alone
|
|
6691
|
-
0.1.6-alpha.1 engine, and against our own cc-/ccp-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
than
|
|
6695
|
-
the two: a renamed or restructured shell should degrade to its own row, not
|
|
6696
|
-
lose the fix. tests/styles.test.ts pins both halves of this — the dialog row
|
|
6697
|
-
is no longer matched, the sidebar row still is. */
|
|
6398
|
+
dsh-client-ui-sidebar alone (audited across every client bundle of the
|
|
6399
|
+
0.1.6-alpha.1 engine, and against our own cc-/ccp- names, which collide with
|
|
6400
|
+
no engine class). The DESCENDANT combinator survives a wrapper element
|
|
6401
|
+
appearing between the two, so a restructured shell degrades to its own row
|
|
6402
|
+
rather than losing the fix. tests/styles.test.ts pins both halves. */
|
|
6698
6403
|
[class*="_footArea"] [class*="_footerActions"]{flex-direction:column}
|
|
6699
6404
|
.ccp-foot{box-sizing:border-box;flex:0 0 auto;width:100%;min-width:0;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:1px solid transparent;border-radius:10px;flex-direction:column;gap:6px;margin:0 0 4px;padding:8px;display:flex}
|
|
6700
6405
|
.ccp-foot:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}
|
|
@@ -6704,34 +6409,31 @@ window.__ModuleLoader__.load({
|
|
|
6704
6409
|
/* One block per quota window: a head line carrying the window's own spend and
|
|
6705
6410
|
limit, then the FULL-WIDTH bar under it. Stacking the two lets the card show
|
|
6706
6411
|
the dollar figures — the reason this surface exists — without squeezing the
|
|
6707
|
-
bar into what is left beside them. Mirrors the dashboard's
|
|
6412
|
+
bar into what is left beside them. Mirrors the dashboard's window block. */
|
|
6708
6413
|
.ccp-footRow{flex-direction:column;gap:4px;min-width:0;display:flex}
|
|
6709
6414
|
.ccp-footHead{align-items:baseline;gap:8px;min-width:0;display:flex}
|
|
6710
6415
|
.ccp-footLabel{flex:1;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}
|
|
6711
6416
|
.ccp-footAmount{flex:none;color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px;font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
6712
6417
|
/* The card's markup must stay PHRASING content — it renders inside the shell's
|
|
6713
|
-
own button — so these bars are spans,
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
container) while the fill collapsed to 0x0 and the bar showed no usage. */
|
|
6418
|
+
own button — so these bars are spans, which makes display:block load-bearing:
|
|
6419
|
+
an inline box ignores width outright, so the fill would collapse to 0x0 and
|
|
6420
|
+
the bar would show no usage. */
|
|
6717
6421
|
.ccp-footBar{display:block;background:var(--dsw-alias-bg-layer-2);border-radius:999px;height:5px;overflow:hidden}
|
|
6718
6422
|
.ccp-footFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
6719
6423
|
.ccp-footFillWarn{background:var(--dsw-alias-state-error-primary)}
|
|
6720
6424
|
.ccp-footPct{flex:none;width:34px;color:var(--dsw-alias-label-secondary);text-align:right;font-size:11px;line-height:16px;font-variant-numeric:tabular-nums}
|
|
6721
6425
|
|
|
6722
|
-
/* The 56px rail: one icon button on the shell's own rail
|
|
6723
|
-
|
|
6426
|
+
/* The 56px rail: one icon button on the shell's own 36px rail cell, so the
|
|
6427
|
+
collapsed column keeps a single 18px glyph like its siblings. */
|
|
6724
6428
|
.ccp-railButton{box-sizing:border-box;width:36px;height:36px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:1px solid transparent;border-radius:8px;flex:none;justify-content:center;align-items:center;margin:0 0 4px;padding:0;display:inline-flex}
|
|
6725
6429
|
.ccp-railButton:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}
|
|
6726
6430
|
.ccp-railButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}
|
|
6727
6431
|
|
|
6728
|
-
/* The ring glyph
|
|
6432
|
+
/* The ring glyph, sized entirely by its own width/height attribute, so the
|
|
6729
6433
|
footer row, the rail button and the dashboard can each ask for their own. */
|
|
6730
6434
|
.ccp-glyph{flex:none;justify-content:center;align-items:center;display:inline-flex;color:var(--dsw-alias-brand-primary)}
|
|
6731
6435
|
|
|
6732
6436
|
/* ------------------------------------------------------------ dashboard */
|
|
6733
|
-
/* The center column in the layout frame: fill it, scroll the content column,
|
|
6734
|
-
and cap the reading width like the harness's own panels. */
|
|
6735
6437
|
.ccp-main{background:var(--dsw-alias-bg-layer-1);width:100%;height:100%;overflow:auto;display:block}
|
|
6736
6438
|
.ccp-mainInner{max-width:760px;margin:0 auto;padding:24px 20px 40px;flex-direction:column;gap:14px;display:flex;color:var(--dsw-alias-label-primary)}
|
|
6737
6439
|
.ccp-header{align-items:center;gap:10px;display:flex;flex-wrap:wrap}
|
|
@@ -6740,14 +6442,12 @@ window.__ModuleLoader__.load({
|
|
|
6740
6442
|
.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
6741
6443
|
.ccp-spacer{flex:1}
|
|
6742
6444
|
.ccp-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;font-variant-numeric:tabular-nums}
|
|
6743
|
-
/* The dashboard's exit:
|
|
6744
|
-
|
|
6745
|
-
centred, so it reads as a dismiss control rather than a text button. */
|
|
6445
|
+
/* The dashboard's exit: the primitive's own size="sm" geometry is kept; only the
|
|
6446
|
+
glyph is enlarged and optically centred, so it reads as a dismiss control. */
|
|
6746
6447
|
.ccp-close{min-width:28px;justify-content:center;padding-left:0;padding-right:0}
|
|
6747
6448
|
.ccp-close span{font-size:16px;line-height:1}
|
|
6748
6449
|
.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6749
6450
|
|
|
6750
|
-
/* Notices: the no-key guidance, a blocked report, and a stale-data error. */
|
|
6751
6451
|
.ccp-notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:12px 14px;flex-direction:column;gap:4px;display:flex}
|
|
6752
6452
|
.ccp-noticeError{border-color:var(--dsw-alias-state-error-primary)}
|
|
6753
6453
|
.ccp-noticeTitle{margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
@@ -6767,15 +6467,14 @@ window.__ModuleLoader__.load({
|
|
|
6767
6467
|
.ccp-fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
6768
6468
|
.ccp-planName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:1.5}
|
|
6769
6469
|
|
|
6770
|
-
/*
|
|
6470
|
+
/* The monthly credits and the usage totals share one grid. */
|
|
6771
6471
|
.ccp-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px}
|
|
6772
6472
|
.ccp-tile{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex;min-width:0}
|
|
6773
6473
|
.ccp-tileLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
6774
6474
|
.ccp-tileValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4;font-variant-numeric:tabular-nums}
|
|
6775
6475
|
.ccp-tileSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6776
6476
|
|
|
6777
|
-
/* Quota bars: the monthly bar and the two windows
|
|
6778
|
-
label row plus the track. */
|
|
6477
|
+
/* Quota bars: the monthly bar and the two windows. */
|
|
6779
6478
|
.ccp-windows{flex-direction:column;gap:14px;display:flex}
|
|
6780
6479
|
.ccp-window{flex-direction:column;gap:6px;display:flex}
|
|
6781
6480
|
.ccp-windowHead{align-items:baseline;gap:8px;display:flex}
|
|
@@ -6788,7 +6487,6 @@ window.__ModuleLoader__.load({
|
|
|
6788
6487
|
.ccp-barFillWarn{background:var(--dsw-alias-state-error-primary)}
|
|
6789
6488
|
.ccp-windowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
6790
6489
|
|
|
6791
|
-
/* Badges. */
|
|
6792
6490
|
.ccp-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}
|
|
6793
6491
|
.ccp-badgeError{background:transparent;color:var(--dsw-alias-state-error-primary)}
|
|
6794
6492
|
.ccp-badgeWarn{background:var(--dsw-alias-state-warn-tertiary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-secondary))}
|
|
@@ -6832,13 +6530,6 @@ window.__ModuleLoader__.load({
|
|
|
6832
6530
|
webSearchHint: "使用同一密钥承载 dsh 的 web_search;关闭后恢复原搜索后端。",
|
|
6833
6531
|
showSidebarQuota: "在侧边栏显示额度卡片",
|
|
6834
6532
|
showSidebarQuotaHint: "在侧边栏底部显示套餐与额度卡片,点击可打开完整仪表盘。默认关闭,关闭时不会为它后台刷新用量。",
|
|
6835
|
-
commandGuard: "AI 命令安全预判",
|
|
6836
|
-
commandGuardHint: "命令确认弹窗前,先由 typesafe/jev 判断它是否安全;沙箱提权还会额外判断范围与必要性。三项都足够确定才自动放行,其余照常弹窗。默认关闭。",
|
|
6837
|
-
commandGuardLevel: "自动放行阈值",
|
|
6838
|
-
commandGuardLevelHint: "阈值越高,需要越确定才放行,弹窗越多。高 = 0.95,中 = 0.9(默认),低 = 0.8。判定超过 3 秒未返回会照常弹窗。",
|
|
6839
|
-
commandGuardLevelHigh: "高",
|
|
6840
|
-
commandGuardLevelMedium: "中",
|
|
6841
|
-
commandGuardLevelLow: "低",
|
|
6842
6533
|
zdr: "零数据保留(ZDR)",
|
|
6843
6534
|
zdrHint: "仅使用不留存、不训练的上游;可用模型可能更少且价格通常更高。",
|
|
6844
6535
|
accountsTitle: "账户",
|
|
@@ -6991,13 +6682,6 @@ window.__ModuleLoader__.load({
|
|
|
6991
6682
|
webSearchHint: "Use the same key for dsh web search; turning it off restores the previous backend.",
|
|
6992
6683
|
showSidebarQuota: "Show the quota card in the sidebar",
|
|
6993
6684
|
showSidebarQuotaHint: "Show a plan and quota card at the bottom of the sidebar that opens the full dashboard. Off by default; while off, no background usage refresh runs for it.",
|
|
6994
|
-
commandGuard: "AI command guard",
|
|
6995
|
-
commandGuardHint: "Before a shell command asks for approval, typesafe/jev judges whether it is safe. A sandbox escalation also needs separate scope and necessity verdicts; all three must be confident enough to skip the prompt. Off by default.",
|
|
6996
|
-
commandGuardLevel: "Auto-approve threshold",
|
|
6997
|
-
commandGuardLevelHint: "A higher threshold needs more confidence to skip the prompt, so you see more prompts. High = 0.95, Medium = 0.9 (default), Low = 0.8. A judgement that takes longer than 3 seconds shows the normal prompt.",
|
|
6998
|
-
commandGuardLevelHigh: "High",
|
|
6999
|
-
commandGuardLevelMedium: "Medium",
|
|
7000
|
-
commandGuardLevelLow: "Low",
|
|
7001
6685
|
zdr: "Zero data retention (ZDR)",
|
|
7002
6686
|
zdrHint: "Use only upstreams that retain no data and do not train on requests; availability and pricing may differ.",
|
|
7003
6687
|
accountsTitle: "Accounts",
|
|
@@ -7136,8 +6820,8 @@ window.__ModuleLoader__.load({
|
|
|
7136
6820
|
}
|
|
7137
6821
|
/**
|
|
7138
6822
|
* Install the plans & quota panel's stylesheet and return its disposer, for
|
|
7139
|
-
* `ctx.effect` to own. Keyed by its own `data-plugin-css` id, so
|
|
7140
|
-
*
|
|
6823
|
+
* `ctx.effect` to own. Keyed by its own `data-plugin-css` id, so a second
|
|
6824
|
+
* surface asking for it later is a no-op.
|
|
7141
6825
|
*/
|
|
7142
6826
|
function injectPanelCss() {
|
|
7143
6827
|
if (typeof document === "undefined") return () => {};
|
|
@@ -7155,22 +6839,24 @@ window.__ModuleLoader__.load({
|
|
|
7155
6839
|
* Plans & quota panel id. It is the layout's `MainPanelId`: one string shared
|
|
7156
6840
|
* by the `sidebar.footer.action` card and the `main` slot cell, so the card
|
|
7157
6841
|
* selects this panel and nothing else. `dsh-client-ui-layout` is not a
|
|
7158
|
-
* dependency of this bundle
|
|
7159
|
-
*
|
|
6842
|
+
* dependency of this bundle, so its brand is applied at the call site instead
|
|
6843
|
+
* of importing the package.
|
|
7160
6844
|
*/
|
|
7161
6845
|
const PANEL_ID = "commandcode-panel";
|
|
7162
6846
|
/**
|
|
7163
6847
|
* The composer figure's entry id in `conversation.composer.dock`. Its own id,
|
|
7164
|
-
*
|
|
6848
|
+
* never the shipped `stats` cell's: reusing that id would REPLACE the tokens /
|
|
7165
6849
|
* cache-hit / throughput readout rather than inject into it, and that readout
|
|
7166
|
-
* is the harness's to format
|
|
6850
|
+
* is the harness's to format.
|
|
7167
6851
|
*/
|
|
7168
6852
|
const SESSION_COST_ID = "commandcode-session-cost";
|
|
7169
6853
|
/**
|
|
7170
6854
|
* Client plugin body. Gates on `slots`, `locale` and `remote` — never on
|
|
7171
6855
|
* `settingsScope`, whose wrapper service the 0.1.7 settings rewrite removed
|
|
7172
|
-
* (the
|
|
7173
|
-
*
|
|
6856
|
+
* (the scope below speaks the `remote.settings` wire directly), because
|
|
6857
|
+
* gating on a service 0.1.7 does not provide would park EVERY surface below
|
|
6858
|
+
* into silence. `settingsScope` must never reappear in the exported inject
|
|
6859
|
+
* list at the bottom of this file.
|
|
7174
6860
|
*/
|
|
7175
6861
|
function apply(ctx) {
|
|
7176
6862
|
injectPageCss();
|
|
@@ -7212,9 +6898,19 @@ window.__ModuleLoader__.load({
|
|
|
7212
6898
|
ctx.effect(() => () => controller.dispose(), "dsh-commandcode-provider: settings controller");
|
|
7213
6899
|
const store = createSnapshotStore(controller.state());
|
|
7214
6900
|
controller.subscribe(() => store.set(controller.state()));
|
|
7215
|
-
ctx.effect(() =>
|
|
7216
|
-
|
|
7217
|
-
|
|
6901
|
+
ctx.effect(() => {
|
|
6902
|
+
const remote = ctx.remote;
|
|
6903
|
+
const unregisterReference = remote.$on("credentials/reference-updated", () => {
|
|
6904
|
+
controller.refreshCredentials();
|
|
6905
|
+
});
|
|
6906
|
+
const unregisterRecord = remote.$on("credentials/record-updated", () => {
|
|
6907
|
+
controller.refreshCredentials();
|
|
6908
|
+
});
|
|
6909
|
+
return () => {
|
|
6910
|
+
unregisterReference();
|
|
6911
|
+
unregisterRecord();
|
|
6912
|
+
};
|
|
6913
|
+
}, "dsh-commandcode-provider: credential invalidations");
|
|
7218
6914
|
let usageNamespace;
|
|
7219
6915
|
let usageMountError;
|
|
7220
6916
|
let pricesController;
|