@mars-sea/dsh-commandcode-provider 0.14.5 → 0.15.1
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 +59 -0
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/lib/client.js +1952 -839
- package/lib/index.d.ts +62 -3
- package/lib/index.js +312 -91
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -591,7 +591,7 @@ window.__ModuleLoader__.load({
|
|
|
591
591
|
}
|
|
592
592
|
return map;
|
|
593
593
|
}
|
|
594
|
-
const record$
|
|
594
|
+
const record$3 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
595
595
|
const result = () => ({
|
|
596
596
|
config: "none",
|
|
597
597
|
credential: "none",
|
|
@@ -605,16 +605,16 @@ window.__ModuleLoader__.load({
|
|
|
605
605
|
});
|
|
606
606
|
const fieldBaseline = (snapshot, field) => ({
|
|
607
607
|
value: snapshot.value?.[field],
|
|
608
|
-
base: record$
|
|
609
|
-
user: record$
|
|
610
|
-
overridden: Object.hasOwn(record$
|
|
608
|
+
base: record$3(snapshot.base)[field],
|
|
609
|
+
user: record$3(snapshot.user)[field],
|
|
610
|
+
overridden: Object.hasOwn(record$3(snapshot.user), field)
|
|
611
611
|
});
|
|
612
612
|
/** 不用显示文本比较配置;数组顺序与显式覆盖/继承也是写入事实。 */
|
|
613
613
|
function sameValue(a, b) {
|
|
614
614
|
if (Object.is(a, b)) return true;
|
|
615
615
|
if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((value, i) => sameValue(value, b[i]));
|
|
616
616
|
if (a === null || b === null || typeof a !== "object" || typeof b !== "object") return false;
|
|
617
|
-
const left = record$
|
|
617
|
+
const left = record$3(a), right = record$3(b);
|
|
618
618
|
const keys = Object.keys(left);
|
|
619
619
|
return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && sameValue(left[key], right[key]));
|
|
620
620
|
}
|
|
@@ -657,7 +657,7 @@ window.__ModuleLoader__.load({
|
|
|
657
657
|
snapshot.base,
|
|
658
658
|
snapshot.user,
|
|
659
659
|
snapshot.value
|
|
660
|
-
]) for (const id of Object.keys(readVisibility(record$
|
|
660
|
+
]) for (const id of Object.keys(readVisibility(record$3(layer).modelVisibility))) keys.add(id);
|
|
661
661
|
ops.push({
|
|
662
662
|
op: "set",
|
|
663
663
|
path: ["visibleModels"],
|
|
@@ -731,7 +731,7 @@ window.__ModuleLoader__.load({
|
|
|
731
731
|
const raw = this.value("modelAccountRules");
|
|
732
732
|
if (!Array.isArray(raw)) return [];
|
|
733
733
|
return raw.flatMap((item) => {
|
|
734
|
-
const rule = record$
|
|
734
|
+
const rule = record$3(item);
|
|
735
735
|
const models = Array.isArray(rule.models) ? rule.models.filter((id) => typeof id === "string" && id !== "") : [];
|
|
736
736
|
return models.length ? [{
|
|
737
737
|
models,
|
|
@@ -863,7 +863,7 @@ window.__ModuleLoader__.load({
|
|
|
863
863
|
} : { ...account })
|
|
864
864
|
}]);
|
|
865
865
|
} else if (intent.kind === "active") {
|
|
866
|
-
const base = record$
|
|
866
|
+
const base = record$3(this.scope.getSnapshot().base).activeAccount;
|
|
867
867
|
const op = intent.id !== "" || typeof base === "string" && base !== "" ? {
|
|
868
868
|
op: "set",
|
|
869
869
|
path: ["activeAccount"],
|
|
@@ -912,7 +912,7 @@ window.__ModuleLoader__.load({
|
|
|
912
912
|
value: [.../* @__PURE__ */ new Set([...this.cleanupRefs(), intent.ref])]
|
|
913
913
|
}
|
|
914
914
|
];
|
|
915
|
-
if (this.value("activeAccount") === intent.ref) ops.push(record$
|
|
915
|
+
if (this.value("activeAccount") === intent.ref) ops.push(record$3(snapshot.base).activeAccount === intent.ref ? {
|
|
916
916
|
op: "set",
|
|
917
917
|
path: ["activeAccount"],
|
|
918
918
|
value: ""
|
|
@@ -945,8 +945,8 @@ window.__ModuleLoader__.load({
|
|
|
945
945
|
outcome.issue = "closed";
|
|
946
946
|
return;
|
|
947
947
|
}
|
|
948
|
-
const inherited = record$
|
|
949
|
-
if (!(ref === this.defaultRef() || this.accounts().some((account) => account.apiKeyEnv === ref) || Array.isArray(inherited) && inherited.some((account) => record$
|
|
948
|
+
const inherited = record$3(this.scope.getSnapshot().base).accounts;
|
|
949
|
+
if (!(ref === this.defaultRef() || this.accounts().some((account) => account.apiKeyEnv === ref) || Array.isArray(inherited) && inherited.some((account) => record$3(account).apiKeyEnv === ref) || this.rules().some((rule) => rule.account === ref) || this.value("activeAccount") === ref) && this.facts.get(ref)?.configured === true) {
|
|
950
950
|
await this.changeCredential(outcome, ref, void 0);
|
|
951
951
|
if (!writeCompleted(outcome) || outcome.refreshFailed) {
|
|
952
952
|
if (outcome.issue === void 0 && outcome.credential === "confirmed") outcome.issue = "cleanup-pending";
|
|
@@ -995,7 +995,7 @@ window.__ModuleLoader__.load({
|
|
|
995
995
|
* only a generic failure — catching it here names the problem while typing).
|
|
996
996
|
* Decimals pass, like the Host schema's `z.number()`.
|
|
997
997
|
*/
|
|
998
|
-
function numberField$
|
|
998
|
+
function numberField$2(field, bounds) {
|
|
999
999
|
return {
|
|
1000
1000
|
field,
|
|
1001
1001
|
format: (value) => typeof value === "number" ? String(value) : "",
|
|
@@ -1046,7 +1046,7 @@ window.__ModuleLoader__.load({
|
|
|
1046
1046
|
* `max_tokens`"), so no single numeric range can serve both.
|
|
1047
1047
|
*/
|
|
1048
1048
|
function tokenCountField(field, bounds, isValid) {
|
|
1049
|
-
const plain = numberField$
|
|
1049
|
+
const plain = numberField$2(field, bounds);
|
|
1050
1050
|
return {
|
|
1051
1051
|
field,
|
|
1052
1052
|
format: plain.format,
|
|
@@ -1167,7 +1167,7 @@ window.__ModuleLoader__.load({
|
|
|
1167
1167
|
min: MIN_TIMEOUT_SECONDS,
|
|
1168
1168
|
max: MAX_TIMEOUT_SECONDS
|
|
1169
1169
|
}),
|
|
1170
|
-
numberField$
|
|
1170
|
+
numberField$2("transportMaxRetries", {
|
|
1171
1171
|
min: 0,
|
|
1172
1172
|
max: 50
|
|
1173
1173
|
}),
|
|
@@ -1815,6 +1815,19 @@ window.__ModuleLoader__.load({
|
|
|
1815
1815
|
function formatResetAt(ms) {
|
|
1816
1816
|
return ms <= 0 ? "" : new Date(ms).toLocaleString();
|
|
1817
1817
|
}
|
|
1818
|
+
/**
|
|
1819
|
+
* {@link formatResetAt} without the year and seconds ("10/21 18:41"): the
|
|
1820
|
+
* settings page shows several of these per card, and a reset moment never
|
|
1821
|
+
* needs seconds. Empty for an unknown time, like the long form.
|
|
1822
|
+
*/
|
|
1823
|
+
function formatResetAtShort(ms) {
|
|
1824
|
+
return ms <= 0 ? "" : new Date(ms).toLocaleString(void 0, {
|
|
1825
|
+
month: "numeric",
|
|
1826
|
+
day: "numeric",
|
|
1827
|
+
hour: "2-digit",
|
|
1828
|
+
minute: "2-digit"
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1818
1831
|
/** 只有官方汇总与订阅共同确认同一起点,才展示完整账期;旧宿主和部分响应保持未知。 */
|
|
1819
1832
|
function formatUsageBillingPeriod(usageStart, planStart, planEnd) {
|
|
1820
1833
|
if (usageStart === void 0 || planStart !== usageStart || planEnd === void 0 || usageStart <= 0 || planEnd <= usageStart) return "";
|
|
@@ -2433,7 +2446,7 @@ window.__ModuleLoader__.load({
|
|
|
2433
2446
|
* The shared read/validate helpers for the usage report endpoint, prefixed
|
|
2434
2447
|
* so rejection messages name the offending boundary.
|
|
2435
2448
|
*/
|
|
2436
|
-
const { reject: reject$
|
|
2449
|
+
const { reject: reject$2, record: record$2, stringField: stringField$2, numberField: numberField$1, booleanField } = makeBoundaryValidator("commandcode/report result:");
|
|
2437
2450
|
/**
|
|
2438
2451
|
* Parse one quota window, or undefined when the frame carries no such window.
|
|
2439
2452
|
*
|
|
@@ -2444,12 +2457,12 @@ window.__ModuleLoader__.load({
|
|
|
2444
2457
|
*/
|
|
2445
2458
|
function windowLimit(value, field) {
|
|
2446
2459
|
if (value === void 0) return void 0;
|
|
2447
|
-
const source = record$
|
|
2460
|
+
const source = record$2(value, field);
|
|
2448
2461
|
return {
|
|
2449
|
-
used: numberField(source, "used", `${field}.used`),
|
|
2450
|
-
cap: numberField(source, "cap", `${field}.cap`),
|
|
2462
|
+
used: numberField$1(source, "used", `${field}.used`),
|
|
2463
|
+
cap: numberField$1(source, "cap", `${field}.cap`),
|
|
2451
2464
|
exceeded: booleanField(source, "exceeded", `${field}.exceeded`),
|
|
2452
|
-
resetAt: numberField(source, "resetAt", `${field}.resetAt`)
|
|
2465
|
+
resetAt: numberField$1(source, "resetAt", `${field}.resetAt`)
|
|
2453
2466
|
};
|
|
2454
2467
|
}
|
|
2455
2468
|
/**
|
|
@@ -2458,44 +2471,44 @@ window.__ModuleLoader__.load({
|
|
|
2458
2471
|
* malformed frame fails the boundary instead of rendering garbage.
|
|
2459
2472
|
*/
|
|
2460
2473
|
function parseUsageReport(value) {
|
|
2461
|
-
const source = record$
|
|
2474
|
+
const source = record$2(value, "report");
|
|
2462
2475
|
const failures = source.failures;
|
|
2463
|
-
if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== "string")) reject$
|
|
2476
|
+
if (!Array.isArray(failures) || failures.some((entry) => typeof entry !== "string")) reject$2("failures");
|
|
2464
2477
|
const report = { failures };
|
|
2465
2478
|
if (source.blocked !== void 0) {
|
|
2466
2479
|
const blocked = source.blocked;
|
|
2467
2480
|
if (blocked === "invalid-key" || blocked === "service-unavailable" || blocked === "invalid-response" || blocked === "network") report.blocked = blocked;
|
|
2468
|
-
else reject$
|
|
2481
|
+
else reject$2("blocked");
|
|
2469
2482
|
}
|
|
2470
2483
|
if (source.account !== void 0) {
|
|
2471
|
-
const account = record$
|
|
2484
|
+
const account = record$2(source.account, "account");
|
|
2472
2485
|
report.account = {
|
|
2473
|
-
id: stringField$
|
|
2474
|
-
name: stringField$
|
|
2475
|
-
userName: stringField$
|
|
2486
|
+
id: stringField$2(account, "id", "account.id"),
|
|
2487
|
+
name: stringField$2(account, "name", "account.name"),
|
|
2488
|
+
userName: stringField$2(account, "userName", "account.userName")
|
|
2476
2489
|
};
|
|
2477
2490
|
}
|
|
2478
2491
|
if (source.usage !== void 0) {
|
|
2479
|
-
const usage = record$
|
|
2492
|
+
const usage = record$2(source.usage, "usage");
|
|
2480
2493
|
report.usage = {
|
|
2481
|
-
totalCount: numberField(usage, "totalCount", "usage.totalCount"),
|
|
2482
|
-
totalCost: numberField(usage, "totalCost", "usage.totalCost"),
|
|
2483
|
-
successRate: numberField(usage, "successRate", "usage.successRate"),
|
|
2484
|
-
completedCount: numberField(usage, "completedCount", "usage.completedCount"),
|
|
2485
|
-
failedCount: numberField(usage, "failedCount", "usage.failedCount"),
|
|
2486
|
-
totalTokensIn: numberField(usage, "totalTokensIn", "usage.totalTokensIn"),
|
|
2487
|
-
totalTokensOut: numberField(usage, "totalTokensOut", "usage.totalTokensOut"),
|
|
2488
|
-
totalCredits: numberField(usage, "totalCredits", "usage.totalCredits"),
|
|
2489
|
-
periodBasis: stringField$
|
|
2494
|
+
totalCount: numberField$1(usage, "totalCount", "usage.totalCount"),
|
|
2495
|
+
totalCost: numberField$1(usage, "totalCost", "usage.totalCost"),
|
|
2496
|
+
successRate: numberField$1(usage, "successRate", "usage.successRate"),
|
|
2497
|
+
completedCount: numberField$1(usage, "completedCount", "usage.completedCount"),
|
|
2498
|
+
failedCount: numberField$1(usage, "failedCount", "usage.failedCount"),
|
|
2499
|
+
totalTokensIn: numberField$1(usage, "totalTokensIn", "usage.totalTokensIn"),
|
|
2500
|
+
totalTokensOut: numberField$1(usage, "totalTokensOut", "usage.totalTokensOut"),
|
|
2501
|
+
totalCredits: numberField$1(usage, "totalCredits", "usage.totalCredits"),
|
|
2502
|
+
periodBasis: stringField$2(usage, "periodBasis", "usage.periodBasis")
|
|
2490
2503
|
};
|
|
2491
|
-
if (usage.periodStart !== void 0) report.usage.periodStart = numberField(usage, "periodStart", "usage.periodStart");
|
|
2504
|
+
if (usage.periodStart !== void 0) report.usage.periodStart = numberField$1(usage, "periodStart", "usage.periodStart");
|
|
2492
2505
|
}
|
|
2493
2506
|
if (source.credits !== void 0) {
|
|
2494
|
-
const credits = record$
|
|
2507
|
+
const credits = record$2(source.credits, "credits");
|
|
2495
2508
|
const parsed = {
|
|
2496
|
-
monthlyCredits: numberField(credits, "monthlyCredits", "credits.monthlyCredits"),
|
|
2497
|
-
purchasedCredits: numberField(credits, "purchasedCredits", "credits.purchasedCredits"),
|
|
2498
|
-
freeCredits: numberField(credits, "freeCredits", "credits.freeCredits")
|
|
2509
|
+
monthlyCredits: numberField$1(credits, "monthlyCredits", "credits.monthlyCredits"),
|
|
2510
|
+
purchasedCredits: numberField$1(credits, "purchasedCredits", "credits.purchasedCredits"),
|
|
2511
|
+
freeCredits: numberField$1(credits, "freeCredits", "credits.freeCredits")
|
|
2499
2512
|
};
|
|
2500
2513
|
if (credits.monthlyReported !== void 0) parsed.monthlyReported = booleanField(credits, "monthlyReported", "credits.monthlyReported");
|
|
2501
2514
|
for (const flag of ["purchasedReported", "freeReported"]) if (credits[flag] !== void 0) parsed[flag] = booleanField(credits, flag, `credits.${flag}`);
|
|
@@ -2506,38 +2519,38 @@ window.__ModuleLoader__.load({
|
|
|
2506
2519
|
report.credits = parsed;
|
|
2507
2520
|
}
|
|
2508
2521
|
if (source.plan !== void 0) {
|
|
2509
|
-
const plan = record$
|
|
2522
|
+
const plan = record$2(source.plan, "plan");
|
|
2510
2523
|
const monthly = plan.monthlyCredits;
|
|
2511
|
-
if (monthly !== null && (typeof monthly !== "number" || !Number.isFinite(monthly))) reject$
|
|
2524
|
+
if (monthly !== null && (typeof monthly !== "number" || !Number.isFinite(monthly))) reject$2("plan.monthlyCredits");
|
|
2512
2525
|
report.plan = {
|
|
2513
|
-
planId: stringField$
|
|
2514
|
-
name: stringField$
|
|
2515
|
-
status: stringField$
|
|
2526
|
+
planId: stringField$2(plan, "planId", "plan.planId"),
|
|
2527
|
+
name: stringField$2(plan, "name", "plan.name"),
|
|
2528
|
+
status: stringField$2(plan, "status", "plan.status"),
|
|
2516
2529
|
monthlyCredits: monthly,
|
|
2517
|
-
currentPeriodEnd: numberField(plan, "currentPeriodEnd", "plan.currentPeriodEnd")
|
|
2530
|
+
currentPeriodEnd: numberField$1(plan, "currentPeriodEnd", "plan.currentPeriodEnd")
|
|
2518
2531
|
};
|
|
2519
|
-
if (plan.currentPeriodStart !== void 0) report.plan.currentPeriodStart = numberField(plan, "currentPeriodStart", "plan.currentPeriodStart");
|
|
2532
|
+
if (plan.currentPeriodStart !== void 0) report.plan.currentPeriodStart = numberField$1(plan, "currentPeriodStart", "plan.currentPeriodStart");
|
|
2520
2533
|
}
|
|
2521
2534
|
return report;
|
|
2522
2535
|
}
|
|
2523
2536
|
/** Parse one untrusted boundary value into a {@link CommandCodeAccountUsage}. */
|
|
2524
2537
|
function parseAccountUsage(value) {
|
|
2525
|
-
const source = record$
|
|
2538
|
+
const source = record$2(value, "account");
|
|
2526
2539
|
return {
|
|
2527
|
-
id: stringField$
|
|
2528
|
-
label: stringField$
|
|
2540
|
+
id: stringField$2(source, "id", "account.id"),
|
|
2541
|
+
label: stringField$2(source, "label", "account.label"),
|
|
2529
2542
|
configured: booleanField(source, "configured", "account.configured"),
|
|
2530
2543
|
active: booleanField(source, "active", "account.active"),
|
|
2531
|
-
mark: stringField$
|
|
2532
|
-
cooldownUntil: numberField(source, "cooldownUntil", "account.cooldownUntil"),
|
|
2544
|
+
mark: stringField$2(source, "mark", "account.mark"),
|
|
2545
|
+
cooldownUntil: numberField$1(source, "cooldownUntil", "account.cooldownUntil"),
|
|
2533
2546
|
report: parseUsageReport(source.report)
|
|
2534
2547
|
};
|
|
2535
2548
|
}
|
|
2536
2549
|
/** Parse the wire result into a {@link CommandCodeAccountsReport}. */
|
|
2537
2550
|
function parseAccountsReport(value) {
|
|
2538
|
-
const accounts = record$
|
|
2551
|
+
const accounts = record$2(value, "result").accounts;
|
|
2539
2552
|
if (Array.isArray(accounts)) return { accounts: accounts.map(parseAccountUsage) };
|
|
2540
|
-
return reject$
|
|
2553
|
+
return reject$2("accounts");
|
|
2541
2554
|
}
|
|
2542
2555
|
/** The Client-face contribution mounted on `ctx.remote`. */
|
|
2543
2556
|
const USAGE_REMOTE_CONTRIBUTION = {
|
|
@@ -2641,6 +2654,34 @@ window.__ModuleLoader__.load({
|
|
|
2641
2654
|
descriptors: [makeRemoteDescriptor(PRICES_ENDPOINT, "prices", `${USAGE_REMOTE_PACKAGE}#CommandCodePriceTable`, { parse: parsePriceTable })]
|
|
2642
2655
|
};
|
|
2643
2656
|
//#endregion
|
|
2657
|
+
//#region src/service-probe-wire.ts
|
|
2658
|
+
/** Canonical `<namespace>/<method>` endpoint of the probe Remote. */
|
|
2659
|
+
const PROBE_ENDPOINT = "commandcode/probe";
|
|
2660
|
+
const OUTCOMES = [
|
|
2661
|
+
"ok",
|
|
2662
|
+
"http-error",
|
|
2663
|
+
"timeout",
|
|
2664
|
+
"unreachable"
|
|
2665
|
+
];
|
|
2666
|
+
const { reject: reject$1, record: record$1, stringField: stringField$1, numberField } = makeBoundaryValidator("commandcode/probe result:");
|
|
2667
|
+
/** Strict result codec, shared verbatim by the Host registration and Client mount. */
|
|
2668
|
+
function parseProbeResult(value) {
|
|
2669
|
+
const source = record$1(value, "result");
|
|
2670
|
+
const outcome = stringField$1(source, "outcome", "outcome");
|
|
2671
|
+
if (!OUTCOMES.includes(outcome)) reject$1("outcome");
|
|
2672
|
+
return {
|
|
2673
|
+
outcome,
|
|
2674
|
+
status: numberField(source, "status", "status"),
|
|
2675
|
+
latencyMs: numberField(source, "latencyMs", "latencyMs"),
|
|
2676
|
+
checkedAt: numberField(source, "checkedAt", "checkedAt")
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
2679
|
+
/** The Client-face contribution mounted on `ctx.remote`. */
|
|
2680
|
+
const PROBE_REMOTE_CONTRIBUTION = {
|
|
2681
|
+
package: REMOTE_PACKAGE,
|
|
2682
|
+
descriptors: [makeRemoteDescriptor(PROBE_ENDPOINT, "probe", `${REMOTE_PACKAGE}#CommandCodeProbeResult`, { parse: parseProbeResult })]
|
|
2683
|
+
};
|
|
2684
|
+
//#endregion
|
|
2644
2685
|
//#region src/login-wire.ts
|
|
2645
2686
|
/** The canonical endpoint paths of the three login Remotes. */
|
|
2646
2687
|
const LOGIN_BEGIN_ENDPOINT = "commandcode/loginBegin";
|
|
@@ -3083,37 +3124,46 @@ window.__ModuleLoader__.load({
|
|
|
3083
3124
|
openAnalytics: "查看模型用量、成本与性能分析",
|
|
3084
3125
|
nav: "Command Code",
|
|
3085
3126
|
title: "Command Code",
|
|
3086
|
-
intro: "
|
|
3127
|
+
intro: "账户操作立即生效;其余改动点底部「保存」。密钥仅存于本机凭据服务,不回显。",
|
|
3087
3128
|
apiKey: "API 密钥",
|
|
3088
3129
|
apiKeyHint: "在 commandcode.ai 控制台创建。留空保存不会覆盖已存储的密钥。",
|
|
3089
3130
|
apiKeySet: "已配置",
|
|
3090
3131
|
apiKeyUnset: "未配置",
|
|
3091
3132
|
apiKeyLocked: "密钥由只读来源提供",
|
|
3092
3133
|
apiBase: "API 地址",
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
streamIdleTimeoutMsHint: "生成流停滞多久视为断连;默认 300 秒(长思考模型可静默数分钟,默认值刻意放宽)。",
|
|
3134
|
+
requestTimeoutMs: "请求超时",
|
|
3135
|
+
requestTimeoutMsHint: "等待首个字节的超时,默认 300 秒;Provider API 要等上游模型吐出第一个 token 才返回,上游慢时可调高。",
|
|
3136
|
+
streamIdleTimeoutMs: "流空闲超时",
|
|
3137
|
+
streamIdleTimeoutMsHint: "生成流停滞多久视为断连,默认 300 秒(长思考模型可能静默数分钟)。",
|
|
3098
3138
|
transportMaxRetries: "网络失败重试次数",
|
|
3099
|
-
transportMaxRetriesHint: "
|
|
3139
|
+
transportMaxRetriesHint: "连接失败时自动重试的次数,默认 5 次(约 15 秒);填 0 不重试,限流与 5xx 的重试不受影响。",
|
|
3100
3140
|
offloadSeenImagesForCache: "已看过的图片不再重复发送",
|
|
3101
|
-
offloadSeenImagesForCacheHint: "仅 CLI
|
|
3141
|
+
offloadSeenImagesForCacheHint: "仅 CLI 传输。模型回复过的旧图片改用文字占位,减少新增图片时的缓存回退;重看需重新读取或附加。",
|
|
3102
3142
|
advancedSettings: "高级设置",
|
|
3103
3143
|
advancedSettingsHint: "API 地址和网络参数,一般无需修改。",
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3144
|
+
groupOverriddenOne: "已自定义 1 项",
|
|
3145
|
+
groupOverriddenMany: "已自定义 {count} 项",
|
|
3146
|
+
groupInvalid: "有未填好的数字",
|
|
3147
|
+
saveLocate: "定位",
|
|
3148
|
+
accountsSummaryOne: "1 个账户",
|
|
3149
|
+
accountsSummaryMany: "{count} 个账户",
|
|
3150
|
+
accountsSummaryIssues: "{count} 个异常",
|
|
3151
|
+
visibleModelsSummary: "白名单 {count} 个",
|
|
3152
|
+
visibleModelsSummaryAll: "显示全部模型",
|
|
3153
|
+
zdrSummaryOn: "ZDR 开启",
|
|
3154
|
+
zdrSummaryOff: "ZDR 关闭",
|
|
3155
|
+
webSearchSummaryOn: "联网搜索开启",
|
|
3156
|
+
webSearchSummaryOff: "联网搜索关闭",
|
|
3107
3157
|
filterModelsByPlan: "隐藏套餐外模型",
|
|
3108
3158
|
filterModelsByPlanHint: "只显示套餐内模型;按需余额账户仍显示全部。",
|
|
3109
3159
|
webSearch: "用 Command Code 承载联网搜索",
|
|
3110
|
-
webSearchHint: "
|
|
3160
|
+
webSearchHint: "用同一密钥承载 dsh 的 web_search;「网页搜索」里已指定其他后端时本开关不生效。",
|
|
3111
3161
|
showSidebarQuota: "在侧边栏显示额度卡片",
|
|
3112
|
-
showSidebarQuotaHint: "
|
|
3162
|
+
showSidebarQuotaHint: "在侧边栏底部显示套餐与额度卡片,点击打开完整仪表盘;关闭时不在后台刷新用量。",
|
|
3113
3163
|
zdr: "零数据保留(ZDR)",
|
|
3114
3164
|
zdrHint: "仅使用不留存、不训练的上游;可用模型可能更少且价格通常更高。",
|
|
3115
3165
|
accountsTitle: "账户",
|
|
3116
|
-
accountsHint: "
|
|
3166
|
+
accountsHint: "可以添加多个账户:当前账户达到用量限额或密钥失效时,请求会自动切换到下一个。",
|
|
3117
3167
|
accountAdd: "添加账户",
|
|
3118
3168
|
accountDefault: "默认账户",
|
|
3119
3169
|
modelSearchPlaceholder: "搜索模型…",
|
|
@@ -3122,16 +3172,16 @@ window.__ModuleLoader__.load({
|
|
|
3122
3172
|
modelAllowance: "${amount}/月",
|
|
3123
3173
|
modelAllowanceTitle: "该模型每月可用的额度(美元)。套餐内所有模型共用同一个月度额度池,这不是额外赠送的额度。",
|
|
3124
3174
|
visibleModelsTitle: "模型白名单",
|
|
3125
|
-
visibleModelsHint: "
|
|
3175
|
+
visibleModelsHint: "模型选择器只列出勾选的模型,都不勾选则显示全部;网页与终端共用这份选择。",
|
|
3126
3176
|
visibleModelsPick: "选择要保留的模型…",
|
|
3127
3177
|
visibleModelsCount: "已选 {count} 个模型",
|
|
3128
3178
|
visibleModelsShowAll: "显示全部",
|
|
3129
3179
|
visibleModelsStaleHint: "有 {count} 个已选模型在目录中找不到了(可能已下架),不影响其他模型;可清理或保留。",
|
|
3130
3180
|
visibleModelsCleanStale: "清理失效({count})",
|
|
3131
3181
|
contextWindow: "自定义上下文长度",
|
|
3132
|
-
contextWindowHint: "
|
|
3182
|
+
contextWindowHint: "覆盖目录公布的上下文窗口,影响上下文计量与自动压缩;留空跟随目录,支持 32K、1M。",
|
|
3133
3183
|
contextOverridesTitle: "按模型覆盖",
|
|
3134
|
-
contextOverridesHint: "
|
|
3184
|
+
contextOverridesHint: "为单个模型设置上下文长度,优先于上面的全局值;只能选白名单中的模型。",
|
|
3135
3185
|
contextOverrideAdd: "添加模型",
|
|
3136
3186
|
contextOverrideRemove: "移除该模型的上下文覆盖",
|
|
3137
3187
|
contextOverrideModel: "模型",
|
|
@@ -3141,12 +3191,17 @@ window.__ModuleLoader__.load({
|
|
|
3141
3191
|
contextWindowTooLarge: "上下文长度不能大于 10,000,000",
|
|
3142
3192
|
contextWindowInvalid: "请输入有效的整数 token 数",
|
|
3143
3193
|
maxOutputTokens: "单轮输出上限",
|
|
3144
|
-
maxOutputTokensHint: "
|
|
3194
|
+
maxOutputTokensHint: "留空按模型推导;0=不发送该字段(仅 CLI 与 OpenAI,Claude 的 Messages 端点必填)。上限 131072,支持 64K。",
|
|
3145
3195
|
maxOutputTokensTooSmall: "输出上限不能小于 0(0 表示不发送该字段)",
|
|
3146
3196
|
maxOutputTokensTooLarge: "输出上限不能大于 131072(网关上限)",
|
|
3147
3197
|
maxOutputTokensInvalid: "请输入 0 或有效的整数 token 数",
|
|
3148
|
-
overridden: "
|
|
3198
|
+
overridden: "已自定义",
|
|
3149
3199
|
reset: "重置",
|
|
3200
|
+
unitSeconds: "秒",
|
|
3201
|
+
unitTokens: "tokens",
|
|
3202
|
+
unitRetries: "次",
|
|
3203
|
+
placeholderCatalog: "跟随目录",
|
|
3204
|
+
placeholderAuto: "自动",
|
|
3150
3205
|
invalidNumber: "无效数字",
|
|
3151
3206
|
numberTooSmall: "重试次数不能小于 0",
|
|
3152
3207
|
numberTooLarge: "重试次数不能大于 50",
|
|
@@ -3192,12 +3247,12 @@ window.__ModuleLoader__.load({
|
|
|
3192
3247
|
usageTokens: "Token",
|
|
3193
3248
|
usageTokensIn: "入",
|
|
3194
3249
|
usageTokensOut: "出",
|
|
3195
|
-
usageMonthly: "月额度",
|
|
3196
3250
|
usagePurchased: "已购",
|
|
3197
3251
|
usageFree: "赠送",
|
|
3198
3252
|
usageFiveHour: "5 小时窗口",
|
|
3199
3253
|
usageWeekly: "每周窗口",
|
|
3200
3254
|
usageMonthlyLeft: "月额度剩余",
|
|
3255
|
+
usageMonthlyDepleted: "月额度已用完,已购与赠送余额将无法使用。",
|
|
3201
3256
|
usageExceeded: "已超限",
|
|
3202
3257
|
usageReset: "重置于",
|
|
3203
3258
|
usagePartial: "部分端点数据不可用",
|
|
@@ -3222,7 +3277,7 @@ window.__ModuleLoader__.load({
|
|
|
3222
3277
|
loginButton: "登录 Command Code",
|
|
3223
3278
|
loginStarting: "正在启动本地回调服务…",
|
|
3224
3279
|
loginWaiting: "等待在浏览器中完成授权;若页面未自动打开,请点击授权链接。",
|
|
3225
|
-
loginOpenLink: "打开授权页面
|
|
3280
|
+
loginOpenLink: "打开授权页面",
|
|
3226
3281
|
loginCancel: "取消登录",
|
|
3227
3282
|
loginSuccess: "已登录为",
|
|
3228
3283
|
loginUnavailable: "此环境暂不支持登录流程,请手动粘贴密钥。",
|
|
@@ -3237,7 +3292,7 @@ window.__ModuleLoader__.load({
|
|
|
3237
3292
|
cardRouteActive: "已启用",
|
|
3238
3293
|
cardLoadingHint: "正在读取 Command Code 配置…",
|
|
3239
3294
|
cardRegistrationHint: "此卡片由 Command Code 插件提供,正在等待设置页装配,稍后即可显示完整内容。",
|
|
3240
|
-
accountsRotationHint: "
|
|
3295
|
+
accountsRotationHint: "当前账户达到限额或密钥失效时,请求会按列表顺序切换到下一个可用账户。",
|
|
3241
3296
|
accountModeAuto: "使用方式:自动切换(按列表顺序)",
|
|
3242
3297
|
accountModePinned: "使用方式:固定使用「{name}」,不可用时仍会自动切换",
|
|
3243
3298
|
accountStatusPinned: "已固定",
|
|
@@ -3260,6 +3315,8 @@ window.__ModuleLoader__.load({
|
|
|
3260
3315
|
accountAddPaste: "粘贴密钥",
|
|
3261
3316
|
accountAddConfirm: "添加",
|
|
3262
3317
|
accountAddCancel: "取消开通",
|
|
3318
|
+
accountAddStart: "开始登录",
|
|
3319
|
+
accountAddMethod: "添加方式",
|
|
3263
3320
|
accountAddLinkHint: "若登录页面未自动打开,请点击下方链接。",
|
|
3264
3321
|
accountAddOpenLink: "打开浏览器登录",
|
|
3265
3322
|
accountNamePlaceholder: "备注名(可选,网页登录时默认使用账户名)",
|
|
@@ -3273,15 +3330,45 @@ window.__ModuleLoader__.load({
|
|
|
3273
3330
|
accountEnrollmentCleanupRetry: "重试清理",
|
|
3274
3331
|
accountRefSeparator: ":",
|
|
3275
3332
|
accountModels: "专用模型",
|
|
3276
|
-
accountModelsHint: "
|
|
3333
|
+
accountModelsHint: "选中的模型优先由此账户处理,不可用时仍会自动切换;一个模型只归属一个账户。",
|
|
3277
3334
|
accountModelOwner: "属于 {name}",
|
|
3278
3335
|
modelPick: "选择模型…",
|
|
3279
3336
|
modelCount: "已选 {count} 个模型",
|
|
3280
3337
|
modelCatalogFailed: "模型目录获取失败,暂时无法选择模型;已保存的设置仍会生效。",
|
|
3281
3338
|
modelsTitle: "模型与上下文",
|
|
3282
|
-
modelsInvalid: "模型与上下文中有未填好的数字,请展开修正后再保存。",
|
|
3283
3339
|
privacyTitle: "隐私与安全",
|
|
3284
3340
|
integrationsTitle: "集成与显示",
|
|
3341
|
+
serviceStatusTitle: "服务状态",
|
|
3342
|
+
serviceStatusHint: "官方数据来自状态页的公开记录,仅在状态变化或每日汇总时发布;本机连通由宿主刚探测。",
|
|
3343
|
+
serviceStatusChecking: "正在检查…",
|
|
3344
|
+
serviceStatusUp: "服务正常",
|
|
3345
|
+
serviceStatusDegraded: "部分降级",
|
|
3346
|
+
serviceStatusDown: "服务中断",
|
|
3347
|
+
serviceStatusUnknown: "状态未知",
|
|
3348
|
+
serviceStatusOfficial: "官方",
|
|
3349
|
+
serviceStatusLocal: "本机",
|
|
3350
|
+
serviceStatusUptime: "可用率 {value}",
|
|
3351
|
+
serviceStatusBadgeLocalHttp: "本机连接异常",
|
|
3352
|
+
serviceStatusBadgeLocalTimeout: "本机连接超时",
|
|
3353
|
+
serviceStatusBadgeLocalUnreachable: "本机无法连接",
|
|
3354
|
+
serviceStatusUptimeWeek: "7 天 {value}",
|
|
3355
|
+
serviceStatusUptimeMonth: "30 天 {value}",
|
|
3356
|
+
serviceStatusResponseWeek: "平均响应 {value}",
|
|
3357
|
+
serviceStatusUpdatedJustNow: "刚刚更新",
|
|
3358
|
+
serviceStatusUpdatedMinutes: "{count} 分钟前更新",
|
|
3359
|
+
serviceStatusUpdatedHours: "{count} 小时前更新",
|
|
3360
|
+
serviceStatusUpdatedDays: "{count} 天前更新",
|
|
3361
|
+
serviceStatusUpdatedUnknown: "更新时间未知",
|
|
3362
|
+
serviceStatusLag: "官方数据仅在状态变化或每日汇总时发布,可能滞后数小时。",
|
|
3363
|
+
serviceStatusLocalChecking: "正在探测…",
|
|
3364
|
+
serviceStatusLocalOk: "连通正常 · {latency} ms",
|
|
3365
|
+
serviceStatusLocalHttp: "连接异常(HTTP {status})",
|
|
3366
|
+
serviceStatusLocalTimeout: "连接超时",
|
|
3367
|
+
serviceStatusLocalUnreachable: "无法连接",
|
|
3368
|
+
serviceStatusLocalUnavailable: "未知(宿主未提供探测)",
|
|
3369
|
+
serviceStatusStale: "无法获取状态数据,以下为上次成功获取的结果。",
|
|
3370
|
+
serviceStatusUnavailable: "无法获取状态数据。",
|
|
3371
|
+
serviceStatusOpen: "打开状态页",
|
|
3285
3372
|
enrollmentCreating: "正在创建账号",
|
|
3286
3373
|
enrollmentWaiting: "等待浏览器登录",
|
|
3287
3374
|
enrollmentWriting: "正在保存凭据",
|
|
@@ -3309,37 +3396,46 @@ window.__ModuleLoader__.load({
|
|
|
3309
3396
|
openAnalytics: "View model usage, cost and performance",
|
|
3310
3397
|
nav: "Command Code",
|
|
3311
3398
|
title: "Command Code",
|
|
3312
|
-
intro: "Account actions apply immediately; other
|
|
3399
|
+
intro: "Account actions apply immediately; other changes need Save below. The key stays in the local credential service and is never echoed.",
|
|
3313
3400
|
apiKey: "API key",
|
|
3314
3401
|
apiKeyHint: "Create one in the commandcode.ai console. Saving with this field blank keeps the stored key.",
|
|
3315
3402
|
apiKeySet: "Configured",
|
|
3316
3403
|
apiKeyUnset: "Not configured",
|
|
3317
3404
|
apiKeyLocked: "Key provided by a read-only source",
|
|
3318
3405
|
apiBase: "API base URL",
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
streamIdleTimeoutMsHint: "How long a stalled stream is treated as dead; default 300 s (deliberately generous — long-thinking models can stay silent for minutes).",
|
|
3406
|
+
requestTimeoutMs: "Request timeout",
|
|
3407
|
+
requestTimeoutMsHint: "Wait for the first response byte; default 300 s. The Provider API route answers only after the upstream’s first token, so raise it for a slow upstream.",
|
|
3408
|
+
streamIdleTimeoutMs: "Stream idle timeout",
|
|
3409
|
+
streamIdleTimeoutMsHint: "How long a stalled stream counts as dead; default 300 s (long-thinking models can go quiet for minutes).",
|
|
3324
3410
|
transportMaxRetries: "Transport retries",
|
|
3325
|
-
transportMaxRetriesHint: "
|
|
3411
|
+
transportMaxRetriesHint: "Automatic retries after a failed connection; default 5 (~15 s in all). 0 disables them; rate limits and 5xx keep their own retries.",
|
|
3326
3412
|
offloadSeenImagesForCache: "Stop replaying images already seen",
|
|
3327
|
-
offloadSeenImagesForCacheHint: "CLI transport only.
|
|
3413
|
+
offloadSeenImagesForCacheHint: "CLI transport only. Images the model already answered become text placeholders, so a new image no longer rolls back the cache; to see one again, reread or reattach it.",
|
|
3328
3414
|
advancedSettings: "Advanced",
|
|
3329
3415
|
advancedSettingsHint: "API base URL and network limits; usually leave as-is.",
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3416
|
+
groupOverriddenOne: "1 customized",
|
|
3417
|
+
groupOverriddenMany: "{count} customized",
|
|
3418
|
+
groupInvalid: "Needs a fix",
|
|
3419
|
+
saveLocate: "Show",
|
|
3420
|
+
accountsSummaryOne: "1 account",
|
|
3421
|
+
accountsSummaryMany: "{count} accounts",
|
|
3422
|
+
accountsSummaryIssues: "{count} need attention",
|
|
3423
|
+
visibleModelsSummary: "{count} allowlisted",
|
|
3424
|
+
visibleModelsSummaryAll: "All models shown",
|
|
3425
|
+
zdrSummaryOn: "ZDR on",
|
|
3426
|
+
zdrSummaryOff: "ZDR off",
|
|
3427
|
+
webSearchSummaryOn: "Web search on",
|
|
3428
|
+
webSearchSummaryOff: "Web search off",
|
|
3333
3429
|
filterModelsByPlan: "Hide out-of-plan models",
|
|
3334
3430
|
filterModelsByPlanHint: "Show only models in your plan; on-demand credit accounts still see the full catalog.",
|
|
3335
3431
|
webSearch: "Serve dsh web search with Command Code",
|
|
3336
|
-
webSearchHint: "Use the same key for dsh web search
|
|
3432
|
+
webSearchHint: "Use the same key for dsh web search. No effect while the Web search settings pin another backend.",
|
|
3337
3433
|
showSidebarQuota: "Show the quota card in the sidebar",
|
|
3338
|
-
showSidebarQuotaHint: "Show a plan and quota card at the bottom of the sidebar that opens the full dashboard
|
|
3434
|
+
showSidebarQuotaHint: "Show a plan and quota card at the bottom of the sidebar that opens the full dashboard; while off, nothing refreshes in the background.",
|
|
3339
3435
|
zdr: "Zero data retention (ZDR)",
|
|
3340
3436
|
zdrHint: "Use only upstreams that retain no data and do not train on requests; availability and pricing may differ.",
|
|
3341
3437
|
accountsTitle: "Accounts",
|
|
3342
|
-
accountsHint: "
|
|
3438
|
+
accountsHint: "Add more accounts and requests switch to the next one when the current account hits its usage limit or its key stops working.",
|
|
3343
3439
|
accountAdd: "Add account",
|
|
3344
3440
|
accountDefault: "Default account",
|
|
3345
3441
|
modelSearchPlaceholder: "Search models…",
|
|
@@ -3348,16 +3444,16 @@ window.__ModuleLoader__.load({
|
|
|
3348
3444
|
modelAllowance: "${amount}/mo",
|
|
3349
3445
|
modelAllowanceTitle: "Monthly usage this model can draw, in USD. Every model shares one monthly pool — this is not extra credit on top of the plan.",
|
|
3350
3446
|
visibleModelsTitle: "Model allowlist",
|
|
3351
|
-
visibleModelsHint: "
|
|
3447
|
+
visibleModelsHint: "Model pickers list only the checked models; check none to show all. Web and terminal share this selection.",
|
|
3352
3448
|
visibleModelsPick: "Select models to keep…",
|
|
3353
3449
|
visibleModelsCount: "{count} model(s) selected",
|
|
3354
3450
|
visibleModelsShowAll: "Show all",
|
|
3355
3451
|
visibleModelsStaleHint: "{count} selected model(s) are no longer in the catalog (possibly retired); other models are unaffected. Clean them up or keep them.",
|
|
3356
3452
|
visibleModelsCleanStale: "Clean stale ({count})",
|
|
3357
3453
|
contextWindow: "Custom context length",
|
|
3358
|
-
contextWindowHint: "Overrides the context window
|
|
3454
|
+
contextWindowHint: "Overrides the catalog’s context window; the context meter and auto-compaction follow it. Empty follows the catalog; 32K or 1M accepted.",
|
|
3359
3455
|
contextOverridesTitle: "Per-model overrides",
|
|
3360
|
-
contextOverridesHint: "Set
|
|
3456
|
+
contextOverridesHint: "Set one model’s context length; it wins over the global value above. Only allowlisted models can be picked.",
|
|
3361
3457
|
contextOverrideAdd: "Add model",
|
|
3362
3458
|
contextOverrideRemove: "Remove this model’s context override",
|
|
3363
3459
|
contextOverrideModel: "Model",
|
|
@@ -3367,12 +3463,17 @@ window.__ModuleLoader__.load({
|
|
|
3367
3463
|
contextWindowTooLarge: "Context length must not exceed 10,000,000",
|
|
3368
3464
|
contextWindowInvalid: "Enter a valid whole-token count",
|
|
3369
3465
|
maxOutputTokens: "Output limit per turn",
|
|
3370
|
-
maxOutputTokensHint: "Empty derives it from the model
|
|
3466
|
+
maxOutputTokensHint: "Empty derives it from the model. 0 omits the field (CLI and OpenAI only; Claude’s Messages endpoint requires it). Capped at 131,072; 64K accepted.",
|
|
3371
3467
|
maxOutputTokensTooSmall: "Output limit must be at least 0 (0 omits the field)",
|
|
3372
3468
|
maxOutputTokensTooLarge: "Output limit must not exceed 131,072 (the gateway cap)",
|
|
3373
3469
|
maxOutputTokensInvalid: "Enter 0 or a valid whole-token count",
|
|
3374
|
-
overridden: "
|
|
3470
|
+
overridden: "Customized",
|
|
3375
3471
|
reset: "Reset",
|
|
3472
|
+
unitSeconds: "s",
|
|
3473
|
+
unitTokens: "tokens",
|
|
3474
|
+
unitRetries: "times",
|
|
3475
|
+
placeholderCatalog: "Catalog",
|
|
3476
|
+
placeholderAuto: "Auto",
|
|
3376
3477
|
invalidNumber: "Invalid number",
|
|
3377
3478
|
numberTooSmall: "Retries must be at least 0",
|
|
3378
3479
|
numberTooLarge: "Retries must not exceed 50",
|
|
@@ -3418,12 +3519,12 @@ window.__ModuleLoader__.load({
|
|
|
3418
3519
|
usageTokens: "Tokens",
|
|
3419
3520
|
usageTokensIn: "in",
|
|
3420
3521
|
usageTokensOut: "out",
|
|
3421
|
-
usageMonthly: "Monthly",
|
|
3422
3522
|
usagePurchased: "Purchased",
|
|
3423
3523
|
usageFree: "Free",
|
|
3424
3524
|
usageFiveHour: "5-hour window",
|
|
3425
3525
|
usageWeekly: "Weekly window",
|
|
3426
3526
|
usageMonthlyLeft: "Monthly left",
|
|
3527
|
+
usageMonthlyDepleted: "Monthly credit is used up; purchased and free credit can no longer be spent.",
|
|
3427
3528
|
usageExceeded: "Exceeded",
|
|
3428
3529
|
usageReset: "Resets",
|
|
3429
3530
|
usagePartial: "Some endpoint data unavailable",
|
|
@@ -3448,7 +3549,7 @@ window.__ModuleLoader__.load({
|
|
|
3448
3549
|
loginButton: "Sign in to Command Code",
|
|
3449
3550
|
loginStarting: "Starting the local callback server…",
|
|
3450
3551
|
loginWaiting: "Waiting for authorization in your browser. If the page did not open automatically, use the authorization link.",
|
|
3451
|
-
loginOpenLink: "Open the authorization page
|
|
3552
|
+
loginOpenLink: "Open the authorization page",
|
|
3452
3553
|
loginCancel: "Cancel sign-in",
|
|
3453
3554
|
loginSuccess: "Signed in as",
|
|
3454
3555
|
loginUnavailable: "Sign-in is unavailable in this environment; paste the API key instead.",
|
|
@@ -3463,7 +3564,7 @@ window.__ModuleLoader__.load({
|
|
|
3463
3564
|
cardRouteActive: "Active",
|
|
3464
3565
|
cardLoadingHint: "Loading the Command Code configuration…",
|
|
3465
3566
|
cardRegistrationHint: "This card is contributed by the Command Code plugin and is waiting for the settings page to finish assembling.",
|
|
3466
|
-
accountsRotationHint: "
|
|
3567
|
+
accountsRotationHint: "When the current account hits its limit or its key stops working, requests switch to the next usable account in list order.",
|
|
3467
3568
|
accountModeAuto: "Mode: switch automatically (list order)",
|
|
3468
3569
|
accountModePinned: "Mode: pinned to \"{name}\", still switching when it is unavailable",
|
|
3469
3570
|
accountStatusPinned: "Pinned",
|
|
@@ -3486,6 +3587,8 @@ window.__ModuleLoader__.load({
|
|
|
3486
3587
|
accountAddPaste: "Paste key",
|
|
3487
3588
|
accountAddConfirm: "Add",
|
|
3488
3589
|
accountAddCancel: "Cancel setup",
|
|
3590
|
+
accountAddStart: "Start sign-in",
|
|
3591
|
+
accountAddMethod: "Method",
|
|
3489
3592
|
accountAddLinkHint: "If the sign-in page did not open automatically, use the link below.",
|
|
3490
3593
|
accountAddOpenLink: "Open the sign-in page",
|
|
3491
3594
|
accountNamePlaceholder: "Name (optional; sign-in uses the account name)",
|
|
@@ -3499,15 +3602,45 @@ window.__ModuleLoader__.load({
|
|
|
3499
3602
|
accountEnrollmentCleanupRetry: "Retry cleanup",
|
|
3500
3603
|
accountRefSeparator: ": ",
|
|
3501
3604
|
accountModels: "Dedicated models",
|
|
3502
|
-
accountModelsHint: "These models prefer this account and still switch when it is unavailable
|
|
3605
|
+
accountModelsHint: "These models prefer this account and still switch when it is unavailable; a model belongs to one account.",
|
|
3503
3606
|
accountModelOwner: "on {name}",
|
|
3504
3607
|
modelPick: "Choose models…",
|
|
3505
3608
|
modelCount: "{count} models selected",
|
|
3506
3609
|
modelCatalogFailed: "The model catalog could not be loaded; saved settings still apply.",
|
|
3507
3610
|
modelsTitle: "Models & context",
|
|
3508
|
-
modelsInvalid: "A number in Models & context is not ready to save; expand to fix it.",
|
|
3509
3611
|
privacyTitle: "Privacy & security",
|
|
3510
3612
|
integrationsTitle: "Integrations & display",
|
|
3613
|
+
serviceStatusTitle: "Service status",
|
|
3614
|
+
serviceStatusHint: "Published data comes from the official status page and is only written on a status change or the daily summary; local connectivity is probed by the host just now.",
|
|
3615
|
+
serviceStatusChecking: "Checking…",
|
|
3616
|
+
serviceStatusUp: "Operational",
|
|
3617
|
+
serviceStatusDegraded: "Degraded performance",
|
|
3618
|
+
serviceStatusDown: "Service outage",
|
|
3619
|
+
serviceStatusUnknown: "Status unknown",
|
|
3620
|
+
serviceStatusOfficial: "Official",
|
|
3621
|
+
serviceStatusLocal: "This device",
|
|
3622
|
+
serviceStatusUptime: "uptime {value}",
|
|
3623
|
+
serviceStatusBadgeLocalHttp: "Connection error here",
|
|
3624
|
+
serviceStatusBadgeLocalTimeout: "Timing out here",
|
|
3625
|
+
serviceStatusBadgeLocalUnreachable: "Unreachable here",
|
|
3626
|
+
serviceStatusUptimeWeek: "7d {value}",
|
|
3627
|
+
serviceStatusUptimeMonth: "30d {value}",
|
|
3628
|
+
serviceStatusResponseWeek: "avg {value}",
|
|
3629
|
+
serviceStatusUpdatedJustNow: "updated just now",
|
|
3630
|
+
serviceStatusUpdatedMinutes: "updated {count} min ago",
|
|
3631
|
+
serviceStatusUpdatedHours: "updated {count} h ago",
|
|
3632
|
+
serviceStatusUpdatedDays: "updated {count} d ago",
|
|
3633
|
+
serviceStatusUpdatedUnknown: "update time unknown",
|
|
3634
|
+
serviceStatusLag: "Official data is only published on a status change or the daily summary, so it may lag by hours.",
|
|
3635
|
+
serviceStatusLocalChecking: "Probing…",
|
|
3636
|
+
serviceStatusLocalOk: "Reachable · {latency} ms",
|
|
3637
|
+
serviceStatusLocalHttp: "Error (HTTP {status})",
|
|
3638
|
+
serviceStatusLocalTimeout: "Timed out",
|
|
3639
|
+
serviceStatusLocalUnreachable: "Unreachable",
|
|
3640
|
+
serviceStatusLocalUnavailable: "Unknown (host provides no probe)",
|
|
3641
|
+
serviceStatusStale: "Status data unavailable; showing the last known result.",
|
|
3642
|
+
serviceStatusUnavailable: "Status data unavailable.",
|
|
3643
|
+
serviceStatusOpen: "Open status page",
|
|
3511
3644
|
enrollmentCreating: "Creating the account",
|
|
3512
3645
|
enrollmentWaiting: "Waiting for the browser sign-in",
|
|
3513
3646
|
enrollmentWriting: "Saving the credential",
|
|
@@ -3704,7 +3837,7 @@ window.__ModuleLoader__.load({
|
|
|
3704
3837
|
}
|
|
3705
3838
|
//#endregion
|
|
3706
3839
|
//#region package.json
|
|
3707
|
-
var version = "0.
|
|
3840
|
+
var version = "0.15.1";
|
|
3708
3841
|
var repository = {
|
|
3709
3842
|
"type": "git",
|
|
3710
3843
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -3876,6 +4009,392 @@ window.__ModuleLoader__.load({
|
|
|
3876
4009
|
return hintOf(version);
|
|
3877
4010
|
}
|
|
3878
4011
|
//#endregion
|
|
4012
|
+
//#region src/client/service-status.ts
|
|
4013
|
+
/** The public status page the row links to. */
|
|
4014
|
+
const STATUS_PAGE_URL = "https://status.commandcode.ai/";
|
|
4015
|
+
/** Upptime data files, freshest host first. */
|
|
4016
|
+
const STATUS_SOURCES = ["https://raw.githubusercontent.com/CommandCodeAI/commandcode-status/master/history", "https://cdn.jsdelivr.net/gh/CommandCodeAI/commandcode-status@master/history"];
|
|
4017
|
+
/** Files inside a source directory (the monitor's naming, not ours to change). */
|
|
4018
|
+
const SUMMARY_FILE = "summary.json";
|
|
4019
|
+
const STATE_FILE = "command-code.yml";
|
|
4020
|
+
/** The one site the Upptime config monitors. */
|
|
4021
|
+
const MONITORED_URL = "https://api.commandcode.ai";
|
|
4022
|
+
const MONITORED_SLUG = "command-code";
|
|
4023
|
+
/** The `localStorage` key holding the last successful snapshot. */
|
|
4024
|
+
const SERVICE_STATUS_CACHE_KEY = "@mars-sea/dsh-commandcode-provider/service-status";
|
|
4025
|
+
const LEVELS = [
|
|
4026
|
+
"up",
|
|
4027
|
+
"degraded",
|
|
4028
|
+
"down",
|
|
4029
|
+
"unknown"
|
|
4030
|
+
];
|
|
4031
|
+
function levelOf(value) {
|
|
4032
|
+
return typeof value === "string" && LEVELS.includes(value) ? value : void 0;
|
|
4033
|
+
}
|
|
4034
|
+
function stringOrUndefined(value) {
|
|
4035
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
4036
|
+
}
|
|
4037
|
+
function finiteNumber(value) {
|
|
4038
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
4039
|
+
}
|
|
4040
|
+
/**
|
|
4041
|
+
* Read the monitored site's verdict out of `summary.json`.
|
|
4042
|
+
*
|
|
4043
|
+
* The file is an array because an Upptime config may monitor several sites; we
|
|
4044
|
+
* match our API host, then the known slug, then the first record so a rename on
|
|
4045
|
+
* their side degrades to "show what the page shows" rather than to nothing.
|
|
4046
|
+
* Rejects only when the payload cannot answer at all — a rejection makes the
|
|
4047
|
+
* caller try the next mirror.
|
|
4048
|
+
*/
|
|
4049
|
+
function parseSummary(payload) {
|
|
4050
|
+
if (!Array.isArray(payload)) throw new Error("status summary is not an array");
|
|
4051
|
+
const records = payload.filter((entry) => typeof entry === "object" && entry !== null);
|
|
4052
|
+
const record = records.find((entry) => entry["url"] === MONITORED_URL) ?? records.find((entry) => entry["slug"] === MONITORED_SLUG) ?? records[0];
|
|
4053
|
+
if (record === void 0) throw new Error("status summary has no site record");
|
|
4054
|
+
const level = levelOf(record["status"]);
|
|
4055
|
+
if (level === void 0) throw new Error("status summary has no usable status");
|
|
4056
|
+
return {
|
|
4057
|
+
level,
|
|
4058
|
+
uptimeWeek: stringOrUndefined(record["uptimeWeek"]),
|
|
4059
|
+
uptimeMonth: stringOrUndefined(record["uptimeMonth"]),
|
|
4060
|
+
responseTimeWeekMs: finiteNumber(record["timeWeek"])
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
/**
|
|
4064
|
+
* Read the monitor's own state file (`key: value` YAML the robot writes).
|
|
4065
|
+
*
|
|
4066
|
+
* Only scalar lines are needed, so this stays a line parser: pulling a YAML
|
|
4067
|
+
* library into the client bundle for five fields would be the larger risk. A
|
|
4068
|
+
* malformed line is ignored; the caller treats missing fields as unknown rather
|
|
4069
|
+
* than failing the whole source, because the summary (not this file) is what
|
|
4070
|
+
* carries the verdict.
|
|
4071
|
+
*/
|
|
4072
|
+
function parseStateFile(text) {
|
|
4073
|
+
const fields = /* @__PURE__ */ new Map();
|
|
4074
|
+
for (const line of text.split("\n")) {
|
|
4075
|
+
const match = /^([A-Za-z][A-Za-z0-9]*):[ \t]*(.*)$/.exec(line.trim());
|
|
4076
|
+
if (match !== null) fields.set(match[1], match[2].trim());
|
|
4077
|
+
}
|
|
4078
|
+
const checkedRaw = fields.get("lastUpdated");
|
|
4079
|
+
const checkedAt = checkedRaw === void 0 ? NaN : Date.parse(checkedRaw);
|
|
4080
|
+
const codeRaw = fields.get("code");
|
|
4081
|
+
const code = codeRaw === void 0 ? NaN : Number.parseInt(codeRaw, 10);
|
|
4082
|
+
const responseRaw = fields.get("responseTime");
|
|
4083
|
+
const responseTime = responseRaw === void 0 ? NaN : Number.parseFloat(responseRaw);
|
|
4084
|
+
return {
|
|
4085
|
+
level: levelOf(fields.get("status")),
|
|
4086
|
+
checkedAt: Number.isFinite(checkedAt) ? checkedAt : void 0,
|
|
4087
|
+
responseTimeMs: Number.isFinite(responseTime) ? responseTime : void 0,
|
|
4088
|
+
code: Number.isFinite(code) ? code : void 0
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
/** Fetch one text resource with a hard timeout; rejects on any non-OK answer. */
|
|
4092
|
+
async function fetchText(url, fetchImpl, timeoutMs) {
|
|
4093
|
+
const controller = new AbortController();
|
|
4094
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
4095
|
+
try {
|
|
4096
|
+
const response = await fetchImpl(url, { signal: controller.signal });
|
|
4097
|
+
if (!response.ok) throw new Error(`status source responded ${response.status}`);
|
|
4098
|
+
return await response.text();
|
|
4099
|
+
} finally {
|
|
4100
|
+
clearTimeout(timer);
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
/** Read one mirror: the summary is required, the state file is best-effort. */
|
|
4104
|
+
async function readSource(base, fetchImpl, timeoutMs) {
|
|
4105
|
+
const [summaryText, stateText] = await Promise.all([fetchText(`${base}/${SUMMARY_FILE}`, fetchImpl, timeoutMs), fetchText(`${base}/${STATE_FILE}`, fetchImpl, timeoutMs).catch(() => void 0)]);
|
|
4106
|
+
return {
|
|
4107
|
+
summary: parseSummary(JSON.parse(summaryText)),
|
|
4108
|
+
state: stateText === void 0 ? {} : parseStateFile(stateText)
|
|
4109
|
+
};
|
|
4110
|
+
}
|
|
4111
|
+
/**
|
|
4112
|
+
* A {@link ServiceStatusStore} backed by `localStorage`. Tolerates a missing or
|
|
4113
|
+
* throwing storage (private modes): reads yield `undefined`, writes are
|
|
4114
|
+
* dropped, and the status row still works for the lifetime of the page.
|
|
4115
|
+
*/
|
|
4116
|
+
function localStorageServiceStatusStore(storage = typeof localStorage === "undefined" ? void 0 : localStorage) {
|
|
4117
|
+
return {
|
|
4118
|
+
read() {
|
|
4119
|
+
if (storage === void 0) return void 0;
|
|
4120
|
+
try {
|
|
4121
|
+
const raw = storage.getItem(SERVICE_STATUS_CACHE_KEY);
|
|
4122
|
+
if (raw === null) return void 0;
|
|
4123
|
+
return snapshotFrom(JSON.parse(raw));
|
|
4124
|
+
} catch {
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
},
|
|
4128
|
+
write(snapshot) {
|
|
4129
|
+
if (storage === void 0) return;
|
|
4130
|
+
try {
|
|
4131
|
+
storage.setItem(SERVICE_STATUS_CACHE_KEY, JSON.stringify(snapshot));
|
|
4132
|
+
} catch {}
|
|
4133
|
+
}
|
|
4134
|
+
};
|
|
4135
|
+
}
|
|
4136
|
+
/** Validate a cached payload; storage may have been written by an older build. */
|
|
4137
|
+
function snapshotFrom(value) {
|
|
4138
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
4139
|
+
const record = value;
|
|
4140
|
+
const level = levelOf(record["level"]);
|
|
4141
|
+
const fetchedAt = finiteNumber(record["fetchedAt"]);
|
|
4142
|
+
if (level === void 0 || fetchedAt === void 0) return void 0;
|
|
4143
|
+
return {
|
|
4144
|
+
level,
|
|
4145
|
+
checkedAt: finiteNumber(record["checkedAt"]),
|
|
4146
|
+
uptimeWeek: stringOrUndefined(record["uptimeWeek"]),
|
|
4147
|
+
uptimeMonth: stringOrUndefined(record["uptimeMonth"]),
|
|
4148
|
+
responseTimeWeekMs: finiteNumber(record["responseTimeWeekMs"]),
|
|
4149
|
+
live: record["live"] === true,
|
|
4150
|
+
stale: record["stale"] === true,
|
|
4151
|
+
fetchedAt
|
|
4152
|
+
};
|
|
4153
|
+
}
|
|
4154
|
+
/** The cached snapshot, for an instant first paint before the check lands. */
|
|
4155
|
+
function readCachedServiceStatus(store) {
|
|
4156
|
+
return store.read();
|
|
4157
|
+
}
|
|
4158
|
+
/**
|
|
4159
|
+
* Resolve the service status, preferring the cache while it is fresh and the
|
|
4160
|
+
* freshest mirror otherwise. Resolves with a snapshot in every case; the only
|
|
4161
|
+
* "failure" the caller sees is `live: false` (+ `stale` when a cache existed).
|
|
4162
|
+
*/
|
|
4163
|
+
async function checkServiceStatus(options) {
|
|
4164
|
+
const now = options.now ?? Date.now();
|
|
4165
|
+
const cached = options.store.read();
|
|
4166
|
+
if (cached !== void 0 && now - cached.fetchedAt < 3e5) return cached;
|
|
4167
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
4168
|
+
const sources = options.sources ?? STATUS_SOURCES;
|
|
4169
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
4170
|
+
for (const source of sources) try {
|
|
4171
|
+
const { summary, state } = await readSource(source, fetchImpl, timeoutMs);
|
|
4172
|
+
const snapshot = {
|
|
4173
|
+
level: state.level ?? summary.level,
|
|
4174
|
+
checkedAt: state.checkedAt,
|
|
4175
|
+
uptimeWeek: summary.uptimeWeek,
|
|
4176
|
+
uptimeMonth: summary.uptimeMonth,
|
|
4177
|
+
responseTimeWeekMs: summary.responseTimeWeekMs ?? state.responseTimeMs,
|
|
4178
|
+
live: true,
|
|
4179
|
+
stale: false,
|
|
4180
|
+
fetchedAt: now
|
|
4181
|
+
};
|
|
4182
|
+
options.store.write(snapshot);
|
|
4183
|
+
return snapshot;
|
|
4184
|
+
} catch {}
|
|
4185
|
+
if (cached !== void 0) return {
|
|
4186
|
+
...cached,
|
|
4187
|
+
live: false,
|
|
4188
|
+
stale: true
|
|
4189
|
+
};
|
|
4190
|
+
return {
|
|
4191
|
+
level: "unknown",
|
|
4192
|
+
live: false,
|
|
4193
|
+
stale: false,
|
|
4194
|
+
fetchedAt: now
|
|
4195
|
+
};
|
|
4196
|
+
}
|
|
4197
|
+
/** The published record's age: `官方数据更新:刚刚` / N minutes / hours / days. */
|
|
4198
|
+
function updatedCopy(checkedAt, now, t) {
|
|
4199
|
+
const age = Math.max(0, now - checkedAt);
|
|
4200
|
+
if (age < 6e4) return t("serviceStatusUpdatedJustNow");
|
|
4201
|
+
const minutes = Math.floor(age / 6e4);
|
|
4202
|
+
if (minutes < 60) return t("serviceStatusUpdatedMinutes", { count: minutes });
|
|
4203
|
+
const hours = Math.floor(minutes / 60);
|
|
4204
|
+
if (hours < 24) return t("serviceStatusUpdatedHours", { count: hours });
|
|
4205
|
+
return t("serviceStatusUpdatedDays", { count: Math.floor(hours / 24) });
|
|
4206
|
+
}
|
|
4207
|
+
/** The publication-lag explanation, shown once the record is old enough. */
|
|
4208
|
+
function lagCopy(checkedAt, now, t) {
|
|
4209
|
+
if (checkedAt === void 0) return void 0;
|
|
4210
|
+
return now - checkedAt >= 72e5 ? t("serviceStatusLag") : void 0;
|
|
4211
|
+
}
|
|
4212
|
+
/** The local-connectivity line and its dot tone. */
|
|
4213
|
+
function localCopy(probe, t) {
|
|
4214
|
+
if (probe.kind === "checking") return {
|
|
4215
|
+
text: t("serviceStatusLocalChecking"),
|
|
4216
|
+
tone: "muted"
|
|
4217
|
+
};
|
|
4218
|
+
if (probe.kind === "unavailable") return {
|
|
4219
|
+
text: t("serviceStatusLocalUnavailable"),
|
|
4220
|
+
tone: "muted"
|
|
4221
|
+
};
|
|
4222
|
+
const { result } = probe;
|
|
4223
|
+
if (result.outcome === "ok") return {
|
|
4224
|
+
text: t("serviceStatusLocalOk", { latency: result.latencyMs }),
|
|
4225
|
+
tone: "ok"
|
|
4226
|
+
};
|
|
4227
|
+
if (result.outcome === "http-error") return {
|
|
4228
|
+
text: t("serviceStatusLocalHttp", { status: result.status }),
|
|
4229
|
+
tone: "error"
|
|
4230
|
+
};
|
|
4231
|
+
if (result.outcome === "timeout") return {
|
|
4232
|
+
text: t("serviceStatusLocalTimeout"),
|
|
4233
|
+
tone: "error"
|
|
4234
|
+
};
|
|
4235
|
+
return {
|
|
4236
|
+
text: t("serviceStatusLocalUnreachable"),
|
|
4237
|
+
tone: "error"
|
|
4238
|
+
};
|
|
4239
|
+
}
|
|
4240
|
+
/**
|
|
4241
|
+
* A published uptime without its padding zeros: the summary prints two
|
|
4242
|
+
* decimals verbatim (`100.00%`), which reads as noise, so `100.00%` becomes
|
|
4243
|
+
* `100%` and `99.90%` becomes `99.9%`; anything that is not a plain percentage
|
|
4244
|
+
* is shown as published.
|
|
4245
|
+
*/
|
|
4246
|
+
function compactUptime(value) {
|
|
4247
|
+
const match = /^(\d+)(?:\.(\d+))?%$/.exec(value.trim());
|
|
4248
|
+
if (match === null) return value;
|
|
4249
|
+
const fraction = (match[2] ?? "").replace(/0+$/, "");
|
|
4250
|
+
return fraction === "" ? `${match[1]}%` : `${match[1]}.${fraction}%`;
|
|
4251
|
+
}
|
|
4252
|
+
/** The aggregate line, or undefined when this check carried no aggregates. */
|
|
4253
|
+
function detailCopy(snapshot, t) {
|
|
4254
|
+
const parts = [];
|
|
4255
|
+
const uptimes = [];
|
|
4256
|
+
if (snapshot.uptimeWeek !== void 0) uptimes.push(t("serviceStatusUptimeWeek", { value: compactUptime(snapshot.uptimeWeek) }));
|
|
4257
|
+
if (snapshot.uptimeMonth !== void 0) uptimes.push(t("serviceStatusUptimeMonth", { value: compactUptime(snapshot.uptimeMonth) }));
|
|
4258
|
+
if (uptimes.length > 0) parts.push(t("serviceStatusUptime", { value: uptimes.join(" / ") }));
|
|
4259
|
+
if (snapshot.responseTimeWeekMs !== void 0) parts.push(t("serviceStatusResponseWeek", { value: `${Math.round(snapshot.responseTimeWeekMs)} ms` }));
|
|
4260
|
+
return parts.length === 0 ? void 0 : parts.join(" · ");
|
|
4261
|
+
}
|
|
4262
|
+
/** The heading verdict: a failed local probe first, else the published one. */
|
|
4263
|
+
function badgeOf(probe, official, t) {
|
|
4264
|
+
if (probe.kind !== "result" || probe.result.outcome === "ok") return official;
|
|
4265
|
+
const { outcome } = probe.result;
|
|
4266
|
+
return {
|
|
4267
|
+
label: outcome === "http-error" ? t("serviceStatusBadgeLocalHttp") : outcome === "timeout" ? t("serviceStatusBadgeLocalTimeout") : t("serviceStatusBadgeLocalUnreachable"),
|
|
4268
|
+
tone: "warn"
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
4271
|
+
/**
|
|
4272
|
+
* Project a snapshot + the live probe into the row's copy. Pure and React-free
|
|
4273
|
+
* so the labels, the age buckets, the lag rule and the failure wording are
|
|
4274
|
+
* pinned by node tests rather than by rendering.
|
|
4275
|
+
*
|
|
4276
|
+
* `snapshot === undefined` means the first published-data check is still in
|
|
4277
|
+
* flight (the hook paints the cache first, so this only shows on a cold cache).
|
|
4278
|
+
* The probe is independent: the row always renders both halves, and the local
|
|
4279
|
+
* half never borrows the published verdict.
|
|
4280
|
+
*/
|
|
4281
|
+
function serviceStatusView(snapshot, probe, t, now) {
|
|
4282
|
+
const local = localCopy(probe, t);
|
|
4283
|
+
const hint = t("serviceStatusHint");
|
|
4284
|
+
if (snapshot === void 0) {
|
|
4285
|
+
const label = t("serviceStatusChecking");
|
|
4286
|
+
return {
|
|
4287
|
+
level: "unknown",
|
|
4288
|
+
checking: true,
|
|
4289
|
+
label,
|
|
4290
|
+
officialTone: "checking",
|
|
4291
|
+
badge: badgeOf(probe, {
|
|
4292
|
+
label,
|
|
4293
|
+
tone: "checking"
|
|
4294
|
+
}, t),
|
|
4295
|
+
local: local.text,
|
|
4296
|
+
localTone: local.tone,
|
|
4297
|
+
localChecking: probe.kind === "checking",
|
|
4298
|
+
hint,
|
|
4299
|
+
linkLabel: t("serviceStatusOpen")
|
|
4300
|
+
};
|
|
4301
|
+
}
|
|
4302
|
+
const label = snapshot.level === "up" ? t("serviceStatusUp") : snapshot.level === "degraded" ? t("serviceStatusDegraded") : snapshot.level === "down" ? t("serviceStatusDown") : t("serviceStatusUnknown");
|
|
4303
|
+
const notice = snapshot.live ? void 0 : snapshot.stale ? t("serviceStatusStale") : t("serviceStatusUnavailable");
|
|
4304
|
+
const officialTone = snapshot.level === "up" ? "ok" : snapshot.level === "degraded" ? "warn" : snapshot.level === "down" ? "error" : "idle";
|
|
4305
|
+
return {
|
|
4306
|
+
level: snapshot.level,
|
|
4307
|
+
checking: false,
|
|
4308
|
+
label,
|
|
4309
|
+
officialTone,
|
|
4310
|
+
badge: badgeOf(probe, {
|
|
4311
|
+
label,
|
|
4312
|
+
tone: officialTone
|
|
4313
|
+
}, t),
|
|
4314
|
+
detail: detailCopy(snapshot, t),
|
|
4315
|
+
updated: snapshot.checkedAt === void 0 ? t("serviceStatusUpdatedUnknown") : updatedCopy(snapshot.checkedAt, now, t),
|
|
4316
|
+
lag: lagCopy(snapshot.checkedAt, now, t),
|
|
4317
|
+
local: local.text,
|
|
4318
|
+
localTone: local.tone,
|
|
4319
|
+
localChecking: probe.kind === "checking",
|
|
4320
|
+
notice,
|
|
4321
|
+
hint,
|
|
4322
|
+
linkLabel: t("serviceStatusOpen")
|
|
4323
|
+
};
|
|
4324
|
+
}
|
|
4325
|
+
//#endregion
|
|
4326
|
+
//#region src/client/group-fold.ts
|
|
4327
|
+
const FOLD_GROUPS = [
|
|
4328
|
+
"accounts",
|
|
4329
|
+
"models",
|
|
4330
|
+
"privacy",
|
|
4331
|
+
"integrations",
|
|
4332
|
+
"advanced"
|
|
4333
|
+
];
|
|
4334
|
+
/** First visit: only Accounts open. */
|
|
4335
|
+
const DEFAULT_FOLD_STATE = {
|
|
4336
|
+
accounts: true,
|
|
4337
|
+
models: false,
|
|
4338
|
+
privacy: false,
|
|
4339
|
+
integrations: false,
|
|
4340
|
+
advanced: false
|
|
4341
|
+
};
|
|
4342
|
+
/** The `localStorage` key holding the serialized {@link FoldState}. */
|
|
4343
|
+
const FOLD_STATE_KEY = "@mars-sea/dsh-commandcode-provider/settings-fold";
|
|
4344
|
+
/**
|
|
4345
|
+
* Read a stored value back. Anything unusable — absent, not JSON, not an
|
|
4346
|
+
* object — yields the defaults; within an object, each group takes its stored
|
|
4347
|
+
* flag only when it is a real boolean, so a partial or older record keeps the
|
|
4348
|
+
* groups it knows and defaults the rest.
|
|
4349
|
+
*/
|
|
4350
|
+
function parseFoldState(raw) {
|
|
4351
|
+
if (raw === null || raw === void 0 || raw === "") return DEFAULT_FOLD_STATE;
|
|
4352
|
+
let parsed;
|
|
4353
|
+
try {
|
|
4354
|
+
parsed = JSON.parse(raw);
|
|
4355
|
+
} catch {
|
|
4356
|
+
return DEFAULT_FOLD_STATE;
|
|
4357
|
+
}
|
|
4358
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return DEFAULT_FOLD_STATE;
|
|
4359
|
+
const record = parsed;
|
|
4360
|
+
const next = { ...DEFAULT_FOLD_STATE };
|
|
4361
|
+
for (const group of FOLD_GROUPS) {
|
|
4362
|
+
const value = record[group];
|
|
4363
|
+
if (typeof value === "boolean") next[group] = value;
|
|
4364
|
+
}
|
|
4365
|
+
return next;
|
|
4366
|
+
}
|
|
4367
|
+
/** Open the given groups, leaving the rest as they are (the save bar's locate action). */
|
|
4368
|
+
function expandGroups(state, groups) {
|
|
4369
|
+
if (groups.every((group) => state[group])) return state;
|
|
4370
|
+
const next = { ...state };
|
|
4371
|
+
for (const group of groups) next[group] = true;
|
|
4372
|
+
return next;
|
|
4373
|
+
}
|
|
4374
|
+
/**
|
|
4375
|
+
* A {@link FoldStateStore} backed by `localStorage`. A missing or throwing
|
|
4376
|
+
* storage (private mode, blocked site data) reads as the defaults and drops
|
|
4377
|
+
* writes: the page must render the same either way.
|
|
4378
|
+
*/
|
|
4379
|
+
function localStorageFoldStore(storage = typeof localStorage === "undefined" ? void 0 : localStorage) {
|
|
4380
|
+
return {
|
|
4381
|
+
read() {
|
|
4382
|
+
if (storage === void 0) return DEFAULT_FOLD_STATE;
|
|
4383
|
+
try {
|
|
4384
|
+
return parseFoldState(storage.getItem(FOLD_STATE_KEY));
|
|
4385
|
+
} catch {
|
|
4386
|
+
return DEFAULT_FOLD_STATE;
|
|
4387
|
+
}
|
|
4388
|
+
},
|
|
4389
|
+
write(state) {
|
|
4390
|
+
if (storage === void 0) return;
|
|
4391
|
+
try {
|
|
4392
|
+
storage.setItem(FOLD_STATE_KEY, JSON.stringify(state));
|
|
4393
|
+
} catch {}
|
|
4394
|
+
}
|
|
4395
|
+
};
|
|
4396
|
+
}
|
|
4397
|
+
//#endregion
|
|
3879
4398
|
//#region src/client/section.tsx
|
|
3880
4399
|
/**
|
|
3881
4400
|
* React component for the "Command Code" settings page (browser half).
|
|
@@ -3889,21 +4408,172 @@ window.__ModuleLoader__.load({
|
|
|
3889
4408
|
* actions and dedicated models — every operation commits immediately), Models
|
|
3890
4409
|
* & context (plan filter + visible-model allowlist, then the context-length
|
|
3891
4410
|
* rows: the global custom window and the per-model overrides, issue #86),
|
|
3892
|
-
* Privacy & security (ZDR), Integrations & display (web search,
|
|
3893
|
-
* card), and
|
|
4411
|
+
* Privacy & security (ZDR), Integrations & display (service status, web search,
|
|
4412
|
+
* sidebar quota card), and Advanced (API base + network limits). Everything
|
|
3894
4413
|
* below Accounts is a flat group of rows (title/description left, control
|
|
3895
4414
|
* right) inside the staged form the floating save bar writes.
|
|
3896
4415
|
*
|
|
3897
|
-
*
|
|
3898
|
-
*
|
|
3899
|
-
* remembered
|
|
3900
|
-
*
|
|
3901
|
-
*
|
|
3902
|
-
* button unexplained.
|
|
4416
|
+
* All five groups fold from their own heading (`FoldableGroup`, 决策记录第十章
|
|
4417
|
+
* 第4条): Accounts opens by default, the rest start folded, and the choice is
|
|
4418
|
+
* remembered per browser (./group-fold.ts). A folded heading still summarizes its group, and anything
|
|
4419
|
+
* inside it that blocks the save is reported on the heading; the save bar's
|
|
4420
|
+
* Locate action opens that group and focuses the invalid field.
|
|
3903
4421
|
*
|
|
3904
4422
|
* Styles are injected once by the client entry (see src/client/index.ts) and
|
|
3905
4423
|
* class-prefixed `cc-` to stay local.
|
|
3906
4424
|
*/
|
|
4425
|
+
const ICON_PATHS = {
|
|
4426
|
+
swap: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 5h9l-2-2" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M13.5 11h-9l2 2" })] }),
|
|
4427
|
+
chevron: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" }),
|
|
4428
|
+
more: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4429
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4430
|
+
cx: "8",
|
|
4431
|
+
cy: "3.5",
|
|
4432
|
+
r: ".9",
|
|
4433
|
+
fill: "currentColor",
|
|
4434
|
+
stroke: "none"
|
|
4435
|
+
}),
|
|
4436
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4437
|
+
cx: "8",
|
|
4438
|
+
cy: "8",
|
|
4439
|
+
r: ".9",
|
|
4440
|
+
fill: "currentColor",
|
|
4441
|
+
stroke: "none"
|
|
4442
|
+
}),
|
|
4443
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4444
|
+
cx: "8",
|
|
4445
|
+
cy: "12.5",
|
|
4446
|
+
r: ".9",
|
|
4447
|
+
fill: "currentColor",
|
|
4448
|
+
stroke: "none"
|
|
4449
|
+
})
|
|
4450
|
+
] }),
|
|
4451
|
+
chart: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 13.5h11" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4.5 13.5V8.5M8 13.5V4.5M11.5 13.5V6.5" })] }),
|
|
4452
|
+
arrowRight: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3 8h10M9 4l4 4-4 4" }),
|
|
4453
|
+
check: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4454
|
+
cx: "8",
|
|
4455
|
+
cy: "8",
|
|
4456
|
+
r: "6"
|
|
4457
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.5 8.2 7.2 9.8 10.5 6.5" })] }),
|
|
4458
|
+
reset: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 8a5.5 5.5 0 1 0 1.6-3.9" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 2.5v3h3" })] }),
|
|
4459
|
+
close: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 4l8 8M12 4l-8 8" }),
|
|
4460
|
+
refresh: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M13.5 2.5v3h-3" })] }),
|
|
4461
|
+
plus: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 3v10M3 8h10" }),
|
|
4462
|
+
external: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4463
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9 2.5h4.5V7" }),
|
|
4464
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M13.5 2.5 7.5 8.5" }),
|
|
4465
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M11.5 9.5v3a1 1 0 0 1-1 1h-7a1 1 0 0 1-1-1v-7a1 1 0 0 1 1-1h3" })
|
|
4466
|
+
] }),
|
|
4467
|
+
info: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4468
|
+
cx: "8",
|
|
4469
|
+
cy: "8",
|
|
4470
|
+
r: "6"
|
|
4471
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 7.25v3.5M8 5.25v.01" })] }),
|
|
4472
|
+
warn: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 2.5 14 13H2z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 6.5v3M8 11.25v.01" })] }),
|
|
4473
|
+
error: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
4474
|
+
cx: "8",
|
|
4475
|
+
cy: "8",
|
|
4476
|
+
r: "6"
|
|
4477
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M6 6l4 4M10 6l-4 4" })] }),
|
|
4478
|
+
lock: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
4479
|
+
x: "3",
|
|
4480
|
+
y: "7",
|
|
4481
|
+
width: "10",
|
|
4482
|
+
height: "7",
|
|
4483
|
+
rx: "1.5"
|
|
4484
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2" })] })
|
|
4485
|
+
};
|
|
4486
|
+
function Icon({ name, className = "cc-icon" }) {
|
|
4487
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
4488
|
+
className,
|
|
4489
|
+
viewBox: "0 0 16 16",
|
|
4490
|
+
width: "16",
|
|
4491
|
+
height: "16",
|
|
4492
|
+
fill: "none",
|
|
4493
|
+
stroke: "currentColor",
|
|
4494
|
+
strokeWidth: "1.5",
|
|
4495
|
+
strokeLinecap: "round",
|
|
4496
|
+
strokeLinejoin: "round",
|
|
4497
|
+
"aria-hidden": "true",
|
|
4498
|
+
children: ICON_PATHS[name]
|
|
4499
|
+
});
|
|
4500
|
+
}
|
|
4501
|
+
const PAGE_BUTTON_VARIANT = {
|
|
4502
|
+
primary: "cc-btnPrimary",
|
|
4503
|
+
outline: "cc-btnSecondary",
|
|
4504
|
+
ghost: "cc-btnGhost",
|
|
4505
|
+
danger: "cc-btnDanger"
|
|
4506
|
+
};
|
|
4507
|
+
const PAGE_BUTTON_SIZE = {
|
|
4508
|
+
sm: " cc-btnSm",
|
|
4509
|
+
md: "",
|
|
4510
|
+
lg: " cc-btnLg"
|
|
4511
|
+
};
|
|
4512
|
+
function PageButton({ variant = "ghost", size = "md", icon, className, type = "button", children, ...rest }) {
|
|
4513
|
+
const classes = `cc-btn ${PAGE_BUTTON_VARIANT[variant]}${PAGE_BUTTON_SIZE[size]}${className === void 0 ? "" : ` ${className}`}`;
|
|
4514
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4515
|
+
...rest,
|
|
4516
|
+
type,
|
|
4517
|
+
className: classes,
|
|
4518
|
+
children: [icon, children]
|
|
4519
|
+
});
|
|
4520
|
+
}
|
|
4521
|
+
const NOTICE_ICON = {
|
|
4522
|
+
neutral: "info",
|
|
4523
|
+
success: "check",
|
|
4524
|
+
warn: "warn",
|
|
4525
|
+
error: "error"
|
|
4526
|
+
};
|
|
4527
|
+
const NOTICE_CLASS = {
|
|
4528
|
+
neutral: "cc-notice",
|
|
4529
|
+
success: "cc-notice cc-noticeSuccess",
|
|
4530
|
+
warn: "cc-notice cc-noticeWarn",
|
|
4531
|
+
error: "cc-notice cc-noticeError"
|
|
4532
|
+
};
|
|
4533
|
+
/**
|
|
4534
|
+
* The one block every result, warning and failure on this page uses (read-only
|
|
4535
|
+
* config, a failed account operation, a cleanup still owed, …), so status no
|
|
4536
|
+
* longer arrives as loose red paragraphs in a different shape each time.
|
|
4537
|
+
* Actions sit under the text; the caller keeps the live-region role.
|
|
4538
|
+
*/
|
|
4539
|
+
function Notice({ tone = "neutral", icon, title, actions, role = "status", label, children }) {
|
|
4540
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4541
|
+
className: NOTICE_CLASS[tone],
|
|
4542
|
+
role,
|
|
4543
|
+
"aria-label": label,
|
|
4544
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
4545
|
+
name: icon ?? NOTICE_ICON[tone],
|
|
4546
|
+
className: "cc-noticeIcon"
|
|
4547
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4548
|
+
className: "cc-noticeBody",
|
|
4549
|
+
children: [
|
|
4550
|
+
title !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4551
|
+
className: "cc-noticeTitle",
|
|
4552
|
+
children: title
|
|
4553
|
+
}) : null,
|
|
4554
|
+
children,
|
|
4555
|
+
actions !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4556
|
+
className: "cc-noticeActions",
|
|
4557
|
+
children: actions
|
|
4558
|
+
}) : null
|
|
4559
|
+
]
|
|
4560
|
+
})]
|
|
4561
|
+
});
|
|
4562
|
+
}
|
|
4563
|
+
/**
|
|
4564
|
+
* The Host-side defaults an empty field falls back to, shown as placeholders so
|
|
4565
|
+
* an empty box reads "300 s" rather than looking broken. They are literals
|
|
4566
|
+
* because the client bundle must not pull in the adapter; `tests/section.test.ts`
|
|
4567
|
+
* pins each one to the constant it mirrors (DEFAULT_API_BASE,
|
|
4568
|
+
* DEFAULT_REQUEST_TIMEOUT_MS / DEFAULT_STREAM_IDLE_TIMEOUT_MS in seconds,
|
|
4569
|
+
* DEFAULT_TRANSPORT_MAX_RETRIES).
|
|
4570
|
+
*/
|
|
4571
|
+
const FIELD_DEFAULTS = {
|
|
4572
|
+
apiBase: "https://api.commandcode.ai",
|
|
4573
|
+
requestTimeoutSeconds: "300",
|
|
4574
|
+
streamIdleTimeoutSeconds: "300",
|
|
4575
|
+
transportMaxRetries: "5"
|
|
4576
|
+
};
|
|
3907
4577
|
const ADVANCED_FIELDS = [
|
|
3908
4578
|
"apiBase",
|
|
3909
4579
|
"requestTimeoutMs",
|
|
@@ -3933,16 +4603,76 @@ window.__ModuleLoader__.load({
|
|
|
3933
4603
|
function modelsGroupInvalid(state) {
|
|
3934
4604
|
return MODELS_FIELDS.some((field) => state[field].invalid) || state.contextWindowOverrides.some((row) => row.invalid);
|
|
3935
4605
|
}
|
|
3936
|
-
/**
|
|
4606
|
+
/**
|
|
4607
|
+
* The groups holding a draft that blocks the save, in page order — what the
|
|
4608
|
+
* save bar's locate action opens before focusing the first invalid field.
|
|
4609
|
+
* Privacy and Integrations hold switches only and Accounts is not staged, so
|
|
4610
|
+
* only these two can ever appear.
|
|
4611
|
+
*/
|
|
4612
|
+
function invalidGroups(state) {
|
|
4613
|
+
const groups = [];
|
|
4614
|
+
if (modelsGroupInvalid(state)) groups.push("models");
|
|
4615
|
+
if (advancedGroupInvalid(state)) groups.push("advanced");
|
|
4616
|
+
return groups;
|
|
4617
|
+
}
|
|
4618
|
+
/**
|
|
4619
|
+
* "N customized" on the Models & context heading: its staged fields that
|
|
4620
|
+
* differ from the default, plus one per per-model context override (each row
|
|
4621
|
+
* is a customization the user made).
|
|
4622
|
+
*/
|
|
4623
|
+
function modelsOverriddenCount(state) {
|
|
4624
|
+
return MODELS_FIELDS.filter((field) => state[field].overridden).length + state.contextWindowOverrides.length;
|
|
4625
|
+
}
|
|
4626
|
+
/** "N customized" on the Advanced heading. */
|
|
4627
|
+
function advancedOverriddenCount(state) {
|
|
4628
|
+
return ADVANCED_FIELDS.filter((field) => state[field].overridden).length;
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* The effective value of a staged switch: an unset draft (`''`) means the
|
|
4632
|
+
* field's default. Used by the summary badges, which must say what the switch
|
|
4633
|
+
* on screen says.
|
|
4634
|
+
*/
|
|
4635
|
+
function stagedSwitch(field, defaultValue) {
|
|
4636
|
+
return field.text === "" ? defaultValue : field.text === "true";
|
|
4637
|
+
}
|
|
4638
|
+
/**
|
|
4639
|
+
* Accounts that need attention, for the Accounts heading. Uses the same
|
|
4640
|
+
* verdicts as each row's status dot (`statusDotClass`): a rejected key is a
|
|
4641
|
+
* hard failure, a cooldown or any other mark a warning.
|
|
4642
|
+
*/
|
|
4643
|
+
function accountIssues(entries) {
|
|
4644
|
+
let count = 0;
|
|
4645
|
+
let severe = false;
|
|
4646
|
+
for (const entry of entries) {
|
|
4647
|
+
if (entry === void 0) continue;
|
|
4648
|
+
if (entry.mark === "invalid-credential") {
|
|
4649
|
+
count += 1;
|
|
4650
|
+
severe = true;
|
|
4651
|
+
} else if (entry.mark !== "" || entry.cooldownUntil > 0) count += 1;
|
|
4652
|
+
}
|
|
4653
|
+
return {
|
|
4654
|
+
count,
|
|
4655
|
+
severe
|
|
4656
|
+
};
|
|
4657
|
+
}
|
|
4658
|
+
/**
|
|
4659
|
+
* The reset button a staged field shows once it differs from the default. It
|
|
4660
|
+
* trails the control, and a row with nothing to reset keeps an empty slot of
|
|
4661
|
+
* the same width, so every staged control in a group ends on one right edge.
|
|
4662
|
+
*/
|
|
3937
4663
|
function FieldOverride({ label, state, disabled, t, onReset }) {
|
|
3938
|
-
if (!state.overridden && !state.clear) return
|
|
4664
|
+
if (!state.overridden && !state.clear) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4665
|
+
className: "cc-resetSlot",
|
|
4666
|
+
"aria-hidden": "true"
|
|
4667
|
+
});
|
|
3939
4668
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3940
4669
|
type: "button",
|
|
3941
|
-
className: "cc-
|
|
4670
|
+
className: "cc-iconButton",
|
|
3942
4671
|
disabled,
|
|
3943
4672
|
onClick: onReset,
|
|
3944
4673
|
"aria-label": `${label} — ${t("reset")}`,
|
|
3945
|
-
|
|
4674
|
+
title: t("reset"),
|
|
4675
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "reset" })
|
|
3946
4676
|
});
|
|
3947
4677
|
}
|
|
3948
4678
|
/**
|
|
@@ -3992,7 +4722,18 @@ window.__ModuleLoader__.load({
|
|
|
3992
4722
|
}) : null;
|
|
3993
4723
|
}
|
|
3994
4724
|
/** One text/number field row. */
|
|
3995
|
-
function Field({ id, label, hint, state, disabled, numeric, decimal, context, output, wide, placeholder, onEdit, onReset, t }) {
|
|
4725
|
+
function Field({ id, label, hint, state, disabled, numeric, decimal, context, output, wide, unit, placeholder, onEdit, onReset, t }) {
|
|
4726
|
+
const input = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4727
|
+
id,
|
|
4728
|
+
className: unit === void 0 ? `cc-fieldInput ${wide ? "cc-rowInputWide" : "cc-rowInput"}${state.invalid ? " cc-fieldInputInvalid" : ""}` : "cc-fieldInput",
|
|
4729
|
+
type: "text",
|
|
4730
|
+
inputMode: decimal ? "decimal" : numeric ? "numeric" : void 0,
|
|
4731
|
+
"aria-invalid": state.invalid || void 0,
|
|
4732
|
+
value: state.text,
|
|
4733
|
+
placeholder,
|
|
4734
|
+
disabled,
|
|
4735
|
+
onChange: (event) => onEdit(event.target.value)
|
|
4736
|
+
});
|
|
3996
4737
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingRow, {
|
|
3997
4738
|
title: label,
|
|
3998
4739
|
titleFor: id,
|
|
@@ -4002,22 +4743,18 @@ window.__ModuleLoader__.load({
|
|
|
4002
4743
|
}),
|
|
4003
4744
|
description: hint,
|
|
4004
4745
|
error: state.invalid ? invalidCopy(state.invalidReason, t, output === true ? "output" : context === true ? "context" : decimal === true ? "duration" : "number") : void 0,
|
|
4005
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
4746
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [unit === void 0 ? input : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4747
|
+
className: state.invalid ? "cc-unitBox cc-unitBoxInvalid" : "cc-unitBox",
|
|
4748
|
+
children: [input, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4749
|
+
className: "cc-unit",
|
|
4750
|
+
children: unit
|
|
4751
|
+
})]
|
|
4752
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldOverride, {
|
|
4006
4753
|
label,
|
|
4007
4754
|
state,
|
|
4008
4755
|
disabled,
|
|
4009
4756
|
t,
|
|
4010
4757
|
onReset
|
|
4011
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4012
|
-
id,
|
|
4013
|
-
className: `cc-input ${wide ? "cc-rowInputWide" : "cc-rowInput"}${state.invalid ? " cc-inputInvalid" : ""}`,
|
|
4014
|
-
type: "text",
|
|
4015
|
-
inputMode: decimal ? "decimal" : numeric ? "numeric" : void 0,
|
|
4016
|
-
"aria-invalid": state.invalid || void 0,
|
|
4017
|
-
value: state.text,
|
|
4018
|
-
placeholder,
|
|
4019
|
-
disabled,
|
|
4020
|
-
onChange: (event) => onEdit(event.target.value)
|
|
4021
4758
|
})] })
|
|
4022
4759
|
});
|
|
4023
4760
|
}
|
|
@@ -4057,13 +4794,7 @@ window.__ModuleLoader__.load({
|
|
|
4057
4794
|
t
|
|
4058
4795
|
}),
|
|
4059
4796
|
description: hint,
|
|
4060
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4061
|
-
label,
|
|
4062
|
-
state,
|
|
4063
|
-
disabled,
|
|
4064
|
-
t,
|
|
4065
|
-
onReset
|
|
4066
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4797
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4067
4798
|
id,
|
|
4068
4799
|
className: "cc-toggle",
|
|
4069
4800
|
type: "checkbox",
|
|
@@ -4071,6 +4802,12 @@ window.__ModuleLoader__.load({
|
|
|
4071
4802
|
checked,
|
|
4072
4803
|
disabled,
|
|
4073
4804
|
onChange: (event) => onEdit(event.target.checked ? "true" : "false")
|
|
4805
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldOverride, {
|
|
4806
|
+
label,
|
|
4807
|
+
state,
|
|
4808
|
+
disabled,
|
|
4809
|
+
t,
|
|
4810
|
+
onReset
|
|
4074
4811
|
})] })
|
|
4075
4812
|
});
|
|
4076
4813
|
}
|
|
@@ -4099,7 +4836,7 @@ window.__ModuleLoader__.load({
|
|
|
4099
4836
|
function UsageWindow({ label, limit, t }) {
|
|
4100
4837
|
const { used, cap, exceeded, resetAt } = limit;
|
|
4101
4838
|
const ratio = windowRatio(used, cap);
|
|
4102
|
-
const reset =
|
|
4839
|
+
const reset = formatResetAtShort(resetAt);
|
|
4103
4840
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4104
4841
|
className: "cc-usageWindow",
|
|
4105
4842
|
children: [
|
|
@@ -4170,7 +4907,7 @@ window.__ModuleLoader__.load({
|
|
|
4170
4907
|
children: accountName
|
|
4171
4908
|
}) : null,
|
|
4172
4909
|
planName !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4173
|
-
className: "cc-
|
|
4910
|
+
className: "cc-badge cc-badgeOutline",
|
|
4174
4911
|
children: planName
|
|
4175
4912
|
}) : null
|
|
4176
4913
|
]
|
|
@@ -4183,25 +4920,44 @@ window.__ModuleLoader__.load({
|
|
|
4183
4920
|
className: "cc-usageHint",
|
|
4184
4921
|
children: t("usageUnconfigured")
|
|
4185
4922
|
}) : null,
|
|
4186
|
-
report.blocked !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4187
|
-
|
|
4923
|
+
report.blocked !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Notice, {
|
|
4924
|
+
tone: "error",
|
|
4188
4925
|
role: "alert",
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
className: "cc-usageBlockedHint",
|
|
4196
|
-
children: blockedHint(report.blocked, t)
|
|
4197
|
-
}),
|
|
4198
|
-
report.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4199
|
-
className: "cc-usageBlockedDetail",
|
|
4200
|
-
title: report.failures.join("; "),
|
|
4201
|
-
children: report.failures.join(" · ")
|
|
4202
|
-
}) : null
|
|
4203
|
-
]
|
|
4926
|
+
title: blockedTitle(report.blocked, t),
|
|
4927
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: blockedHint(report.blocked, t) }), report.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4928
|
+
className: "cc-noticeDetail",
|
|
4929
|
+
title: report.failures.join("; "),
|
|
4930
|
+
children: report.failures.join(" · ")
|
|
4931
|
+
}) : null]
|
|
4204
4932
|
}) : null,
|
|
4933
|
+
credits !== void 0 ? (() => {
|
|
4934
|
+
const monthlyKnown = credits.monthlyReported !== false;
|
|
4935
|
+
const depleted = monthlyKnown && credits.monthlyCredits <= 0;
|
|
4936
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4937
|
+
className: depleted ? "cc-balance cc-balanceEmpty" : "cc-balance",
|
|
4938
|
+
children: [
|
|
4939
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4940
|
+
className: "cc-balanceMain",
|
|
4941
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4942
|
+
className: "cc-balanceLabel",
|
|
4943
|
+
children: t("usageMonthlyLeft")
|
|
4944
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4945
|
+
className: "cc-balanceValue",
|
|
4946
|
+
children: monthlyKnown ? formatMoney(Math.max(0, credits.monthlyCredits)) : "—"
|
|
4947
|
+
})]
|
|
4948
|
+
}),
|
|
4949
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4950
|
+
className: "cc-balanceSub",
|
|
4951
|
+
children: `${t("usagePurchased")} ${credits.purchasedReported === false ? "—" : formatMoney(credits.purchasedCredits)} · ${t("usageFree")} ${credits.freeReported === false ? "—" : formatMoney(credits.freeCredits)}`
|
|
4952
|
+
}),
|
|
4953
|
+
depleted ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4954
|
+
className: "cc-balanceNote",
|
|
4955
|
+
role: "status",
|
|
4956
|
+
children: t("usageMonthlyDepleted")
|
|
4957
|
+
}) : null
|
|
4958
|
+
]
|
|
4959
|
+
});
|
|
4960
|
+
})() : null,
|
|
4205
4961
|
report.usage !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4206
4962
|
className: "cc-usageUpdated",
|
|
4207
4963
|
children: usagePeriod ? `${t("usageBillingPeriod")} ${usagePeriod}` : t("usagePeriodUnknown")
|
|
@@ -4212,7 +4968,7 @@ window.__ModuleLoader__.load({
|
|
|
4212
4968
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageStat, {
|
|
4213
4969
|
label: t("usageRequests"),
|
|
4214
4970
|
value: formatCompactCount(report.usage.totalCount),
|
|
4215
|
-
sub: `${t("
|
|
4971
|
+
sub: `${t("usageFailed")} ${formatCompactCount(report.usage.failedCount)}`,
|
|
4216
4972
|
title: compactCountTitle([
|
|
4217
4973
|
[t("usageRequests"), report.usage.totalCount],
|
|
4218
4974
|
[t("usageCompleted"), report.usage.completedCount],
|
|
@@ -4235,23 +4991,6 @@ window.__ModuleLoader__.load({
|
|
|
4235
4991
|
})
|
|
4236
4992
|
]
|
|
4237
4993
|
}) : null,
|
|
4238
|
-
credits !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4239
|
-
className: "cc-usageStats cc-usageStatsBalance",
|
|
4240
|
-
children: [
|
|
4241
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageStat, {
|
|
4242
|
-
label: t("usageMonthly"),
|
|
4243
|
-
value: credits.monthlyReported === false ? "—" : formatMoney(credits.monthlyCredits)
|
|
4244
|
-
}),
|
|
4245
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageStat, {
|
|
4246
|
-
label: t("usagePurchased"),
|
|
4247
|
-
value: credits.purchasedReported === false ? "—" : formatMoney(credits.purchasedCredits)
|
|
4248
|
-
}),
|
|
4249
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageStat, {
|
|
4250
|
-
label: t("usageFree"),
|
|
4251
|
-
value: credits.freeReported === false ? "—" : formatMoney(credits.freeCredits)
|
|
4252
|
-
})
|
|
4253
|
-
]
|
|
4254
|
-
}) : null,
|
|
4255
4994
|
credits?.fiveHour !== void 0 || credits?.weekly !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4256
4995
|
className: "cc-usageWindows",
|
|
4257
4996
|
children: [credits.fiveHour !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageWindow, {
|
|
@@ -4286,7 +5025,10 @@ window.__ModuleLoader__.load({
|
|
|
4286
5025
|
children: [
|
|
4287
5026
|
t("usageUpdated"),
|
|
4288
5027
|
" ",
|
|
4289
|
-
new Date(fetchedAt).toLocaleTimeString(
|
|
5028
|
+
new Date(fetchedAt).toLocaleTimeString(void 0, {
|
|
5029
|
+
hour: "2-digit",
|
|
5030
|
+
minute: "2-digit"
|
|
5031
|
+
})
|
|
4290
5032
|
]
|
|
4291
5033
|
}) : null
|
|
4292
5034
|
]
|
|
@@ -4362,12 +5104,12 @@ window.__ModuleLoader__.load({
|
|
|
4362
5104
|
children: t("modelStale")
|
|
4363
5105
|
}) : null,
|
|
4364
5106
|
option.allowance !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4365
|
-
className: "cc-
|
|
5107
|
+
className: "cc-badge cc-badgeOutline",
|
|
4366
5108
|
title: t("modelAllowanceTitle"),
|
|
4367
5109
|
children: t("modelAllowance", { amount: option.allowance })
|
|
4368
5110
|
}) : null,
|
|
4369
5111
|
!selected.includes(option.value) && ownerOf?.(option.value) !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4370
|
-
className: "cc-
|
|
5112
|
+
className: "cc-badge cc-badgeOutline",
|
|
4371
5113
|
children: t("accountModelOwner", { name: ownerOf(option.value) })
|
|
4372
5114
|
}) : null
|
|
4373
5115
|
]
|
|
@@ -4400,9 +5142,9 @@ window.__ModuleLoader__.load({
|
|
|
4400
5142
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4401
5143
|
className: "cc-selectorText",
|
|
4402
5144
|
children: selected.length === 0 ? t("modelPick") : t("modelCount", { count: selected.length })
|
|
4403
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4404
|
-
|
|
4405
|
-
"
|
|
5145
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
5146
|
+
name: "chevron",
|
|
5147
|
+
className: "cc-icon cc-selectorChevron"
|
|
4406
5148
|
})]
|
|
4407
5149
|
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
4408
5150
|
type: "search",
|
|
@@ -4436,16 +5178,16 @@ window.__ModuleLoader__.load({
|
|
|
4436
5178
|
description: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("visibleModelsHint") }), staleIds.length > 0 && catalogReady ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("visibleModelsStaleHint", { count: staleIds.length }) }) : null] }),
|
|
4437
5179
|
error: state.catalogFailed ? t("modelCatalogFailed") : void 0,
|
|
4438
5180
|
control: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4439
|
-
catalogReady && staleIds.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4440
|
-
|
|
4441
|
-
|
|
5181
|
+
catalogReady && staleIds.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5182
|
+
variant: "ghost",
|
|
5183
|
+
size: "sm",
|
|
4442
5184
|
disabled,
|
|
4443
5185
|
onClick: () => onSelect(state.visibleModels.filter((id) => !staleIds.includes(id))),
|
|
4444
5186
|
children: t("visibleModelsCleanStale", { count: staleIds.length })
|
|
4445
5187
|
}) : null,
|
|
4446
|
-
!state.visibleModelsAll ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4447
|
-
|
|
4448
|
-
|
|
5188
|
+
!state.visibleModelsAll ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5189
|
+
variant: "ghost",
|
|
5190
|
+
size: "sm",
|
|
4449
5191
|
disabled,
|
|
4450
5192
|
onClick: onClear,
|
|
4451
5193
|
children: t("visibleModelsShowAll")
|
|
@@ -4462,86 +5204,87 @@ window.__ModuleLoader__.load({
|
|
|
4462
5204
|
});
|
|
4463
5205
|
}
|
|
4464
5206
|
/**
|
|
4465
|
-
* One
|
|
4466
|
-
*
|
|
4467
|
-
*
|
|
4468
|
-
*
|
|
5207
|
+
* One top-level group of the page (决策记录第十章第4条). All five groups share
|
|
5208
|
+
* this one shape so they cannot drift apart: the heading is an `h3` wrapping a
|
|
5209
|
+
* single full-width button — chevron first, then the title and the summary
|
|
5210
|
+
* badges — and a group action such as Refresh sits OUTSIDE that button, so
|
|
5211
|
+
* using it never folds the group. Which groups are open is page state (see
|
|
5212
|
+
* ./group-fold.ts), passed in here.
|
|
5213
|
+
*
|
|
5214
|
+
* The body stays mounted and is hidden with the `hidden` attribute rather than
|
|
5215
|
+
* unrendered: `aria-controls` then always points at a real element, and the
|
|
5216
|
+
* save bar's locate action can focus an invalid field right after opening its
|
|
5217
|
+
* group. Folding is presentation only — staged drafts, validation and the save
|
|
5218
|
+
* path are untouched (第六章第1、2条).
|
|
4469
5219
|
*/
|
|
4470
|
-
function
|
|
5220
|
+
function FoldableGroup({ id, title, divided = true, expanded, onToggle, badges, action, children }) {
|
|
5221
|
+
const titleId = `cc-group-${id}-title`;
|
|
5222
|
+
const bodyId = `cc-group-${id}-body`;
|
|
4471
5223
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
4472
5224
|
className: divided ? "cc-group cc-groupDivided" : "cc-group",
|
|
4473
|
-
"aria-
|
|
5225
|
+
"aria-labelledby": titleId,
|
|
4474
5226
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4475
5227
|
className: "cc-groupHead",
|
|
4476
5228
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
4477
|
-
className: "cc-
|
|
4478
|
-
children:
|
|
5229
|
+
className: "cc-groupHeading",
|
|
5230
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5231
|
+
type: "button",
|
|
5232
|
+
className: "cc-disclosure",
|
|
5233
|
+
"aria-expanded": expanded,
|
|
5234
|
+
"aria-controls": bodyId,
|
|
5235
|
+
onClick: onToggle,
|
|
5236
|
+
children: [
|
|
5237
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
5238
|
+
name: "chevron",
|
|
5239
|
+
className: expanded ? "cc-icon cc-foldChevron" : "cc-icon cc-foldChevron cc-foldChevronClosed"
|
|
5240
|
+
}),
|
|
5241
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5242
|
+
id: titleId,
|
|
5243
|
+
className: "cc-groupTitle",
|
|
5244
|
+
children: title
|
|
5245
|
+
}),
|
|
5246
|
+
badges
|
|
5247
|
+
]
|
|
5248
|
+
})
|
|
4479
5249
|
}), action]
|
|
4480
5250
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4481
|
-
|
|
4482
|
-
|
|
5251
|
+
id: bodyId,
|
|
5252
|
+
className: "cc-groupBody",
|
|
5253
|
+
hidden: !expanded,
|
|
5254
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5255
|
+
className: "cc-rows",
|
|
5256
|
+
children
|
|
5257
|
+
})
|
|
4483
5258
|
})]
|
|
4484
5259
|
});
|
|
4485
5260
|
}
|
|
4486
5261
|
/**
|
|
4487
|
-
*
|
|
4488
|
-
*
|
|
4489
|
-
*
|
|
4490
|
-
* the two cannot drift apart in either markup or behaviour.
|
|
4491
|
-
*
|
|
4492
|
-
* The title is a `span`, not the `h3` a static group uses, because a heading
|
|
4493
|
-
* element cannot sit inside a button — the same trade-off Advanced has always
|
|
4494
|
-
* made on its own.
|
|
5262
|
+
* A heading's neutral summary as quiet text ("3 allowlisted · 1 customized"),
|
|
5263
|
+
* like the harness's own section captions; only warnings and errors get a
|
|
5264
|
+
* tinted pill, so a pill always means "look here". Empty parts are skipped.
|
|
4495
5265
|
*/
|
|
4496
|
-
function
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
className: "cc-
|
|
4500
|
-
|
|
4501
|
-
"aria-controls": bodyId,
|
|
4502
|
-
onClick: onToggle,
|
|
4503
|
-
children: [
|
|
4504
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4505
|
-
className: "cc-groupTitle",
|
|
4506
|
-
children: title
|
|
4507
|
-
}),
|
|
4508
|
-
badges?.(expanded),
|
|
4509
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
4510
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4511
|
-
className: expanded ? "cc-chevron cc-chevronUp" : "cc-chevron",
|
|
4512
|
-
"aria-hidden": "true"
|
|
4513
|
-
})
|
|
4514
|
-
]
|
|
5266
|
+
function GroupSummary({ parts }) {
|
|
5267
|
+
const text = parts.filter((part) => part !== void 0 && part !== "").join(" · ");
|
|
5268
|
+
return text === "" ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5269
|
+
className: "cc-groupSummary",
|
|
5270
|
+
children: text
|
|
4515
5271
|
});
|
|
4516
5272
|
}
|
|
5273
|
+
/** "N customized" for a heading summary; undefined at zero. */
|
|
5274
|
+
function overriddenText(count, t) {
|
|
5275
|
+
if (count === 0) return void 0;
|
|
5276
|
+
return count === 1 ? t("groupOverriddenOne") : t("groupOverriddenMany", { count });
|
|
5277
|
+
}
|
|
4517
5278
|
/**
|
|
4518
|
-
*
|
|
4519
|
-
*
|
|
4520
|
-
*
|
|
4521
|
-
* folding can never turn into a stored preference the settings document would
|
|
4522
|
-
* have to carry.
|
|
5279
|
+
* The badge a FOLDED group shows while something inside it blocks the save:
|
|
5280
|
+
* its rows are off screen, so without it Save would sit disabled with nothing
|
|
5281
|
+
* visible explaining why (issue #94). Expanded, the row errors speak for it.
|
|
4523
5282
|
*/
|
|
4524
|
-
function
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
children: [
|
|
4530
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DisclosureHead, {
|
|
4531
|
-
title,
|
|
4532
|
-
bodyId,
|
|
4533
|
-
expanded,
|
|
4534
|
-
onToggle: () => setExpanded((value) => !value),
|
|
4535
|
-
badges
|
|
4536
|
-
}),
|
|
4537
|
-
expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4538
|
-
id: bodyId,
|
|
4539
|
-
className: "cc-rows",
|
|
4540
|
-
children
|
|
4541
|
-
}) : null,
|
|
4542
|
-
expanded ? footer : null
|
|
4543
|
-
]
|
|
4544
|
-
});
|
|
5283
|
+
function InvalidBadge({ show, t }) {
|
|
5284
|
+
return show ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5285
|
+
className: "cc-badge cc-badgeError",
|
|
5286
|
+
children: t("groupInvalid")
|
|
5287
|
+
}) : null;
|
|
4545
5288
|
}
|
|
4546
5289
|
/**
|
|
4547
5290
|
* Models & context: the plan filter and the allowlist sit together because both
|
|
@@ -4549,21 +5292,20 @@ window.__ModuleLoader__.load({
|
|
|
4549
5292
|
* filter), and the context-length fields follow them because they are the same
|
|
4550
5293
|
* subject seen from the other side — the window each listed model advertises.
|
|
4551
5294
|
* Those fields carry no heading or divider of their own: they are rows of this
|
|
4552
|
-
* group, not a section inside it.
|
|
4553
|
-
*
|
|
4554
|
-
*
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollapsibleGroup, {
|
|
5295
|
+
* group, not a section inside it. Folded by default like every group but
|
|
5296
|
+
* Accounts; the heading then summarizes the allowlist size and how much of the
|
|
5297
|
+
* group is customized.
|
|
5298
|
+
*/
|
|
5299
|
+
function ModelsCard({ state, disabled, t, onEdit, onReset, onSelect, onClear, onOverrides, expanded, onToggle }) {
|
|
5300
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FoldableGroup, {
|
|
5301
|
+
id: "models",
|
|
4560
5302
|
title: t("modelsTitle"),
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
badges: (
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
})
|
|
5303
|
+
expanded,
|
|
5304
|
+
onToggle,
|
|
5305
|
+
badges: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupSummary, { parts: [state.visibleModelsAll ? t("visibleModelsSummaryAll") : t("visibleModelsSummary", { count: state.visibleModels.length }), overriddenText(modelsOverriddenCount(state), t)] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InvalidBadge, {
|
|
5306
|
+
show: !expanded && modelsGroupInvalid(state),
|
|
5307
|
+
t
|
|
5308
|
+
})] }),
|
|
4567
5309
|
children: [
|
|
4568
5310
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
4569
5311
|
id: "cc-filter-models-by-plan",
|
|
@@ -4653,6 +5395,8 @@ window.__ModuleLoader__.load({
|
|
|
4653
5395
|
state: state.contextWindow,
|
|
4654
5396
|
disabled,
|
|
4655
5397
|
context: true,
|
|
5398
|
+
unit: t("unitTokens"),
|
|
5399
|
+
placeholder: t("placeholderCatalog"),
|
|
4656
5400
|
onEdit: (text) => onEdit("contextWindow", text),
|
|
4657
5401
|
onReset: () => onReset("contextWindow"),
|
|
4658
5402
|
t
|
|
@@ -4665,6 +5409,8 @@ window.__ModuleLoader__.load({
|
|
|
4665
5409
|
disabled,
|
|
4666
5410
|
numeric: true,
|
|
4667
5411
|
output: true,
|
|
5412
|
+
unit: t("unitTokens"),
|
|
5413
|
+
placeholder: t("placeholderAuto"),
|
|
4668
5414
|
onEdit: (text) => onEdit("maxOutputTokens", text),
|
|
4669
5415
|
onReset: () => onReset("maxOutputTokens"),
|
|
4670
5416
|
t
|
|
@@ -4672,9 +5418,13 @@ window.__ModuleLoader__.load({
|
|
|
4672
5418
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingRow, {
|
|
4673
5419
|
title: t("contextOverridesTitle"),
|
|
4674
5420
|
description: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("contextOverridesHint") }),
|
|
4675
|
-
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4676
|
-
|
|
4677
|
-
|
|
5421
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5422
|
+
variant: "outline",
|
|
5423
|
+
size: "sm",
|
|
5424
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
5425
|
+
name: "plus",
|
|
5426
|
+
className: "cc-icon cc-btnIcon"
|
|
5427
|
+
}),
|
|
4678
5428
|
disabled: disabled || available.length === 0,
|
|
4679
5429
|
onClick: addRow,
|
|
4680
5430
|
children: t("contextOverrideAdd")
|
|
@@ -4685,78 +5435,80 @@ window.__ModuleLoader__.load({
|
|
|
4685
5435
|
children: t("contextOverrideNoCatalog")
|
|
4686
5436
|
}) : null,
|
|
4687
5437
|
rows.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4688
|
-
className: "cc-
|
|
4689
|
-
children: [
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
children: t("contextOverrideModel")
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
}) : null,
|
|
4704
|
-
rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4705
|
-
className: "cc-contextItem",
|
|
4706
|
-
children: [
|
|
4707
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4708
|
-
className: "cc-contextSelect",
|
|
4709
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
4710
|
-
className: "cc-input cc-contextModel",
|
|
4711
|
-
value: row.model,
|
|
4712
|
-
"aria-label": t("contextOverrideModel"),
|
|
4713
|
-
disabled,
|
|
4714
|
-
onChange: (event) => setModel(row.model, event.target.value),
|
|
4715
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5438
|
+
className: "cc-contextTable",
|
|
5439
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5440
|
+
className: "cc-contextHead",
|
|
5441
|
+
children: [
|
|
5442
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("contextOverrideModel") }),
|
|
5443
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("contextOverrideValue") }),
|
|
5444
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { "aria-hidden": "true" })
|
|
5445
|
+
]
|
|
5446
|
+
}), rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5447
|
+
className: "cc-contextItem",
|
|
5448
|
+
children: [
|
|
5449
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5450
|
+
className: "cc-contextSelect",
|
|
5451
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
5452
|
+
className: "cc-fieldInput cc-contextModel",
|
|
4716
5453
|
value: row.model,
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
children:
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
5454
|
+
"aria-label": t("contextOverrideModel"),
|
|
5455
|
+
disabled,
|
|
5456
|
+
onChange: (event) => setModel(row.model, event.target.value),
|
|
5457
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5458
|
+
value: row.model,
|
|
5459
|
+
children: labelOf(row.model)
|
|
5460
|
+
}), available.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
5461
|
+
value: model.id,
|
|
5462
|
+
children: labelOf(model.id)
|
|
5463
|
+
}, model.id))]
|
|
5464
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
5465
|
+
name: "chevron",
|
|
5466
|
+
className: "cc-icon cc-contextCaret"
|
|
5467
|
+
})]
|
|
5468
|
+
}),
|
|
5469
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5470
|
+
className: row.invalid ? "cc-unitBox cc-unitBoxInvalid" : "cc-unitBox",
|
|
5471
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5472
|
+
className: "cc-fieldInput",
|
|
5473
|
+
type: "text",
|
|
5474
|
+
"aria-label": t("contextOverrideValue"),
|
|
5475
|
+
"aria-invalid": row.invalid || void 0,
|
|
5476
|
+
value: row.text,
|
|
5477
|
+
disabled,
|
|
5478
|
+
onChange: (event) => setText(row.model, event.target.value)
|
|
5479
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5480
|
+
className: "cc-unit",
|
|
5481
|
+
children: t("unitTokens")
|
|
5482
|
+
})]
|
|
5483
|
+
}),
|
|
5484
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5485
|
+
type: "button",
|
|
5486
|
+
className: "cc-iconButton",
|
|
5487
|
+
"aria-label": t("contextOverrideRemove"),
|
|
5488
|
+
disabled,
|
|
5489
|
+
onClick: () => removeRow(row.model),
|
|
5490
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
|
|
5491
|
+
}),
|
|
5492
|
+
row.invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5493
|
+
className: "cc-rowError cc-contextError",
|
|
5494
|
+
children: invalidCopy(row.invalidReason, t, "context")
|
|
5495
|
+
}) : null
|
|
5496
|
+
]
|
|
5497
|
+
}, row.model))]
|
|
5498
|
+
}) : null
|
|
4750
5499
|
] });
|
|
4751
5500
|
}
|
|
4752
5501
|
/**
|
|
4753
5502
|
* Privacy & security: the opt-in that changes where data goes. ZDR restricts
|
|
4754
5503
|
* which upstream serves a request, so it starts off.
|
|
4755
5504
|
*/
|
|
4756
|
-
function PrivacyCard({ state, disabled, t, onEdit, onReset }) {
|
|
4757
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5505
|
+
function PrivacyCard({ state, disabled, t, onEdit, onReset, expanded, onToggle }) {
|
|
5506
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldableGroup, {
|
|
5507
|
+
id: "privacy",
|
|
4758
5508
|
title: t("privacyTitle"),
|
|
4759
|
-
|
|
5509
|
+
expanded,
|
|
5510
|
+
onToggle,
|
|
5511
|
+
badges: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupSummary, { parts: [stagedSwitch(state.zdr, false) ? t("zdrSummaryOn") : t("zdrSummaryOff")] }),
|
|
4760
5512
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
4761
5513
|
id: "cc-zdr",
|
|
4762
5514
|
label: t("zdr"),
|
|
@@ -4770,59 +5522,161 @@ window.__ModuleLoader__.load({
|
|
|
4770
5522
|
})
|
|
4771
5523
|
});
|
|
4772
5524
|
}
|
|
4773
|
-
/**
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
5525
|
+
/**
|
|
5526
|
+
* The service-status row: the official status page's published record and the
|
|
5527
|
+
* Host's live probe of the configured API base, both projected by
|
|
5528
|
+
* ./service-status.ts (source order, cache TTL, the lag rule and every
|
|
5529
|
+
* degradation path live there). It is display-only — it writes no setting and
|
|
5530
|
+
* never blocks Save; the link opens the page for the full history.
|
|
5531
|
+
*/
|
|
5532
|
+
function ServiceStatusRow({ view, t }) {
|
|
5533
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingRow, {
|
|
5534
|
+
title: t("serviceStatusTitle"),
|
|
5535
|
+
description: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5536
|
+
className: "cc-statusLines",
|
|
5537
|
+
children: [
|
|
5538
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5539
|
+
className: "cc-statusKey",
|
|
5540
|
+
children: t("serviceStatusOfficial")
|
|
5541
|
+
}),
|
|
5542
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5543
|
+
className: "cc-statusValue",
|
|
5544
|
+
children: [
|
|
5545
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
5546
|
+
state: toneDot(view.officialTone),
|
|
5547
|
+
size: 8
|
|
5548
|
+
}),
|
|
5549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5550
|
+
className: "cc-statusVerdict",
|
|
5551
|
+
children: view.label
|
|
5552
|
+
}),
|
|
5553
|
+
view.detail !== void 0 || view.updated !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5554
|
+
className: "cc-statusMeta",
|
|
5555
|
+
children: [
|
|
5556
|
+
view.detail,
|
|
5557
|
+
view.detail !== void 0 && view.updated !== void 0 ? "\xA0· " : null,
|
|
5558
|
+
view.updated !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5559
|
+
title: view.lag ?? view.hint,
|
|
5560
|
+
children: view.updated
|
|
5561
|
+
}) : null
|
|
5562
|
+
]
|
|
5563
|
+
}) : null
|
|
5564
|
+
]
|
|
5565
|
+
}),
|
|
5566
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5567
|
+
className: "cc-statusKey",
|
|
5568
|
+
children: t("serviceStatusLocal")
|
|
5569
|
+
}),
|
|
5570
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5571
|
+
className: "cc-statusValue",
|
|
5572
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
5573
|
+
state: localDotState(view),
|
|
5574
|
+
size: 8
|
|
5575
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5576
|
+
className: view.localTone === "error" ? "cc-statusVerdict cc-statusBad" : "cc-statusVerdict",
|
|
5577
|
+
children: view.local
|
|
5578
|
+
})]
|
|
5579
|
+
})
|
|
5580
|
+
]
|
|
5581
|
+
}), view.notice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5582
|
+
className: "cc-statusNotice",
|
|
5583
|
+
children: view.notice
|
|
5584
|
+
}) : null] }),
|
|
5585
|
+
control: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
5586
|
+
className: "cc-statusLink",
|
|
5587
|
+
href: STATUS_PAGE_URL,
|
|
5588
|
+
target: "_blank",
|
|
5589
|
+
rel: "noreferrer",
|
|
5590
|
+
children: view.linkLabel
|
|
5591
|
+
})
|
|
5592
|
+
});
|
|
5593
|
+
}
|
|
5594
|
+
/**
|
|
5595
|
+
* The status dot and verdict, shared by the status row and the Integrations
|
|
5596
|
+
* heading. The primitive's five states already carry the theme's
|
|
5597
|
+
* success/warn/error tokens, so the colours are the design system's own.
|
|
5598
|
+
*/
|
|
5599
|
+
function ServiceStatusBadge({ view }) {
|
|
5600
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5601
|
+
className: "cc-statusBadge",
|
|
5602
|
+
title: view.hint,
|
|
5603
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: toneDot(view.badge.tone) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5604
|
+
className: view.badge.tone === "warn" || view.badge.tone === "error" ? "cc-statusLabel cc-statusBad" : "cc-statusLabel",
|
|
5605
|
+
children: view.badge.label
|
|
4798
5606
|
})]
|
|
4799
5607
|
});
|
|
4800
5608
|
}
|
|
5609
|
+
/** A view tone on the harness StateDot. */
|
|
5610
|
+
function toneDot(tone) {
|
|
5611
|
+
return tone === "ok" ? "done" : tone === "warn" ? "warning" : tone === "error" ? "error" : tone === "checking" ? "ongoing" : "idle";
|
|
5612
|
+
}
|
|
5613
|
+
/**
|
|
5614
|
+
* The local probe's dot: done/error once it answered, breathing while the
|
|
5615
|
+
* request is in flight, idle when the Host offers no probe at all.
|
|
5616
|
+
*/
|
|
5617
|
+
function localDotState(view) {
|
|
5618
|
+
if (view.localTone === "ok") return "done";
|
|
5619
|
+
if (view.localTone === "error") return "error";
|
|
5620
|
+
return view.localChecking ? "ongoing" : "idle";
|
|
5621
|
+
}
|
|
5622
|
+
/**
|
|
5623
|
+
* Integrations & display: surfaces outside chat that reuse this provider. The
|
|
5624
|
+
* status snapshot comes from the page, which probes once per open even while
|
|
5625
|
+
* this group is folded — its heading shows the verdict either way.
|
|
5626
|
+
*/
|
|
5627
|
+
function IntegrationsCard({ state, disabled, t, onEdit, onReset, expanded, onToggle, status, probe }) {
|
|
5628
|
+
const view = serviceStatusView(status, probe, t, Date.now());
|
|
5629
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FoldableGroup, {
|
|
5630
|
+
id: "integrations",
|
|
5631
|
+
title: t("integrationsTitle"),
|
|
5632
|
+
expanded,
|
|
5633
|
+
onToggle,
|
|
5634
|
+
badges: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServiceStatusBadge, { view }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupSummary, { parts: [stagedSwitch(state.webSearch, true) ? t("webSearchSummaryOn") : t("webSearchSummaryOff")] })] }),
|
|
5635
|
+
children: [
|
|
5636
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServiceStatusRow, {
|
|
5637
|
+
view,
|
|
5638
|
+
t
|
|
5639
|
+
}),
|
|
5640
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
5641
|
+
id: "cc-web-search",
|
|
5642
|
+
label: t("webSearch"),
|
|
5643
|
+
hint: t("webSearchHint"),
|
|
5644
|
+
state: state.webSearch,
|
|
5645
|
+
disabled,
|
|
5646
|
+
defaultChecked: true,
|
|
5647
|
+
onEdit: (text) => onEdit("webSearch", text),
|
|
5648
|
+
onReset: () => onReset("webSearch"),
|
|
5649
|
+
t
|
|
5650
|
+
}),
|
|
5651
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
5652
|
+
id: "cc-show-sidebar-quota",
|
|
5653
|
+
label: t("showSidebarQuota"),
|
|
5654
|
+
hint: t("showSidebarQuotaHint"),
|
|
5655
|
+
state: state.showSidebarQuota,
|
|
5656
|
+
disabled,
|
|
5657
|
+
defaultChecked: false,
|
|
5658
|
+
onEdit: (text) => onEdit("showSidebarQuota", text),
|
|
5659
|
+
onReset: () => onReset("showSidebarQuota"),
|
|
5660
|
+
t
|
|
5661
|
+
})
|
|
5662
|
+
]
|
|
5663
|
+
});
|
|
5664
|
+
}
|
|
4801
5665
|
/**
|
|
4802
|
-
* The
|
|
4803
|
-
*
|
|
4804
|
-
*
|
|
4805
|
-
* count and an invalid number (which blocks save) is surfaced on the header.
|
|
5666
|
+
* The "Advanced" group: the API base and the network limits. Its heading
|
|
5667
|
+
* names the customized count, and while folded, an invalid number (which
|
|
5668
|
+
* blocks save); expanded, the row's own error says it.
|
|
4806
5669
|
*/
|
|
4807
|
-
function AdvancedSection({ state, disabled, t, onEdit, onReset }) {
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CollapsibleGroup, {
|
|
5670
|
+
function AdvancedSection({ state, disabled, t, onEdit, onReset, expanded, onToggle }) {
|
|
5671
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FoldableGroup, {
|
|
5672
|
+
id: "advanced",
|
|
4811
5673
|
title: t("advancedSettings"),
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
badges:
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
})
|
|
4818
|
-
className: "cc-badge cc-badgeWarn",
|
|
4819
|
-
children: t("advancedInvalid")
|
|
4820
|
-
}) : null] }),
|
|
4821
|
-
footer: invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4822
|
-
className: "cc-rowError",
|
|
4823
|
-
role: "status",
|
|
4824
|
-
children: t("advancedInvalid")
|
|
4825
|
-
}) : null,
|
|
5674
|
+
expanded,
|
|
5675
|
+
onToggle,
|
|
5676
|
+
badges: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupSummary, { parts: [overriddenText(advancedOverriddenCount(state), t)] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InvalidBadge, {
|
|
5677
|
+
show: !expanded && advancedGroupInvalid(state),
|
|
5678
|
+
t
|
|
5679
|
+
})] }),
|
|
4826
5680
|
children: [
|
|
4827
5681
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4828
5682
|
className: "cc-groupDesc",
|
|
@@ -4831,10 +5685,10 @@ window.__ModuleLoader__.load({
|
|
|
4831
5685
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
4832
5686
|
id: "cc-api-base",
|
|
4833
5687
|
label: t("apiBase"),
|
|
4834
|
-
hint: t("apiBaseHint"),
|
|
4835
5688
|
state: state.apiBase,
|
|
4836
5689
|
disabled,
|
|
4837
5690
|
wide: true,
|
|
5691
|
+
placeholder: FIELD_DEFAULTS.apiBase,
|
|
4838
5692
|
onEdit: (text) => onEdit("apiBase", text),
|
|
4839
5693
|
onReset: () => onReset("apiBase"),
|
|
4840
5694
|
t
|
|
@@ -4847,6 +5701,8 @@ window.__ModuleLoader__.load({
|
|
|
4847
5701
|
disabled,
|
|
4848
5702
|
numeric: true,
|
|
4849
5703
|
decimal: true,
|
|
5704
|
+
unit: t("unitSeconds"),
|
|
5705
|
+
placeholder: FIELD_DEFAULTS.requestTimeoutSeconds,
|
|
4850
5706
|
onEdit: (text) => onEdit("requestTimeoutMs", text),
|
|
4851
5707
|
onReset: () => onReset("requestTimeoutMs"),
|
|
4852
5708
|
t
|
|
@@ -4859,6 +5715,8 @@ window.__ModuleLoader__.load({
|
|
|
4859
5715
|
disabled,
|
|
4860
5716
|
numeric: true,
|
|
4861
5717
|
decimal: true,
|
|
5718
|
+
unit: t("unitSeconds"),
|
|
5719
|
+
placeholder: FIELD_DEFAULTS.streamIdleTimeoutSeconds,
|
|
4862
5720
|
onEdit: (text) => onEdit("streamIdleTimeoutMs", text),
|
|
4863
5721
|
onReset: () => onReset("streamIdleTimeoutMs"),
|
|
4864
5722
|
t
|
|
@@ -4870,6 +5728,8 @@ window.__ModuleLoader__.load({
|
|
|
4870
5728
|
state: state.transportMaxRetries,
|
|
4871
5729
|
disabled,
|
|
4872
5730
|
numeric: true,
|
|
5731
|
+
unit: t("unitRetries"),
|
|
5732
|
+
placeholder: FIELD_DEFAULTS.transportMaxRetries,
|
|
4873
5733
|
onEdit: (text) => onEdit("transportMaxRetries", text),
|
|
4874
5734
|
onReset: () => onReset("transportMaxRetries"),
|
|
4875
5735
|
t
|
|
@@ -5044,21 +5904,22 @@ window.__ModuleLoader__.load({
|
|
|
5044
5904
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5045
5905
|
className: "cc-inlineActions",
|
|
5046
5906
|
children: [
|
|
5047
|
-
secret && value !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5907
|
+
secret && value !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5908
|
+
variant: "ghost",
|
|
5909
|
+
size: "sm",
|
|
5048
5910
|
type: "button",
|
|
5049
|
-
className: "cc-reset",
|
|
5050
5911
|
onClick: () => setVisible((shown) => !shown),
|
|
5051
5912
|
children: visible ? t("hide") : t("show")
|
|
5052
5913
|
}) : null,
|
|
5053
5914
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
5054
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5915
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5055
5916
|
variant: "ghost",
|
|
5056
5917
|
size: "sm",
|
|
5057
5918
|
type: "button",
|
|
5058
5919
|
onClick: onCancel,
|
|
5059
5920
|
children: t("cancel")
|
|
5060
5921
|
}),
|
|
5061
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5922
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5062
5923
|
variant: "primary",
|
|
5063
5924
|
size: "sm",
|
|
5064
5925
|
type: "submit",
|
|
@@ -5069,35 +5930,26 @@ window.__ModuleLoader__.load({
|
|
|
5069
5930
|
})]
|
|
5070
5931
|
});
|
|
5071
5932
|
}
|
|
5072
|
-
/** A destructive confirmation
|
|
5933
|
+
/** A destructive confirmation, shown in place in the card as an error notice (no modal). */
|
|
5073
5934
|
function ConfirmBar({ text, confirmLabel, disabled, t, onConfirm, onCancel }) {
|
|
5074
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
5075
|
-
|
|
5935
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
5936
|
+
tone: "error",
|
|
5937
|
+
icon: "warn",
|
|
5076
5938
|
role: "alertdialog",
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5092
|
-
variant: "outline",
|
|
5093
|
-
size: "sm",
|
|
5094
|
-
className: "cc-dangerButton",
|
|
5095
|
-
disabled,
|
|
5096
|
-
onClick: onConfirm,
|
|
5097
|
-
children: confirmLabel
|
|
5098
|
-
})
|
|
5099
|
-
]
|
|
5100
|
-
})]
|
|
5939
|
+
label: text,
|
|
5940
|
+
title: text,
|
|
5941
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5942
|
+
variant: "danger",
|
|
5943
|
+
size: "sm",
|
|
5944
|
+
disabled,
|
|
5945
|
+
onClick: onConfirm,
|
|
5946
|
+
children: confirmLabel
|
|
5947
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5948
|
+
variant: "ghost",
|
|
5949
|
+
size: "sm",
|
|
5950
|
+
onClick: onCancel,
|
|
5951
|
+
children: t("cancel")
|
|
5952
|
+
})] })
|
|
5101
5953
|
});
|
|
5102
5954
|
}
|
|
5103
5955
|
/** One account row: identity, status, quota summary, actions and expandable details. */
|
|
@@ -5206,11 +6058,11 @@ window.__ModuleLoader__.load({
|
|
|
5206
6058
|
children: accountName
|
|
5207
6059
|
}) : null,
|
|
5208
6060
|
planName !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5209
|
-
className: "cc-
|
|
6061
|
+
className: "cc-badge cc-badgeOutline",
|
|
5210
6062
|
children: planName
|
|
5211
6063
|
}) : null,
|
|
5212
6064
|
entry?.active && multi ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5213
|
-
className: "cc-badge",
|
|
6065
|
+
className: "cc-badge cc-badgeOk",
|
|
5214
6066
|
children: t("usageActive")
|
|
5215
6067
|
}) : null,
|
|
5216
6068
|
pinned ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -5218,21 +6070,21 @@ window.__ModuleLoader__.load({
|
|
|
5218
6070
|
children: t("accountStatusPinned")
|
|
5219
6071
|
}) : null,
|
|
5220
6072
|
!row.credentialKnown || !row.configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5221
|
-
className: "cc-
|
|
6073
|
+
className: "cc-badge cc-badgeOutline",
|
|
5222
6074
|
children: t(row.credentialKnown ? "apiKeyUnset" : "writeStateUnknown")
|
|
5223
6075
|
}) : null,
|
|
5224
6076
|
entry?.mark === "invalid-credential" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5225
|
-
className: "cc-
|
|
6077
|
+
className: "cc-badge cc-badgeError",
|
|
5226
6078
|
children: t("usageInvalidKey")
|
|
5227
6079
|
}) : null,
|
|
5228
6080
|
entry !== void 0 && entry.mark !== "invalid-credential" && (entry.cooldownUntil > 0 || entry.mark === "rate-limit") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5229
|
-
className: "cc-
|
|
5230
|
-
children: [t("usageCooldown"), entry.cooldownUntil > 0 ? ` ${
|
|
6081
|
+
className: "cc-badge cc-badgeWarn",
|
|
6082
|
+
children: [t("usageCooldown"), entry.cooldownUntil > 0 ? ` ${formatResetAtShort(entry.cooldownUntil)}` : ""]
|
|
5231
6083
|
}) : null,
|
|
5232
6084
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
5233
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5234
|
-
|
|
5235
|
-
"
|
|
6085
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6086
|
+
name: "chevron",
|
|
6087
|
+
className: expanded ? "cc-icon cc-foldChevron cc-chevronOpen" : "cc-icon cc-foldChevron"
|
|
5236
6088
|
})
|
|
5237
6089
|
]
|
|
5238
6090
|
}), items.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
@@ -5250,14 +6102,11 @@ window.__ModuleLoader__.load({
|
|
|
5250
6102
|
"aria-haspopup": "menu",
|
|
5251
6103
|
"aria-expanded": menuOpen,
|
|
5252
6104
|
onClick: () => setMenuOpen((value) => !value),
|
|
5253
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
5254
|
-
className: "cc-kebab",
|
|
5255
|
-
"aria-hidden": "true"
|
|
5256
|
-
})
|
|
6105
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "more" })
|
|
5257
6106
|
})
|
|
5258
6107
|
}) : null]
|
|
5259
6108
|
}),
|
|
5260
|
-
credits !== void 0 && (credits.fiveHour !== void 0 || credits.weekly !== void 0 || monthlyReported) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6109
|
+
!expanded && credits !== void 0 && (credits.fiveHour !== void 0 || credits.weekly !== void 0 || monthlyReported) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5261
6110
|
className: "cc-accountMeters",
|
|
5262
6111
|
children: [
|
|
5263
6112
|
credits.fiveHour !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MiniMeter, {
|
|
@@ -5274,60 +6123,61 @@ window.__ModuleLoader__.load({
|
|
|
5274
6123
|
}) : null
|
|
5275
6124
|
]
|
|
5276
6125
|
}) : null,
|
|
5277
|
-
row.credentialKnown && !row.configured && row.managed && mode === void 0 && !showLogin ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
5278
|
-
|
|
5279
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
children:
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
size: "sm",
|
|
5293
|
-
onClick: () => setMode("key"),
|
|
5294
|
-
children: t("accountAddPaste")
|
|
5295
|
-
})]
|
|
5296
|
-
}) : null]
|
|
6126
|
+
row.credentialKnown && !row.configured && row.managed && mode === void 0 && !showLogin ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6127
|
+
icon: row.keyWritable ? "info" : "lock",
|
|
6128
|
+
actions: keyActions ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6129
|
+
variant: "primary",
|
|
6130
|
+
size: "sm",
|
|
6131
|
+
disabled: loginBusy || busyElsewhere,
|
|
6132
|
+
onClick: () => actions.beginLogin(loginTarget),
|
|
6133
|
+
children: t("accountAddLogin")
|
|
6134
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6135
|
+
variant: "outline",
|
|
6136
|
+
size: "sm",
|
|
6137
|
+
onClick: () => setMode("key"),
|
|
6138
|
+
children: t("accountAddPaste")
|
|
6139
|
+
})] }) : void 0,
|
|
6140
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: row.keyWritable ? t("accountNoKeyHint") : t("apiKeyLocked") })
|
|
5297
6141
|
}) : null,
|
|
5298
6142
|
showLogin ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoginStatus, {
|
|
5299
|
-
state: loginState,
|
|
5300
|
-
t,
|
|
5301
|
-
onCancel: actions.cancelLogin
|
|
5302
|
-
}) : null,
|
|
5303
|
-
mode === "key" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineInput, {
|
|
5304
|
-
id: `cc-account-${row.id}-key`,
|
|
5305
|
-
label: t("accountKeyPlaceholder"),
|
|
5306
|
-
secret: true,
|
|
5307
|
-
placeholder: t("accountKeyPlaceholder"),
|
|
5308
|
-
confirmLabel: t("accountApply"),
|
|
5309
|
-
disabled: disabled || state.accountBusy,
|
|
5310
|
-
t,
|
|
5311
|
-
onCancel: () => setMode(void 0),
|
|
5312
|
-
onSubmit: (value) => {
|
|
5313
|
-
actions.setKey(row.id, value).then((ok) => {
|
|
5314
|
-
if (ok) setMode(void 0);
|
|
5315
|
-
});
|
|
5316
|
-
}
|
|
5317
|
-
}) : null,
|
|
5318
|
-
mode === "rename" && row.ref !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineInput, {
|
|
5319
|
-
id: `cc-account-${row.id}-rename`,
|
|
5320
|
-
label: t("accountActionRename"),
|
|
5321
|
-
initial: row.label,
|
|
5322
|
-
confirmLabel: t("accountApply"),
|
|
5323
|
-
disabled: disabled || state.accountBusy,
|
|
6143
|
+
state: loginState,
|
|
5324
6144
|
t,
|
|
5325
|
-
onCancel:
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
6145
|
+
onCancel: actions.cancelLogin
|
|
6146
|
+
}) : null,
|
|
6147
|
+
mode === "key" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6148
|
+
className: "cc-panel",
|
|
6149
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineInput, {
|
|
6150
|
+
id: `cc-account-${row.id}-key`,
|
|
6151
|
+
label: t("accountKeyPlaceholder"),
|
|
6152
|
+
secret: true,
|
|
6153
|
+
placeholder: t("accountKeyPlaceholder"),
|
|
6154
|
+
confirmLabel: t("accountApply"),
|
|
6155
|
+
disabled: disabled || state.accountBusy,
|
|
6156
|
+
t,
|
|
6157
|
+
onCancel: () => setMode(void 0),
|
|
6158
|
+
onSubmit: (value) => {
|
|
6159
|
+
actions.setKey(row.id, value).then((ok) => {
|
|
6160
|
+
if (ok) setMode(void 0);
|
|
6161
|
+
});
|
|
6162
|
+
}
|
|
6163
|
+
})
|
|
6164
|
+
}) : null,
|
|
6165
|
+
mode === "rename" && row.ref !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6166
|
+
className: "cc-panel",
|
|
6167
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineInput, {
|
|
6168
|
+
id: `cc-account-${row.id}-rename`,
|
|
6169
|
+
label: t("accountActionRename"),
|
|
6170
|
+
initial: row.label,
|
|
6171
|
+
confirmLabel: t("accountApply"),
|
|
6172
|
+
disabled: disabled || state.accountBusy,
|
|
6173
|
+
t,
|
|
6174
|
+
onCancel: () => setMode(void 0),
|
|
6175
|
+
onSubmit: (value) => {
|
|
6176
|
+
actions.rename(row.ref, value).then((ok) => {
|
|
6177
|
+
if (ok) setMode(void 0);
|
|
6178
|
+
});
|
|
6179
|
+
}
|
|
6180
|
+
})
|
|
5331
6181
|
}) : null,
|
|
5332
6182
|
mode === "remove" && row.ref !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConfirmBar, {
|
|
5333
6183
|
text: t("accountRemoveConfirm", { name: row.label }),
|
|
@@ -5389,163 +6239,218 @@ window.__ModuleLoader__.load({
|
|
|
5389
6239
|
function LoginStatus({ state, t, onCancel }) {
|
|
5390
6240
|
const hint = loginHint(state, t);
|
|
5391
6241
|
const busy = state.phase === "starting" || state.phase === "waiting";
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
6242
|
+
const tone = hint.className === "cc-loginError" ? "error" : hint.className === "cc-loginDone" ? "success" : "neutral";
|
|
6243
|
+
const link = state.authUrl !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
6244
|
+
className: "cc-loginLink",
|
|
6245
|
+
href: state.authUrl,
|
|
6246
|
+
target: "_blank",
|
|
6247
|
+
rel: "noreferrer",
|
|
6248
|
+
children: [t("loginOpenLink"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6249
|
+
name: "external",
|
|
6250
|
+
className: "cc-icon cc-iconInline"
|
|
6251
|
+
})]
|
|
6252
|
+
}) : null;
|
|
6253
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6254
|
+
tone,
|
|
6255
|
+
actions: link !== null || busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [link, busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6256
|
+
variant: "ghost",
|
|
6257
|
+
size: "sm",
|
|
6258
|
+
onClick: onCancel,
|
|
6259
|
+
children: t("loginCancel")
|
|
6260
|
+
}) : null] }) : void 0,
|
|
6261
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6262
|
+
title: hint.title,
|
|
6263
|
+
children: hint.text
|
|
6264
|
+
})
|
|
5415
6265
|
});
|
|
5416
6266
|
}
|
|
5417
|
-
/**
|
|
6267
|
+
/** Enrollment phases during which the panel only offers "cancel setup". */
|
|
6268
|
+
const ENROLLMENT_BUSY_PHASES = [
|
|
6269
|
+
"creating",
|
|
6270
|
+
"waiting",
|
|
6271
|
+
"writing",
|
|
6272
|
+
"cancelling"
|
|
6273
|
+
];
|
|
6274
|
+
/**
|
|
6275
|
+
* What the add-account panel's action row shows, from the enrollment phase
|
|
6276
|
+
* and the panel's own inputs — a pure function so the button logic is tested
|
|
6277
|
+
* without rendering:
|
|
6278
|
+
* - `naming`: the host could not save the name; retry / accept / cancel.
|
|
6279
|
+
* - `cancelSetup`: a sign-in or key write is in flight; only "cancel setup",
|
|
6280
|
+
* with the method switch and inputs locked.
|
|
6281
|
+
* - `start`: idle; cancel plus the mode's primary action ("Start sign-in", or
|
|
6282
|
+
* "Add" once a key is typed in paste mode).
|
|
6283
|
+
*/
|
|
6284
|
+
function addAccountPanelView({ phase, mode, keyReady, disabled }) {
|
|
6285
|
+
if (phase === "naming") return {
|
|
6286
|
+
actions: "naming",
|
|
6287
|
+
locked: true,
|
|
6288
|
+
canSubmit: false
|
|
6289
|
+
};
|
|
6290
|
+
if (phase !== void 0 && ENROLLMENT_BUSY_PHASES.includes(phase)) return {
|
|
6291
|
+
actions: "cancelSetup",
|
|
6292
|
+
locked: true,
|
|
6293
|
+
canSubmit: false
|
|
6294
|
+
};
|
|
6295
|
+
return {
|
|
6296
|
+
actions: "start",
|
|
6297
|
+
locked: disabled,
|
|
6298
|
+
canSubmit: !disabled && (mode === "browser" || keyReady)
|
|
6299
|
+
};
|
|
6300
|
+
}
|
|
6301
|
+
/**
|
|
6302
|
+
* 新增面板只负责输入和操作意图;账号、登录、命名与补偿由宿主过程负责。
|
|
6303
|
+
* Drawn as the design canvas does: a "sign in / paste key" segmented switch,
|
|
6304
|
+
* the optional name, the key field in paste mode, then cancel + the primary
|
|
6305
|
+
* action on the right. Leaving paste mode clears the typed key, so a key never
|
|
6306
|
+
* lingers in a field the user has moved away from.
|
|
6307
|
+
*/
|
|
5418
6308
|
function AddAccountPanel({ state, disabled, t, enrollment, snapshot, onClose }) {
|
|
5419
6309
|
const [label, setLabel] = (0, react.useState)("");
|
|
5420
|
-
const [
|
|
6310
|
+
const [mode, setMode] = (0, react.useState)("browser");
|
|
6311
|
+
const [key, setKey] = (0, react.useState)("");
|
|
6312
|
+
const [keyVisible, setKeyVisible] = (0, react.useState)(false);
|
|
5421
6313
|
const active = snapshot.active;
|
|
5422
|
-
const
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
"
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
].includes(active.phase);
|
|
6314
|
+
const view = addAccountPanelView({
|
|
6315
|
+
phase: active?.phase,
|
|
6316
|
+
mode,
|
|
6317
|
+
keyReady: key.trim() !== "",
|
|
6318
|
+
disabled
|
|
6319
|
+
});
|
|
5429
6320
|
const fallbackName = t("accountNameN", { n: state.accounts.length + 2 });
|
|
5430
6321
|
(0, react.useEffect)(() => {
|
|
5431
6322
|
if (active?.phase === "finished") onClose();
|
|
5432
6323
|
}, [active?.phase, onClose]);
|
|
5433
|
-
const start = (
|
|
5434
|
-
mode:
|
|
6324
|
+
const start = () => enrollment.begin({
|
|
6325
|
+
mode: mode === "browser" ? "browser" : "manual",
|
|
5435
6326
|
label: label.trim() || fallbackName,
|
|
5436
6327
|
automaticName: label.trim() === "",
|
|
5437
|
-
...
|
|
6328
|
+
...mode === "browser" ? {} : { key }
|
|
5438
6329
|
});
|
|
5439
6330
|
const close = () => {
|
|
5440
6331
|
enrollment.cancel();
|
|
5441
6332
|
onClose();
|
|
5442
6333
|
};
|
|
5443
|
-
|
|
5444
|
-
|
|
6334
|
+
const pick = (next) => {
|
|
6335
|
+
setMode(next);
|
|
6336
|
+
if (next === "browser") {
|
|
6337
|
+
setKey("");
|
|
6338
|
+
setKeyVisible(false);
|
|
6339
|
+
}
|
|
6340
|
+
};
|
|
6341
|
+
const waitingLink = active?.authUrl && active.phase === "waiting" ? active.authUrl : void 0;
|
|
6342
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
6343
|
+
className: "cc-panel",
|
|
5445
6344
|
"aria-label": t("accountAdd"),
|
|
6345
|
+
onSubmit: (event) => {
|
|
6346
|
+
event.preventDefault();
|
|
6347
|
+
if (view.canSubmit) start();
|
|
6348
|
+
},
|
|
5446
6349
|
children: [
|
|
5447
6350
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5448
6351
|
className: "cc-panelTitle",
|
|
5449
6352
|
children: t("accountAdd")
|
|
5450
6353
|
}),
|
|
6354
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6355
|
+
className: "cc-rowDesc",
|
|
6356
|
+
children: t("accountAddHint")
|
|
6357
|
+
}),
|
|
6358
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6359
|
+
className: "cc-seg",
|
|
6360
|
+
role: "group",
|
|
6361
|
+
"aria-label": t("accountAddMethod"),
|
|
6362
|
+
children: ["browser", "paste"].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6363
|
+
type: "button",
|
|
6364
|
+
className: mode === option ? "cc-segItem cc-segOn" : "cc-segItem",
|
|
6365
|
+
"aria-pressed": mode === option,
|
|
6366
|
+
disabled: view.locked,
|
|
6367
|
+
onClick: () => pick(option),
|
|
6368
|
+
children: option === "browser" ? t("accountAddLogin") : t("accountAddPaste")
|
|
6369
|
+
}, option))
|
|
6370
|
+
}),
|
|
5451
6371
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
5452
|
-
className: "cc-
|
|
6372
|
+
className: "cc-fieldInput cc-panelInput",
|
|
5453
6373
|
type: "text",
|
|
5454
6374
|
"aria-label": t("accountNamePlaceholder"),
|
|
5455
6375
|
placeholder: t("accountNamePlaceholder"),
|
|
5456
6376
|
value: label,
|
|
5457
|
-
disabled:
|
|
6377
|
+
disabled: view.locked,
|
|
5458
6378
|
onChange: (event) => setLabel(event.target.value)
|
|
5459
6379
|
}),
|
|
5460
|
-
|
|
5461
|
-
className: "cc-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
6380
|
+
mode === "paste" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6381
|
+
className: "cc-keyField",
|
|
6382
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
6383
|
+
id: "cc-add-account-key",
|
|
6384
|
+
className: "cc-fieldInput cc-panelInput",
|
|
6385
|
+
type: keyVisible ? "text" : "password",
|
|
6386
|
+
"aria-label": t("accountKeyPlaceholder"),
|
|
6387
|
+
placeholder: t("accountKeyPlaceholder"),
|
|
6388
|
+
autoComplete: "new-password",
|
|
6389
|
+
spellCheck: false,
|
|
6390
|
+
autoFocus: true,
|
|
6391
|
+
value: key,
|
|
6392
|
+
disabled: view.locked,
|
|
6393
|
+
onChange: (event) => setKey(event.target.value)
|
|
6394
|
+
}), key !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6395
|
+
variant: "ghost",
|
|
6396
|
+
size: "sm",
|
|
6397
|
+
disabled: view.locked,
|
|
6398
|
+
onClick: () => setKeyVisible((shown) => !shown),
|
|
6399
|
+
children: keyVisible ? t("hide") : t("show")
|
|
6400
|
+
}) : null]
|
|
5468
6401
|
}) : null,
|
|
5469
|
-
active
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
6402
|
+
active ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Notice, {
|
|
6403
|
+
actions: waitingLink !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
6404
|
+
className: "cc-loginLink",
|
|
6405
|
+
href: waitingLink,
|
|
6406
|
+
target: "_blank",
|
|
6407
|
+
rel: "noreferrer",
|
|
6408
|
+
children: [t("accountAddOpenLink"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6409
|
+
name: "external",
|
|
6410
|
+
className: "cc-icon cc-iconInline"
|
|
6411
|
+
})]
|
|
6412
|
+
}) : void 0,
|
|
6413
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(active.messageKey) }), waitingLink !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("accountAddLinkHint") }) : null]
|
|
5475
6414
|
}) : null,
|
|
5476
|
-
snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
children: t(snapshot.error)
|
|
6415
|
+
snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6416
|
+
tone: "error",
|
|
6417
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(snapshot.error) })
|
|
5480
6418
|
}) : null,
|
|
5481
|
-
|
|
5482
|
-
className: "cc-
|
|
5483
|
-
children: [
|
|
5484
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5485
|
-
variant: "primary",
|
|
5486
|
-
size: "sm",
|
|
5487
|
-
disabled,
|
|
5488
|
-
onClick: () => void enrollment.name(active.suggestedName || label || fallbackName),
|
|
5489
|
-
children: t("accountNameSaveRetry")
|
|
5490
|
-
}),
|
|
5491
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6419
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6420
|
+
className: "cc-panelActions",
|
|
6421
|
+
children: view.actions === "naming" && active !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
6422
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5492
6423
|
variant: "ghost",
|
|
5493
|
-
|
|
6424
|
+
onClick: close,
|
|
6425
|
+
children: t("cancel")
|
|
6426
|
+
}),
|
|
6427
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6428
|
+
variant: "outline",
|
|
5494
6429
|
disabled,
|
|
5495
6430
|
onClick: () => void enrollment.name(),
|
|
5496
6431
|
children: t("accountNameAcceptExisting")
|
|
5497
6432
|
}),
|
|
5498
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5499
|
-
variant: "ghost",
|
|
5500
|
-
size: "sm",
|
|
5501
|
-
onClick: close,
|
|
5502
|
-
children: t("cancel")
|
|
5503
|
-
})
|
|
5504
|
-
]
|
|
5505
|
-
}) : pasting ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineInput, {
|
|
5506
|
-
id: "cc-add-account-key",
|
|
5507
|
-
label: t("accountKeyPlaceholder"),
|
|
5508
|
-
secret: true,
|
|
5509
|
-
placeholder: t("accountKeyPlaceholder"),
|
|
5510
|
-
confirmLabel: t("accountAddConfirm"),
|
|
5511
|
-
disabled: disabled || busy,
|
|
5512
|
-
t,
|
|
5513
|
-
onCancel: close,
|
|
5514
|
-
onSubmit: (key) => {
|
|
5515
|
-
start(key);
|
|
5516
|
-
}
|
|
5517
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5518
|
-
className: "cc-inlineActions",
|
|
5519
|
-
children: [
|
|
5520
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
6433
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5521
6434
|
variant: "primary",
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
children: t("accountAddLogin")
|
|
5526
|
-
}),
|
|
5527
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5528
|
-
variant: "ghost",
|
|
5529
|
-
size: "sm",
|
|
5530
|
-
disabled: disabled || busy,
|
|
5531
|
-
onClick: () => setPasting(true),
|
|
5532
|
-
children: t("accountAddPaste")
|
|
5533
|
-
}),
|
|
5534
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
5535
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
5536
|
-
variant: "ghost",
|
|
5537
|
-
size: "sm",
|
|
5538
|
-
onClick: close,
|
|
5539
|
-
children: t("cancel")
|
|
6435
|
+
disabled,
|
|
6436
|
+
onClick: () => void enrollment.name(active.suggestedName || label || fallbackName),
|
|
6437
|
+
children: t("accountNameSaveRetry")
|
|
5540
6438
|
})
|
|
5541
|
-
]
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
6439
|
+
] }) : view.actions === "cancelSetup" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6440
|
+
variant: "ghost",
|
|
6441
|
+
onClick: close,
|
|
6442
|
+
children: t("accountAddCancel")
|
|
6443
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6444
|
+
variant: "ghost",
|
|
6445
|
+
onClick: close,
|
|
6446
|
+
children: t("cancel")
|
|
6447
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6448
|
+
variant: "primary",
|
|
6449
|
+
type: "submit",
|
|
6450
|
+
disabled: !view.canSubmit,
|
|
6451
|
+
children: mode === "browser" ? t("accountAddStart") : t("accountAddConfirm")
|
|
6452
|
+
})] })
|
|
6453
|
+
})
|
|
5549
6454
|
]
|
|
5550
6455
|
});
|
|
5551
6456
|
}
|
|
@@ -5554,7 +6459,7 @@ window.__ModuleLoader__.load({
|
|
|
5554
6459
|
* each, with its status and quota inline — so one account's facts no longer
|
|
5555
6460
|
* have to be cross-read across separate surfaces.
|
|
5556
6461
|
*/
|
|
5557
|
-
function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, openAnalytics, createEnrollment }) {
|
|
6462
|
+
function AccountsCard({ t, state, usage, login, disabled, actions, onRefresh, openAnalytics, createEnrollment, expanded, onToggle }) {
|
|
5558
6463
|
const [adding, setAdding] = (0, react.useState)(false);
|
|
5559
6464
|
const [enrollment] = (0, react.useState)(createEnrollment);
|
|
5560
6465
|
const snapshot = (0, react.useSyncExternalStore)(enrollment.store.subscribe, enrollment.store.getSnapshot);
|
|
@@ -5570,124 +6475,128 @@ window.__ModuleLoader__.load({
|
|
|
5570
6475
|
const rows = accountRows(state, usage, t).filter((row) => row.ref === void 0 || !state.accountEnrollmentRefs.includes(row.ref));
|
|
5571
6476
|
const multi = rows.length > 1;
|
|
5572
6477
|
const pinnedRow = rows.find((row) => row.id === state.activeAccount);
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
}) : null,
|
|
5591
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5592
|
-
type: "button",
|
|
5593
|
-
className: "cc-linkButton",
|
|
5594
|
-
disabled: loading,
|
|
5595
|
-
onClick: () => {
|
|
5596
|
-
onRefresh();
|
|
5597
|
-
enrollment.refresh();
|
|
5598
|
-
},
|
|
5599
|
-
children: loading ? t("usageRefreshing") : t("usageRefresh")
|
|
5600
|
-
})
|
|
5601
|
-
]
|
|
6478
|
+
const issues = accountIssues(rows.map((row) => row.usage));
|
|
6479
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(FoldableGroup, {
|
|
6480
|
+
id: "accounts",
|
|
6481
|
+
title: t("accountsTitle"),
|
|
6482
|
+
divided: false,
|
|
6483
|
+
expanded,
|
|
6484
|
+
onToggle,
|
|
6485
|
+
badges: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GroupSummary, { parts: [rows.length === 1 ? t("accountsSummaryOne") : t("accountsSummaryMany", { count: rows.length })] }), issues.count > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6486
|
+
className: issues.severe ? "cc-badge cc-badgeError" : "cc-badge cc-badgeWarn",
|
|
6487
|
+
children: t("accountsSummaryIssues", { count: issues.count })
|
|
6488
|
+
}) : null] }),
|
|
6489
|
+
action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6490
|
+
variant: "ghost",
|
|
6491
|
+
size: "sm",
|
|
6492
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6493
|
+
name: "refresh",
|
|
6494
|
+
className: "cc-icon cc-btnIcon"
|
|
5602
6495
|
}),
|
|
6496
|
+
disabled: loading,
|
|
6497
|
+
onClick: () => {
|
|
6498
|
+
onRefresh();
|
|
6499
|
+
enrollment.refresh();
|
|
6500
|
+
},
|
|
6501
|
+
children: loading ? t("usageRefreshing") : t("usageRefresh")
|
|
6502
|
+
}),
|
|
6503
|
+
children: [
|
|
5603
6504
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5604
6505
|
className: "cc-groupDesc",
|
|
5605
6506
|
children: multi ? t("accountsRotationHint") : t("accountsHint")
|
|
5606
6507
|
}),
|
|
5607
6508
|
multi ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5608
6509
|
className: "cc-accountMode",
|
|
5609
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: pinnedRow !== void 0 ? t("accountModePinned", { name: pinnedRow.label }) : t("accountModeAuto") }), pinnedRow !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5610
|
-
type: "button",
|
|
5611
|
-
className: "cc-reset",
|
|
5612
|
-
disabled: disabled || state.accountBusy,
|
|
5613
|
-
onClick: () => void actions.setActive(""),
|
|
5614
|
-
children: t("accountActionUnpin")
|
|
5615
|
-
}) : null]
|
|
5616
|
-
}) : null,
|
|
5617
|
-
usage.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
5618
|
-
className: "cc-rowError",
|
|
5619
|
-
role: "status",
|
|
5620
|
-
children: [t("usageError"), usage.error !== void 0 && usage.error !== "" ? ` — ${usage.error}` : ""]
|
|
5621
|
-
}) : null,
|
|
5622
|
-
settingsWriteNotice(state.accountResult, t) || state.accountFailed !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5623
|
-
className: "cc-rowError",
|
|
5624
|
-
role: "status",
|
|
5625
|
-
children: settingsWriteNotice(state.accountResult, t) || t("accountOpFailed")
|
|
5626
|
-
}) : null,
|
|
5627
|
-
state.credentialRefreshFailed || state.accountResult?.refreshFailed || state.saveResult?.refreshFailed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5628
|
-
className: "cc-rowError",
|
|
5629
|
-
role: "status",
|
|
5630
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("writeRefreshFailed") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5631
|
-
type: "button",
|
|
5632
|
-
className: "cc-btn cc-btnSm",
|
|
5633
|
-
onClick: actions.refreshCredentials,
|
|
5634
|
-
children: t("writeRefreshRetry")
|
|
5635
|
-
})]
|
|
5636
|
-
}) : null,
|
|
5637
|
-
!adding && snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
5638
|
-
className: "cc-rowError",
|
|
5639
|
-
role: "status",
|
|
5640
|
-
children: t(snapshot.error)
|
|
5641
|
-
}) : null,
|
|
5642
|
-
state.pendingCredentialCleanup.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5643
|
-
className: "cc-rowError",
|
|
5644
|
-
role: "status",
|
|
5645
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("accountCleanupPending") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5646
|
-
type: "button",
|
|
5647
|
-
className: "cc-btn cc-btnSm",
|
|
5648
|
-
disabled: disabled || state.accountBusy,
|
|
5649
|
-
onClick: () => {
|
|
5650
|
-
for (const ref of state.pendingCredentialCleanup) actions.cleanup(ref);
|
|
5651
|
-
},
|
|
5652
|
-
children: t("accountCleanupRetry")
|
|
5653
|
-
})]
|
|
5654
|
-
}) : null,
|
|
5655
|
-
snapshot.pending.filter((record) => record.id !== snapshot.active?.id).map((record) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5656
|
-
className: "cc-rowError",
|
|
5657
|
-
role: "status",
|
|
5658
6510
|
children: [
|
|
5659
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
6511
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6512
|
+
name: "swap",
|
|
6513
|
+
className: "cc-icon cc-btnIcon"
|
|
6514
|
+
}),
|
|
6515
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: pinnedRow !== void 0 ? t("accountModePinned", { name: pinnedRow.label }) : t("accountModeAuto") }),
|
|
6516
|
+
pinnedRow !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
5665
6517
|
variant: "ghost",
|
|
5666
6518
|
size: "sm",
|
|
6519
|
+
disabled: disabled || state.accountBusy,
|
|
6520
|
+
onClick: () => void actions.setActive(""),
|
|
6521
|
+
children: t("accountActionUnpin")
|
|
6522
|
+
}) : null
|
|
6523
|
+
]
|
|
6524
|
+
}) : null,
|
|
6525
|
+
(() => {
|
|
6526
|
+
const writeNotice = settingsWriteNotice(state.accountResult, t);
|
|
6527
|
+
const notices = [];
|
|
6528
|
+
if (usage.status === "error") notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6529
|
+
tone: "error",
|
|
6530
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [t("usageError"), usage.error !== void 0 && usage.error !== "" ? ` — ${usage.error}` : ""] })
|
|
6531
|
+
}, "usage"));
|
|
6532
|
+
if (writeNotice || state.accountFailed !== void 0) notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6533
|
+
tone: "error",
|
|
6534
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: writeNotice || t("accountOpFailed") })
|
|
6535
|
+
}, "op"));
|
|
6536
|
+
if (state.credentialRefreshFailed || state.accountResult?.refreshFailed || state.saveResult?.refreshFailed) notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6537
|
+
tone: "warn",
|
|
6538
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6539
|
+
variant: "outline",
|
|
6540
|
+
size: "sm",
|
|
6541
|
+
onClick: actions.refreshCredentials,
|
|
6542
|
+
children: t("writeRefreshRetry")
|
|
6543
|
+
}),
|
|
6544
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("writeRefreshFailed") })
|
|
6545
|
+
}, "refresh"));
|
|
6546
|
+
if (!adding && snapshot.error) notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6547
|
+
tone: "error",
|
|
6548
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(snapshot.error) })
|
|
6549
|
+
}, "enroll"));
|
|
6550
|
+
if (state.pendingCredentialCleanup.length > 0) notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6551
|
+
tone: "warn",
|
|
6552
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6553
|
+
variant: "outline",
|
|
6554
|
+
size: "sm",
|
|
6555
|
+
disabled: disabled || state.accountBusy,
|
|
6556
|
+
onClick: () => {
|
|
6557
|
+
for (const ref of state.pendingCredentialCleanup) actions.cleanup(ref);
|
|
6558
|
+
},
|
|
6559
|
+
children: t("accountCleanupRetry")
|
|
6560
|
+
}),
|
|
6561
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("accountCleanupPending") })
|
|
6562
|
+
}, "cleanup"));
|
|
6563
|
+
for (const record of snapshot.pending.filter((candidate) => candidate.id !== snapshot.active?.id)) notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6564
|
+
tone: "warn",
|
|
6565
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [record.phase === "naming" && record.suggestedName ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6566
|
+
variant: "outline",
|
|
6567
|
+
size: "sm",
|
|
5667
6568
|
disabled,
|
|
5668
6569
|
onClick: () => void enrollment.recover(record, record.suggestedName),
|
|
5669
6570
|
children: t("accountNameSaveRetry")
|
|
5670
|
-
}) : null,
|
|
5671
|
-
|
|
5672
|
-
variant: "ghost",
|
|
6571
|
+
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6572
|
+
variant: "outline",
|
|
5673
6573
|
size: "sm",
|
|
5674
6574
|
disabled,
|
|
5675
6575
|
onClick: () => void enrollment.recover(record),
|
|
5676
6576
|
children: record.phase === "naming" ? t("accountNameAcceptExisting") : t("accountEnrollmentCleanupRetry")
|
|
5677
|
-
})
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
6577
|
+
})] }),
|
|
6578
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
6579
|
+
record.ref,
|
|
6580
|
+
t("accountRefSeparator"),
|
|
6581
|
+
t(record.messageKey)
|
|
6582
|
+
] })
|
|
6583
|
+
}, record.id));
|
|
6584
|
+
if (snapshot.active?.phase === "cleanup-needed") notices.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6585
|
+
tone: "warn",
|
|
6586
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6587
|
+
variant: "outline",
|
|
6588
|
+
size: "sm",
|
|
6589
|
+
disabled,
|
|
6590
|
+
onClick: () => void enrollment.recover(snapshot.active),
|
|
6591
|
+
children: t("accountEnrollmentCleanupRetry")
|
|
6592
|
+
}),
|
|
6593
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t(snapshot.active.messageKey) })
|
|
6594
|
+
}, "active-cleanup"));
|
|
6595
|
+
return notices.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6596
|
+
className: "cc-notices",
|
|
6597
|
+
children: notices
|
|
6598
|
+
}) : null;
|
|
6599
|
+
})(),
|
|
5691
6600
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5692
6601
|
className: "cc-accountList",
|
|
5693
6602
|
children: rows.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountItem, {
|
|
@@ -5709,19 +6618,44 @@ window.__ModuleLoader__.load({
|
|
|
5709
6618
|
enrollment,
|
|
5710
6619
|
snapshot,
|
|
5711
6620
|
onClose: closeAdd
|
|
5712
|
-
}) :
|
|
5713
|
-
|
|
5714
|
-
className: "cc-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
6621
|
+
}) : null,
|
|
6622
|
+
!adding || openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6623
|
+
className: "cc-accountActions",
|
|
6624
|
+
children: [
|
|
6625
|
+
!adding ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6626
|
+
variant: "outline",
|
|
6627
|
+
size: "md",
|
|
6628
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6629
|
+
name: "plus",
|
|
6630
|
+
className: "cc-icon cc-btnIcon"
|
|
6631
|
+
}),
|
|
6632
|
+
disabled,
|
|
6633
|
+
onClick: () => {
|
|
6634
|
+
enrollment.reset();
|
|
6635
|
+
setAdding(true);
|
|
6636
|
+
},
|
|
6637
|
+
children: t("accountAdd")
|
|
6638
|
+
}) : null,
|
|
6639
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-spacer" }),
|
|
6640
|
+
openAnalytics ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PageButton, {
|
|
6641
|
+
variant: "ghost",
|
|
6642
|
+
size: "md",
|
|
6643
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6644
|
+
name: "chart",
|
|
6645
|
+
className: "cc-icon cc-btnIcon"
|
|
6646
|
+
}),
|
|
6647
|
+
className: "cc-analyticsEntry",
|
|
6648
|
+
onClick: openAnalytics,
|
|
6649
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6650
|
+
className: "cc-analyticsEntryText",
|
|
6651
|
+
children: t("openAnalytics")
|
|
6652
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, {
|
|
6653
|
+
name: "arrowRight",
|
|
6654
|
+
className: "cc-icon cc-btnIcon"
|
|
6655
|
+
})]
|
|
6656
|
+
}) : null
|
|
6657
|
+
]
|
|
6658
|
+
}) : null
|
|
5725
6659
|
]
|
|
5726
6660
|
});
|
|
5727
6661
|
}
|
|
@@ -5766,6 +6700,51 @@ window.__ModuleLoader__.load({
|
|
|
5766
6700
|
return available;
|
|
5767
6701
|
}
|
|
5768
6702
|
/**
|
|
6703
|
+
* The service status: paint the cached snapshot immediately, then run one
|
|
6704
|
+
* throttled check per page open (the TTL and every failure path live in
|
|
6705
|
+
* ./service-status.ts, which never rejects). The Host probe runs alongside it
|
|
6706
|
+
* and is the row's real-time half — the published record only moves on a status
|
|
6707
|
+
* change or the daily summary, so it can legitimately be hours old.
|
|
6708
|
+
*/
|
|
6709
|
+
function useServiceStatus(probeService) {
|
|
6710
|
+
const [snapshot, setSnapshot] = (0, react.useState)(() => readCachedServiceStatus(localStorageServiceStatusStore()));
|
|
6711
|
+
const [probe, setProbe] = (0, react.useState)({ kind: "checking" });
|
|
6712
|
+
(0, react.useEffect)(() => {
|
|
6713
|
+
let cancelled = false;
|
|
6714
|
+
checkServiceStatus({ store: localStorageServiceStatusStore() }).then((next) => {
|
|
6715
|
+
if (!cancelled) setSnapshot(next);
|
|
6716
|
+
}, () => {});
|
|
6717
|
+
probeService().then((result) => {
|
|
6718
|
+
if (cancelled) return;
|
|
6719
|
+
setProbe(result.ok ? {
|
|
6720
|
+
kind: "result",
|
|
6721
|
+
result: result.value
|
|
6722
|
+
} : { kind: "unavailable" });
|
|
6723
|
+
}, () => {
|
|
6724
|
+
if (!cancelled) setProbe({ kind: "unavailable" });
|
|
6725
|
+
});
|
|
6726
|
+
return () => {
|
|
6727
|
+
cancelled = true;
|
|
6728
|
+
};
|
|
6729
|
+
}, []);
|
|
6730
|
+
return {
|
|
6731
|
+
snapshot,
|
|
6732
|
+
probe
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6735
|
+
/**
|
|
6736
|
+
* The page's fold state, read once from this browser's storage and written
|
|
6737
|
+
* back on every change (./group-fold.ts holds the defaults and fallbacks).
|
|
6738
|
+
*/
|
|
6739
|
+
function useGroupFold() {
|
|
6740
|
+
const [store] = (0, react.useState)(localStorageFoldStore);
|
|
6741
|
+
const [fold, setFoldState] = (0, react.useState)(() => store.read());
|
|
6742
|
+
return [fold, (0, react.useCallback)((next) => {
|
|
6743
|
+
setFoldState(next);
|
|
6744
|
+
store.write(next);
|
|
6745
|
+
}, [store])];
|
|
6746
|
+
}
|
|
6747
|
+
/**
|
|
5769
6748
|
* What the save bar says. It exists only while there is something to act on
|
|
5770
6749
|
* or to confirm: pending edits, a save in flight, a failure, or the brief
|
|
5771
6750
|
* confirmation after a save landed. Account operations never reach it, they
|
|
@@ -5842,7 +6821,7 @@ window.__ModuleLoader__.load({
|
|
|
5842
6821
|
* animate out, and keeps showing its last message while it does (the state
|
|
5843
6822
|
* that hid it has no message of its own).
|
|
5844
6823
|
*/
|
|
5845
|
-
function SaveBar({ view, state, t, onDiscard, onSave }) {
|
|
6824
|
+
function SaveBar({ view, state, t, onDiscard, onSave, onLocate }) {
|
|
5846
6825
|
const last = (0, react.useRef)(view);
|
|
5847
6826
|
if (view.visible) last.current = view;
|
|
5848
6827
|
const shown = view.visible ? view : last.current;
|
|
@@ -5864,19 +6843,29 @@ window.__ModuleLoader__.load({
|
|
|
5864
6843
|
}),
|
|
5865
6844
|
shown.actions ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5866
6845
|
className: "cc-saveBarActions",
|
|
5867
|
-
children: [
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
6846
|
+
children: [
|
|
6847
|
+
state.invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6848
|
+
variant: "ghost",
|
|
6849
|
+
size: "lg",
|
|
6850
|
+
disabled: !view.visible,
|
|
6851
|
+
onClick: onLocate,
|
|
6852
|
+
children: t("saveLocate")
|
|
6853
|
+
}) : null,
|
|
6854
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6855
|
+
variant: "ghost",
|
|
6856
|
+
size: "lg",
|
|
6857
|
+
disabled: !view.visible || !state.dirty && !state.failed || state.saving,
|
|
6858
|
+
onClick: onDiscard,
|
|
6859
|
+
children: t("discard")
|
|
6860
|
+
}),
|
|
6861
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageButton, {
|
|
6862
|
+
variant: "primary",
|
|
6863
|
+
size: "lg",
|
|
6864
|
+
disabled: !view.visible || !state.dirty || state.invalid || state.saving,
|
|
6865
|
+
onClick: onSave,
|
|
6866
|
+
children: t(state.saving ? "saving" : "save")
|
|
6867
|
+
})
|
|
6868
|
+
]
|
|
5880
6869
|
}) : null
|
|
5881
6870
|
]
|
|
5882
6871
|
})
|
|
@@ -5923,7 +6912,30 @@ window.__ModuleLoader__.load({
|
|
|
5923
6912
|
onEdit: props.edit,
|
|
5924
6913
|
onReset: props.resetField
|
|
5925
6914
|
};
|
|
6915
|
+
const status = useServiceStatus(props.probeService);
|
|
6916
|
+
const [fold, setFold] = useGroupFold();
|
|
6917
|
+
const foldProps = (group) => ({
|
|
6918
|
+
expanded: fold[group],
|
|
6919
|
+
onToggle: () => setFold({
|
|
6920
|
+
...fold,
|
|
6921
|
+
[group]: !fold[group]
|
|
6922
|
+
})
|
|
6923
|
+
});
|
|
6924
|
+
const sectionRef = (0, react.useRef)(null);
|
|
6925
|
+
const [locateTick, setLocateTick] = (0, react.useState)(0);
|
|
6926
|
+
(0, react.useEffect)(() => {
|
|
6927
|
+
if (locateTick === 0) return;
|
|
6928
|
+
const target = sectionRef.current?.querySelector("[aria-invalid=\"true\"]");
|
|
6929
|
+
if (target === null || target === void 0) return;
|
|
6930
|
+
target.scrollIntoView({ block: "center" });
|
|
6931
|
+
target.focus({ preventScroll: true });
|
|
6932
|
+
}, [locateTick]);
|
|
6933
|
+
const locate = () => {
|
|
6934
|
+
setFold(expandGroups(fold, invalidGroups(state)));
|
|
6935
|
+
setLocateTick((tick) => tick + 1);
|
|
6936
|
+
};
|
|
5926
6937
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6938
|
+
ref: sectionRef,
|
|
5927
6939
|
className: bar.visible ? "cc-section cc-sectionWithBar" : "cc-section",
|
|
5928
6940
|
"aria-label": t("title"),
|
|
5929
6941
|
children: [
|
|
@@ -5935,10 +6947,9 @@ window.__ModuleLoader__.load({
|
|
|
5935
6947
|
className: "cc-intro",
|
|
5936
6948
|
children: t("intro")
|
|
5937
6949
|
}),
|
|
5938
|
-
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
children: t("readOnly")
|
|
6950
|
+
!state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Notice, {
|
|
6951
|
+
icon: "lock",
|
|
6952
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("readOnly") })
|
|
5942
6953
|
}) : null,
|
|
5943
6954
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountsCard, {
|
|
5944
6955
|
t,
|
|
@@ -5949,17 +6960,30 @@ window.__ModuleLoader__.load({
|
|
|
5949
6960
|
actions,
|
|
5950
6961
|
onRefresh: props.refreshUsage,
|
|
5951
6962
|
openAnalytics: props.openAnalytics,
|
|
5952
|
-
createEnrollment: props.createEnrollment
|
|
6963
|
+
createEnrollment: props.createEnrollment,
|
|
6964
|
+
...foldProps("accounts")
|
|
5953
6965
|
}),
|
|
5954
6966
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelsCard, {
|
|
5955
6967
|
...form,
|
|
6968
|
+
...foldProps("models"),
|
|
5956
6969
|
onSelect: props.editVisibleModels,
|
|
5957
6970
|
onClear: props.clearVisibleModels,
|
|
5958
6971
|
onOverrides: props.editContextWindowOverrides
|
|
5959
6972
|
}),
|
|
5960
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrivacyCard, {
|
|
5961
|
-
|
|
5962
|
-
|
|
6973
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrivacyCard, {
|
|
6974
|
+
...form,
|
|
6975
|
+
...foldProps("privacy")
|
|
6976
|
+
}),
|
|
6977
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntegrationsCard, {
|
|
6978
|
+
...form,
|
|
6979
|
+
...foldProps("integrations"),
|
|
6980
|
+
status: status.snapshot,
|
|
6981
|
+
probe: status.probe
|
|
6982
|
+
}),
|
|
6983
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AdvancedSection, {
|
|
6984
|
+
...form,
|
|
6985
|
+
...foldProps("advanced")
|
|
6986
|
+
}),
|
|
5963
6987
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
5964
6988
|
className: "cc-version",
|
|
5965
6989
|
children: [
|
|
@@ -5985,7 +7009,8 @@ window.__ModuleLoader__.load({
|
|
|
5985
7009
|
state,
|
|
5986
7010
|
t,
|
|
5987
7011
|
onDiscard: props.discard,
|
|
5988
|
-
onSave: props.save
|
|
7012
|
+
onSave: props.save,
|
|
7013
|
+
onLocate: locate
|
|
5989
7014
|
})
|
|
5990
7015
|
]
|
|
5991
7016
|
});
|
|
@@ -9202,53 +10227,105 @@ window.__ModuleLoader__.load({
|
|
|
9202
10227
|
/**
|
|
9203
10228
|
* The settings-page stylesheet.
|
|
9204
10229
|
*
|
|
9205
|
-
*
|
|
9206
|
-
*
|
|
9207
|
-
*
|
|
9208
|
-
*
|
|
9209
|
-
*
|
|
9210
|
-
*
|
|
9211
|
-
*
|
|
9212
|
-
*
|
|
9213
|
-
*
|
|
9214
|
-
*
|
|
9215
|
-
*
|
|
10230
|
+
* Every size is the design canvas's (the cc-kit.css of the "CommandCode 设置页
|
|
10231
|
+
* 重设计" artboards, 2026-10-21), with its colour tokens mapped onto the
|
|
10232
|
+
* harness theme aliases so dark mode keeps working: a row is 12px of vertical
|
|
10233
|
+
* padding with no line between rows, title 14/22, description 12/18, a 24px
|
|
10234
|
+
* gap to the control; a group is 16px of padding under a 1px border-l2 rule,
|
|
10235
|
+
* its heading 36px high; the page title is 18/26 and group titles 14/22, both
|
|
10236
|
+
* 600. The page renders with grayscale antialiasing and descriptive text in
|
|
10237
|
+
* label-secondary.
|
|
10238
|
+
*
|
|
10239
|
+
* Shapes follow one rule — clickable things are pills, fillable things are
|
|
10240
|
+
* 8px. Buttons are drawn here (PageButton → cc-btn: md 32px, sm 28px, lg 36px
|
|
10241
|
+
* for the save bar), not taken from the harness primitive. Inputs and the
|
|
10242
|
+
* model selector are 32px with a 1px border-l3 stroke on the raised surface; a
|
|
10243
|
+
* number field draws its unit inside the box (cc-unitBox). Account cards and
|
|
10244
|
+
* the per-model override table are 1px border-l2 cards with 12px corners;
|
|
10245
|
+
* panels and notices are 12px-radius fills; badges are 20px pills. Errors use
|
|
10246
|
+
* state-error-primary; tinted surfaces fall back to a color-mix of the state
|
|
10247
|
+
* colour where the theme has no tertiary token. The Models-page provider card
|
|
10248
|
+
* shares cc-hint / cc-badgeMuted / cc-input and keeps their colours.
|
|
9216
10249
|
*/
|
|
9217
10250
|
const PAGE_CSS = `
|
|
9218
|
-
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex}
|
|
9219
|
-
.cc-title{margin:0;color:var(--dsw-alias-label-primary);font-size:
|
|
9220
|
-
.cc-intro{margin:4px 0 0;color:var(--dsw-alias-label-
|
|
9221
|
-
.cc-readOnly{margin:8px 0 0;color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-tertiary));font-size:12px;line-height:18px}
|
|
10251
|
+
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
|
|
10252
|
+
.cc-title{margin:0;color:var(--dsw-alias-label-primary);font-size:18px;font-weight:600;line-height:26px}
|
|
10253
|
+
.cc-intro{margin:4px 0 0;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:22px}
|
|
9222
10254
|
.cc-spacer{flex:1}
|
|
9223
|
-
.cc-group{flex-direction:column;display:flex;
|
|
9224
|
-
.cc-groupDivided{
|
|
9225
|
-
.cc-
|
|
9226
|
-
.cc-
|
|
9227
|
-
.cc-
|
|
9228
|
-
.cc-
|
|
9229
|
-
.cc-
|
|
10255
|
+
.cc-group{flex-direction:column;display:flex;padding:16px 0}
|
|
10256
|
+
.cc-group:not(.cc-groupDivided){padding-top:24px}
|
|
10257
|
+
.cc-groupDivided{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
10258
|
+
.cc-groupHead{align-items:center;gap:8px;display:flex;min-height:36px}
|
|
10259
|
+
.cc-groupTitle{margin:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:600;line-height:22px}
|
|
10260
|
+
.cc-groupDesc{margin:2px 0 0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
10261
|
+
.cc-rows>.cc-groupDesc{margin:0}
|
|
10262
|
+
.cc-groupHeading{flex:1;min-width:0;margin:0;font:inherit;display:flex}
|
|
10263
|
+
/* The whole heading row is the fold toggle: chevron, title, summary badges. */
|
|
10264
|
+
.cc-disclosure{box-sizing:border-box;flex-wrap:wrap;flex:1;align-items:center;gap:6px 8px;min-width:0;min-height:36px;padding:0;border:0;background:0 0;color:inherit;font:inherit;text-align:left;cursor:pointer;border-radius:8px;display:flex}
|
|
10265
|
+
.cc-foldChevron{color:var(--dsw-alias-label-tertiary);transition:transform .15s ease}
|
|
10266
|
+
.cc-foldChevronClosed{transform:rotate(-90deg)}
|
|
10267
|
+
.cc-groupBody{flex-direction:column;display:flex;padding-top:4px}
|
|
10268
|
+
.cc-groupBody[hidden]{display:none}
|
|
9230
10269
|
.cc-disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
9231
10270
|
.cc-rows{flex-direction:column;display:flex}
|
|
9232
|
-
.cc-row{align-items:center;gap:8px;display:flex;padding:12px 0}
|
|
10271
|
+
.cc-row{flex-wrap:wrap;align-items:center;gap:8px 24px;display:flex;padding:12px 0}
|
|
9233
10272
|
.cc-rowFlush{padding:0}
|
|
9234
|
-
.cc-rowText{flex-direction:column;flex:1;gap:
|
|
10273
|
+
.cc-rowText{flex-direction:column;flex:1 1 300px;gap:2px;min-width:0;display:flex}
|
|
9235
10274
|
.cc-rowTitleLine{align-items:center;gap:8px;display:flex;min-width:0}
|
|
9236
10275
|
.cc-rowTitle{min-width:0;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}
|
|
9237
|
-
.cc-rowDesc{color:var(--dsw-alias-label-
|
|
10276
|
+
.cc-rowDesc{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
9238
10277
|
.cc-rowDesc p{margin:0}
|
|
9239
10278
|
.cc-rowDesc p+p{margin-top:4px}
|
|
9240
10279
|
.cc-rowError{margin:0;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
9241
|
-
.cc-rowControl{flex:none;align-items:center;
|
|
10280
|
+
.cc-rowControl{flex:none;align-items:center;gap:8px;display:inline-flex;margin-left:auto}
|
|
9242
10281
|
.cc-rowInput{width:200px}
|
|
9243
10282
|
.cc-rowInputWide{width:280px}
|
|
9244
|
-
|
|
9245
|
-
.
|
|
9246
|
-
|
|
9247
|
-
.cc-
|
|
10283
|
+
/* The row-level field, drawn to the design canvas: 32px, 8px corners, a 1px
|
|
10284
|
+
* border-l3 stroke on the raised surface. A number field draws its unit inside
|
|
10285
|
+
* the same box (cc-unitBox), right of the value. */
|
|
10286
|
+
.cc-fieldInput{box-sizing:border-box;flex:none;height:32px;min-width:0;padding:0 10px;border:1px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-1);font:inherit;color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}
|
|
10287
|
+
.cc-fieldInput::placeholder{color:var(--dsw-alias-label-dimmed)}
|
|
10288
|
+
.cc-fieldInput:hover:not(:disabled){border-color:var(--dsw-alias-label-tertiary)}
|
|
10289
|
+
.cc-fieldInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
10290
|
+
.cc-fieldInput:disabled{opacity:.5;cursor:default}
|
|
10291
|
+
.cc-fieldInputInvalid,.cc-fieldInputInvalid:hover{border-color:var(--dsw-alias-state-error-primary)}
|
|
10292
|
+
.cc-unitBox{box-sizing:border-box;flex:none;align-items:center;display:inline-flex;width:160px;height:32px;border:1px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-1);overflow:hidden}
|
|
10293
|
+
.cc-unitBox:hover{border-color:var(--dsw-alias-label-tertiary)}
|
|
10294
|
+
.cc-unitBox:focus-within{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
10295
|
+
.cc-unitBoxInvalid,.cc-unitBoxInvalid:hover{border-color:var(--dsw-alias-state-error-primary)}
|
|
10296
|
+
.cc-unitBox:has(>.cc-fieldInput:disabled){opacity:.5}
|
|
10297
|
+
.cc-unitBox>.cc-fieldInput{flex:1;width:auto;height:30px;border:0;border-radius:0;background:0 0;outline:none;text-align:right;font-variant-numeric:tabular-nums}
|
|
10298
|
+
.cc-unit{flex:none;padding:0 10px 0 2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;white-space:nowrap}
|
|
10299
|
+
/* Holds the reset button's column on rows that have nothing to reset, so the
|
|
10300
|
+
* staged controls of one group line up on a single right edge. */
|
|
10301
|
+
.cc-resetSlot{flex:none;width:28px;height:28px}
|
|
10302
|
+
.cc-icon{flex:none;width:16px;height:16px}
|
|
10303
|
+
/* The page's buttons (PageButton), drawn to the design canvas: one capsule
|
|
10304
|
+
* shape, md 32px / 14px text / 14px icon, sm 28px / 12px text, lg 36px for
|
|
10305
|
+
* the save bar; primary is the brand fill, secondary the quiet grey fill,
|
|
10306
|
+
* ghost label-secondary text, danger the error fill. */
|
|
10307
|
+
.cc-btn{box-sizing:border-box;flex:none;align-items:center;justify-content:center;gap:6px;display:inline-flex;height:32px;padding:0 14px;border:0;border-radius:999px;corner-shape:round;font:inherit;font-size:14px;line-height:22px;white-space:nowrap;cursor:pointer;text-decoration:none}
|
|
10308
|
+
.cc-btnSm{height:28px;padding:0 10px;gap:4px;font-size:12px;line-height:18px}
|
|
10309
|
+
.cc-btnLg{height:36px;padding:0 16px}
|
|
10310
|
+
.cc-btn .cc-btnIcon{width:14px;height:14px}
|
|
10311
|
+
.cc-btnPrimary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}
|
|
10312
|
+
.cc-btnPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary)))}
|
|
10313
|
+
.cc-btnSecondary{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}
|
|
10314
|
+
.cc-btnSecondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
10315
|
+
.cc-btnGhost{background:0 0;color:var(--dsw-alias-label-secondary)}
|
|
10316
|
+
.cc-btnGhost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
10317
|
+
.cc-btnDanger{background:var(--dsw-alias-state-error-primary);color:#fff}
|
|
10318
|
+
.cc-btnDanger:hover:not(:disabled){background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 88%,#000)}
|
|
10319
|
+
.cc-btn:disabled{cursor:default;opacity:.4}
|
|
10320
|
+
.cc-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
10321
|
+
.cc-groupSummary{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400;line-height:18px;white-space:nowrap}
|
|
9248
10322
|
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
9249
|
-
.cc-badge,.cc-badgeMuted{flex:none;align-items:center;display:inline-flex;white-space:nowrap;border-radius:999px;corner-shape:round;padding:
|
|
10323
|
+
.cc-badge,.cc-badgeMuted{box-sizing:border-box;flex:none;align-items:center;gap:4px;display:inline-flex;height:20px;white-space:nowrap;border-radius:999px;corner-shape:round;padding:0 8px;font-size:12px;font-weight:500;line-height:18px}
|
|
9250
10324
|
.cc-badge{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary)}
|
|
9251
10325
|
.cc-badgeMuted{border:.5px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}
|
|
10326
|
+
.cc-badgeOutline{background:0 0;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l3);color:var(--dsw-alias-label-tertiary)}
|
|
10327
|
+
.cc-badgeOk{background:var(--dsw-alias-state-success-tertiary,color-mix(in srgb,var(--dsw-alias-state-success-primary,#16a34a) 10%,transparent));color:var(--dsw-alias-state-success-primary,#15803d)}
|
|
10328
|
+
.cc-badgeError{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
|
|
9252
10329
|
.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))}
|
|
9253
10330
|
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
9254
10331
|
.cc-field+.cc-field{border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
@@ -9263,13 +10340,13 @@ window.__ModuleLoader__.load({
|
|
|
9263
10340
|
.cc-input:disabled{opacity:.6;cursor:default}
|
|
9264
10341
|
.cc-inputInvalid{border-color:var(--dsw-alias-state-error-primary)}
|
|
9265
10342
|
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}
|
|
9266
|
-
.cc-modelSelectAnchor{flex-direction:column;align-items:stretch;gap:6px;display:inline-flex;
|
|
9267
|
-
.cc-selector{box-sizing:border-box;align-items:center;gap:
|
|
9268
|
-
.cc-selector:hover:not(:disabled){
|
|
10343
|
+
.cc-modelSelectAnchor{flex-direction:column;align-items:stretch;gap:6px;display:inline-flex;width:200px}
|
|
10344
|
+
.cc-selector{box-sizing:border-box;justify-content:space-between;align-items:center;gap:8px;display:inline-flex;height:32px;padding:0 10px;border:1px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px;text-align:left;cursor:pointer}
|
|
10345
|
+
.cc-selector:hover:not(:disabled){border-color:var(--dsw-alias-label-tertiary)}
|
|
9269
10346
|
.cc-selector:disabled{cursor:default;opacity:.4}
|
|
9270
|
-
.cc-selector:focus-visible{outline:
|
|
10347
|
+
.cc-selector:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
9271
10348
|
.cc-selectorText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
9272
|
-
.cc-
|
|
10349
|
+
.cc-selectorChevron{color:var(--dsw-alias-label-tertiary)}
|
|
9273
10350
|
/* The search box sits inside the Menu anchor, so typing in it never trips
|
|
9274
10351
|
* the Menu's outside-click close. */
|
|
9275
10352
|
.cc-modelSearch{width:100%}
|
|
@@ -9300,79 +10377,74 @@ window.__ModuleLoader__.load({
|
|
|
9300
10377
|
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
9301
10378
|
.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}
|
|
9302
10379
|
.cc-toggle:checked::after{transform:translateX(16px)}
|
|
10380
|
+
.cc-toggle:not(:checked)::after{background:var(--dsw-alias-switch-thumb,var(--dsw-alias-label-primary-foreground))}
|
|
9303
10381
|
.cc-toggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
9304
10382
|
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
9305
|
-
.cc-
|
|
9306
|
-
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
9307
|
-
.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}
|
|
10383
|
+
.cc-accountMode{align-items:center;gap:8px;display:flex;margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
9308
10384
|
.cc-accountList{flex-direction:column;gap:8px;display:flex}
|
|
9309
|
-
.cc-accountList+.cc-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
.cc-
|
|
9313
|
-
.cc-
|
|
10385
|
+
.cc-accountList+.cc-panel{margin-top:8px}
|
|
10386
|
+
/* One row under the list: Add account (outline) leads, the analytics exit
|
|
10387
|
+
* (ghost) trails; the exit's long label clamps instead of wrapping the row. */
|
|
10388
|
+
.cc-accountActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex;margin-top:12px}
|
|
10389
|
+
.cc-analyticsEntry{max-width:100%;min-width:0}
|
|
10390
|
+
.cc-analyticsEntryText{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
10391
|
+
.cc-chevronOpen{transform:rotate(180deg)}
|
|
10392
|
+
.cc-accountItem{flex-direction:column;display:flex;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
|
|
10393
|
+
.cc-accountItem>.cc-notice,.cc-accountItem>.cc-panel{margin:0 16px 14px}
|
|
10394
|
+
.cc-accountItemActive{border-color:var(--dsw-alias-border-l3)}
|
|
10395
|
+
.cc-accountHead{align-items:center;gap:4px;display:flex;padding:8px 8px 8px 0}
|
|
10396
|
+
.cc-accountToggle{flex-wrap:wrap;align-items:center;gap:6px 8px;display:flex;flex:1;min-width:0;min-height:44px;padding:0 0 0 16px;background:0 0;border:0;border-radius:12px;color:inherit;cursor:pointer;font:inherit;text-align:left}
|
|
9314
10397
|
.cc-accountToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:4px}
|
|
9315
10398
|
.cc-accountName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}
|
|
9316
|
-
.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:
|
|
9317
|
-
.cc-iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
10399
|
+
.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:8px;color:var(--dsw-alias-label-tertiary);cursor:pointer}
|
|
10400
|
+
.cc-iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
10401
|
+
.cc-iconButton:disabled{cursor:default;opacity:.4}
|
|
9318
10402
|
.cc-iconButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
|
|
9319
|
-
/* Per-model context-length
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9323
|
-
|
|
9324
|
-
.cc-contextItem{
|
|
9325
|
-
.cc-contextHead{align-items:center;gap:8px;display:
|
|
9326
|
-
.cc-
|
|
9327
|
-
|
|
9328
|
-
.cc-
|
|
9329
|
-
.cc-
|
|
9330
|
-
/* appearance:none swaps the platform arrow for the cc-contextCaret, shaped
|
|
9331
|
-
like cc-selectorCaret so every dropdown in the plugin opens with the same
|
|
9332
|
-
hand-drawn chevron. */
|
|
9333
|
-
.cc-contextModel{box-sizing:border-box;appearance:none;-webkit-appearance:none;width:100%;padding-inline-end:26px;text-overflow:ellipsis;cursor:pointer}
|
|
9334
|
-
.cc-contextCaret{position:absolute;inset-inline-end:12px;top:50%;width:6px;height:6px;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);transform:translateY(-50%) rotate(45deg);pointer-events:none}
|
|
10403
|
+
/* Per-model context-length overrides (issue #86) as the design's small table:
|
|
10404
|
+
* a card holding a head row over a model / value / remove grid, a line
|
|
10405
|
+
* between rows; a row's error wraps onto its own line across the grid. */
|
|
10406
|
+
.cc-contextTable{flex-direction:column;display:flex;margin:0 0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
|
|
10407
|
+
.cc-contextItem{grid-template-columns:minmax(0,1fr) 144px 28px;align-items:center;gap:8px;display:grid;padding:8px 8px 8px 12px}
|
|
10408
|
+
.cc-contextItem+.cc-contextItem{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
10409
|
+
.cc-contextHead{grid-template-columns:minmax(0,1fr) 144px 28px;align-items:center;gap:8px;display:grid;height:32px;padding:0 8px 0 12px;border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
10410
|
+
.cc-contextSelect{position:relative;display:block;min-width:0}
|
|
10411
|
+
/* appearance:none swaps the platform arrow for the page's own chevron icon. */
|
|
10412
|
+
.cc-contextModel{box-sizing:border-box;appearance:none;-webkit-appearance:none;width:100%;padding-inline-end:30px;text-overflow:ellipsis;cursor:pointer}
|
|
10413
|
+
.cc-contextCaret{position:absolute;inset-inline-end:10px;top:50%;color:var(--dsw-alias-label-tertiary);transform:translateY(-50%);pointer-events:none}
|
|
9335
10414
|
.cc-contextSelect:has(.cc-contextModel:disabled) .cc-contextCaret{opacity:.6}
|
|
9336
|
-
.cc-
|
|
9337
|
-
.cc-contextError{
|
|
9338
|
-
/* Three dots from one element: the dot plus two box-shadow copies. */
|
|
9339
|
-
.cc-kebab{width:3px;height:3px;border-radius:50%;corner-shape:round;background:currentColor;box-shadow:0 -5px 0 currentColor,0 5px 0 currentColor}
|
|
10415
|
+
.cc-contextItem>.cc-unitBox{width:100%}
|
|
10416
|
+
.cc-contextError{grid-column:1/-1}
|
|
9340
10417
|
.cc-tabDot{flex-shrink:0;width:8px;height:8px;border-radius:50%;corner-shape:round}
|
|
9341
10418
|
.cc-tabDotOk{background:var(--dsw-alias-state-success-primary)}
|
|
9342
10419
|
.cc-tabDotBlank{background:0 0;border:0}
|
|
9343
10420
|
.cc-tabDotWarn{background:var(--dsw-alias-state-warn-primary,#d97706)}
|
|
9344
10421
|
.cc-tabDotError{background:var(--dsw-alias-state-error-primary)}
|
|
9345
|
-
.cc-accountMeters{flex-wrap:wrap;gap:6px
|
|
10422
|
+
.cc-accountMeters{flex-wrap:wrap;gap:6px 24px;display:flex;padding:0 16px 14px 32px}
|
|
9346
10423
|
.cc-miniMeter{align-items:center;gap:8px;display:inline-flex;font-size:12px;line-height:18px}
|
|
9347
|
-
.cc-miniMeterLabel{color:var(--dsw-alias-label-
|
|
10424
|
+
.cc-miniMeterLabel{color:var(--dsw-alias-label-secondary)}
|
|
9348
10425
|
.cc-miniMeterTrack{overflow:hidden;background:var(--dsw-alias-bg-module-platform);border-radius:999px;width:64px;height:4px}
|
|
9349
10426
|
.cc-miniMeterFill{display:block;background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%}
|
|
9350
10427
|
.cc-miniMeterValue{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
|
|
9351
|
-
.cc-
|
|
9352
|
-
.cc-
|
|
9353
|
-
.cc-loginStatus>p{margin:0;font-size:12px;line-height:18px}
|
|
9354
|
-
.cc-accountDetails{container-type:inline-size;border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;display:flex;padding-top:12px}
|
|
9355
|
-
.cc-inlineForm,.cc-confirmBar{flex-direction:column;gap:8px;display:flex}
|
|
10428
|
+
.cc-accountDetails{container-type:inline-size;border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:16px;display:flex;padding:16px}
|
|
10429
|
+
.cc-inlineForm{flex-direction:column;gap:8px;display:flex}
|
|
9356
10430
|
.cc-inlineActions{align-items:center;gap:8px;display:flex}
|
|
9357
|
-
.cc-
|
|
9358
|
-
.cc-
|
|
9359
|
-
.cc-
|
|
9360
|
-
.cc-
|
|
9361
|
-
|
|
9362
|
-
.
|
|
9363
|
-
.cc-
|
|
9364
|
-
.cc-
|
|
9365
|
-
.cc-
|
|
9366
|
-
.cc-
|
|
9367
|
-
.cc-
|
|
9368
|
-
.cc-
|
|
9369
|
-
.cc-
|
|
9370
|
-
.cc-
|
|
9371
|
-
.cc-accountReport{flex-direction:column;gap:14px;display:flex}
|
|
10431
|
+
.cc-panel{flex-direction:column;gap:12px;display:flex;padding:16px;border-radius:12px;background:var(--dsw-alias-bg-module-platform)}
|
|
10432
|
+
.cc-panelInput{width:100%}
|
|
10433
|
+
.cc-keyField{align-items:center;gap:8px;display:flex}
|
|
10434
|
+
.cc-panelActions{flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
10435
|
+
/* The add-account method switch, drawn as the design's segmented control: a
|
|
10436
|
+
* pill track on the raised surface, the chosen segment in the brand fill. */
|
|
10437
|
+
.cc-seg{align-self:flex-start;display:inline-flex;padding:2px;border-radius:999px;corner-shape:round;background:var(--dsw-alias-bg-layer-1);box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2)}
|
|
10438
|
+
.cc-segItem{height:28px;padding:0 12px;border:0;border-radius:999px;corner-shape:round;background:0 0;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}
|
|
10439
|
+
.cc-segItem:hover:not(:disabled):not(.cc-segOn){color:var(--dsw-alias-label-primary)}
|
|
10440
|
+
.cc-segItem:disabled{cursor:default;opacity:.4}
|
|
10441
|
+
.cc-segItem:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}
|
|
10442
|
+
.cc-segOn{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}
|
|
10443
|
+
.cc-panelTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:600;line-height:22px}
|
|
10444
|
+
.cc-accountReport{flex-direction:column;gap:16px;display:flex}
|
|
9372
10445
|
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
9373
10446
|
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:14px;font-weight:500;line-height:22px}
|
|
9374
10447
|
.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
9375
|
-
.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:12px;font-weight:500;line-height:17px}
|
|
9376
10448
|
.cc-usagePlanStatus{flex:none;margin:0;white-space:nowrap;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
9377
10449
|
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}
|
|
9378
10450
|
/* Two fixed grids, not one auto-fit track: auto-fit wrapped the four activity
|
|
@@ -9380,12 +10452,18 @@ window.__ModuleLoader__.load({
|
|
|
9380
10452
|
* narrow details panel. */
|
|
9381
10453
|
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
9382
10454
|
.cc-usageStatsActivity{grid-template-columns:repeat(4,minmax(0,1fr))}
|
|
9383
|
-
.cc-usageStatsBalance{grid-template-columns:repeat(3,minmax(0,1fr))}
|
|
9384
10455
|
@container (max-width:460px){.cc-usageStatsActivity{grid-template-columns:repeat(2,minmax(0,1fr))}}
|
|
9385
|
-
.cc-
|
|
9386
|
-
.cc-
|
|
10456
|
+
.cc-balance{flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:4px 16px;display:flex}
|
|
10457
|
+
.cc-balanceMain{flex-direction:column;gap:2px;display:flex}
|
|
10458
|
+
.cc-balanceLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
10459
|
+
.cc-balanceValue{color:var(--dsw-alias-label-primary);font-size:20px;font-weight:600;line-height:28px;font-variant-numeric:tabular-nums}
|
|
10460
|
+
.cc-balanceSub{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;font-variant-numeric:tabular-nums}
|
|
10461
|
+
.cc-balanceEmpty .cc-balanceValue{color:var(--dsw-alias-state-error-primary)}
|
|
10462
|
+
.cc-balanceNote{flex-basis:100%;margin:0;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
10463
|
+
.cc-usageStat{min-width:0;flex-direction:column;gap:2px;display:flex;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform)}
|
|
10464
|
+
.cc-usageStatLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
9387
10465
|
.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:500;line-height:24px;font-variant-numeric:tabular-nums}
|
|
9388
|
-
.cc-usageStatSub{color:var(--dsw-alias-label-
|
|
10466
|
+
.cc-usageStatSub{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
9389
10467
|
.cc-usageWindows{flex-direction:column;gap:14px;display:flex}
|
|
9390
10468
|
.cc-usageWindow{flex-direction:column;gap:6px;display:flex}
|
|
9391
10469
|
.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}
|
|
@@ -9395,26 +10473,59 @@ window.__ModuleLoader__.load({
|
|
|
9395
10473
|
.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-module-platform);border-radius:999px;height:4px}
|
|
9396
10474
|
.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
9397
10475
|
.cc-usageBarFillWarn{background:var(--dsw-alias-state-error-primary)}
|
|
9398
|
-
.cc-usageWindowReset{color:var(--dsw-alias-label-
|
|
10476
|
+
.cc-usageWindowReset{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}
|
|
9399
10477
|
.cc-usageMeta{align-items:center;gap:8px;display:flex}
|
|
9400
10478
|
.cc-usageMetaSpacer{flex:1}
|
|
9401
|
-
.cc-usageUpdated{color:var(--dsw-alias-label-
|
|
10479
|
+
.cc-usageUpdated{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:18px}
|
|
9402
10480
|
.cc-usagePartial{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}
|
|
9403
|
-
.cc-
|
|
9404
|
-
.cc-
|
|
9405
|
-
|
|
9406
|
-
|
|
10481
|
+
.cc-notices{flex-direction:column;gap:8px;display:flex;margin-bottom:12px}
|
|
10482
|
+
.cc-section>.cc-notice{margin-top:12px}
|
|
10483
|
+
/* One block for every result, warning and blocked state: neutral (read-only,
|
|
10484
|
+
* in progress), warn (partly done, needs a retry) and error (failed). The
|
|
10485
|
+
* icon and title take the tone; the body stays label-secondary for contrast. */
|
|
10486
|
+
.cc-notice{box-sizing:border-box;align-items:flex-start;gap:10px;display:flex;padding:10px 12px;border-radius:12px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
10487
|
+
.cc-noticeIcon{flex:none;width:16px;height:16px;margin-top:1px;color:var(--dsw-alias-label-tertiary)}
|
|
10488
|
+
.cc-noticeBody{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex;word-break:break-word}
|
|
10489
|
+
.cc-noticeBody>p{margin:0}
|
|
10490
|
+
.cc-noticeTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}
|
|
10491
|
+
.cc-noticeActions{flex-wrap:wrap;align-items:center;gap:8px;display:flex;margin-top:8px}
|
|
10492
|
+
.cc-noticeDetail{color:var(--dsw-alias-label-tertiary)}
|
|
10493
|
+
.cc-noticeSuccess{background:var(--dsw-alias-state-success-tertiary,color-mix(in srgb,var(--dsw-alias-state-success-primary,#16a34a) 10%,transparent))}
|
|
10494
|
+
.cc-noticeSuccess>.cc-noticeIcon{color:var(--dsw-alias-state-success-primary,#16a34a)}
|
|
10495
|
+
.cc-noticeWarn{background:var(--dsw-alias-state-warn-tertiary,color-mix(in srgb,var(--dsw-alias-state-warn-primary,#d97706) 12%,transparent))}
|
|
10496
|
+
.cc-noticeWarn>.cc-noticeIcon,.cc-noticeWarn .cc-noticeTitle{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary,#b45309))}
|
|
10497
|
+
.cc-noticeError{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
|
|
10498
|
+
.cc-noticeError>.cc-noticeIcon,.cc-noticeError .cc-noticeTitle{color:var(--dsw-alias-state-error-primary)}
|
|
9407
10499
|
.cc-version{margin:32px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
9408
10500
|
.cc-versionLink{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
9409
10501
|
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
9410
10502
|
.cc-providerCard{flex-direction:column;display:flex}
|
|
9411
10503
|
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
9412
10504
|
.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}
|
|
9413
|
-
.cc-loginLink{color:var(--dsw-alias-link,var(--dsw-alias-brand-primary));text-decoration:none;font-size:12px;line-height:18px}
|
|
10505
|
+
.cc-loginLink{align-items:center;gap:4px;display:inline-flex;color:var(--dsw-alias-link,var(--dsw-alias-brand-primary));text-decoration:none;font-size:12px;line-height:18px}
|
|
10506
|
+
.cc-loginLink>.cc-iconInline{width:12px;height:12px}
|
|
9414
10507
|
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
10508
|
+
/* The status row's dot + verdict sit beside the row title; the primitive's own
|
|
10509
|
+
* state tokens colour the dot, so only the neutral label and the failure note
|
|
10510
|
+
* need styling here. */
|
|
10511
|
+
.cc-statusBadge{align-items:center;gap:6px;display:inline-flex;white-space:nowrap}
|
|
10512
|
+
.cc-statusLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
10513
|
+
.cc-statusNotice{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-label-tertiary));margin:0;font-size:12px;line-height:18px}
|
|
10514
|
+
/* One muted line in the status description: the local-connectivity probe and
|
|
10515
|
+
* the publication-lag note both use it, so the dot and the text stay aligned. */
|
|
10516
|
+
/* The service-status row's two sources: a key column (Official / This device)
|
|
10517
|
+
* beside a value line that wraps under itself, never under the key. */
|
|
10518
|
+
.cc-statusLines{grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:4px 12px;display:grid;margin:2px 0 0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}
|
|
10519
|
+
.cc-statusKey{color:var(--dsw-alias-label-tertiary);white-space:nowrap}
|
|
10520
|
+
.cc-statusValue{flex-wrap:wrap;align-items:center;gap:2px 8px;min-width:0;display:flex}
|
|
10521
|
+
.cc-statusVerdict{color:var(--dsw-alias-label-primary)}
|
|
10522
|
+
.cc-statusMeta{flex:1 1 200px;min-width:0}
|
|
10523
|
+
.cc-statusBad{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary,#b45309))}
|
|
10524
|
+
.cc-statusLink{color:var(--dsw-alias-link,var(--dsw-alias-brand-primary));text-decoration:none;font-size:12px;line-height:18px;white-space:nowrap}
|
|
10525
|
+
.cc-statusLink:hover{text-decoration:underline;text-underline-position:under}
|
|
9415
10526
|
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
9416
10527
|
.cc-loginError{color:var(--dsw-alias-state-error-primary)}
|
|
9417
|
-
/* The floating save bar: a centered
|
|
10528
|
+
/* The floating save bar: a centered bar pinned to the bottom of the
|
|
9418
10529
|
* settings scrollport. The dock is a zero-height sticky strip at the end of the
|
|
9419
10530
|
* page, so the bar overlays the scrolling content instead of taking a row of
|
|
9420
10531
|
* its own; while shown, the section reserves room at its end so the last line
|
|
@@ -9422,8 +10533,8 @@ window.__ModuleLoader__.load({
|
|
|
9422
10533
|
* the transition) takes its buttons out of the tab order. Its surface is an
|
|
9423
10534
|
* elevated layer (bg-layer-1 over the settings panel's layer-2) with the
|
|
9424
10535
|
* platform's prominent elevation and no stroke, and its corners are concentric
|
|
9425
|
-
*
|
|
9426
|
-
* button is even. */
|
|
10536
|
+
* with the capsule buttons inside it (36px pills inset by 4px in a 44px pill)
|
|
10537
|
+
* so the gap around each button is even. */
|
|
9427
10538
|
.cc-sectionWithBar{padding-bottom:80px}
|
|
9428
10539
|
.cc-saveBarDock{position:sticky;bottom:0;z-index:2;height:0;pointer-events:none}
|
|
9429
10540
|
.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}
|
|
@@ -9435,14 +10546,7 @@ window.__ModuleLoader__.load({
|
|
|
9435
10546
|
.cc-saveBarText{min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}
|
|
9436
10547
|
.cc-saveBar-error .cc-saveBarText{color:var(--dsw-alias-state-error-primary)}
|
|
9437
10548
|
.cc-saveBarActions{flex-shrink:0;align-items:center;gap:4px;display:flex;margin-left:8px}
|
|
9438
|
-
|
|
9439
|
-
.cc-saveBarButton:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}
|
|
9440
|
-
.cc-saveBarButton:disabled{cursor:default;opacity:.4}
|
|
9441
|
-
.cc-saveBarGhost{background:0 0;color:var(--dsw-alias-label-primary)}
|
|
9442
|
-
.cc-saveBarGhost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
9443
|
-
.cc-saveBarPrimary{background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}
|
|
9444
|
-
.cc-saveBarPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-button-primary-fill,var(--dsw-alias-brand-primary)))}
|
|
9445
|
-
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle::after,.cc-usageBarFill,.cc-saveBar,.cc-saveBarShown{transition:none}}
|
|
10549
|
+
@media (prefers-reduced-motion:reduce){.cc-foldChevron,.cc-toggle::after,.cc-usageBarFill,.cc-saveBar,.cc-saveBarShown{transition:none}}
|
|
9446
10550
|
`;
|
|
9447
10551
|
//#endregion
|
|
9448
10552
|
//#region src/client/panel-styles.ts
|
|
@@ -9892,6 +10996,7 @@ window.__ModuleLoader__.load({
|
|
|
9892
10996
|
...MODELS_REMOTE_CONTRIBUTION.descriptors,
|
|
9893
10997
|
...PRICES_REMOTE_CONTRIBUTION.descriptors,
|
|
9894
10998
|
...ANALYTICS_REMOTE_CONTRIBUTION.descriptors,
|
|
10999
|
+
...PROBE_REMOTE_CONTRIBUTION.descriptors,
|
|
9895
11000
|
...LOGIN_REMOTE_CONTRIBUTION.descriptors,
|
|
9896
11001
|
...ENROLLMENT_REMOTE_CONTRIBUTION.descriptors
|
|
9897
11002
|
]
|
|
@@ -10027,6 +11132,14 @@ window.__ModuleLoader__.load({
|
|
|
10027
11132
|
return ok;
|
|
10028
11133
|
};
|
|
10029
11134
|
const injected = () => ({
|
|
11135
|
+
probeService: () => {
|
|
11136
|
+
const namespace = usageNamespace;
|
|
11137
|
+
if (typeof namespace?.probe !== "function") return Promise.resolve({
|
|
11138
|
+
ok: false,
|
|
11139
|
+
error: { message: "宿主未提供连通性探测" }
|
|
11140
|
+
});
|
|
11141
|
+
return namespace.probe();
|
|
11142
|
+
},
|
|
10030
11143
|
createEnrollment: () => new AccountEnrollmentController(() => {
|
|
10031
11144
|
if (!usageNamespace?.enrollmentBegin) throw new Error("宿主不支持账号开通,请更新插件");
|
|
10032
11145
|
return usageNamespace;
|