@mars-sea/dsh-commandcode-provider 0.11.1 โ 0.11.3
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 +32 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/client.js +360 -319
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +80 -2
- package/lib/index.js +658 -29
- package/lib/index.js.map +1 -1
- package/package.json +42 -38
package/lib/client.js
CHANGED
|
@@ -36,150 +36,6 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
//#endregion
|
|
39
|
-
//#region src/command-locales.ts
|
|
40
|
-
const commandcodeCommand = {
|
|
41
|
-
zh: {
|
|
42
|
-
title: "๐ Command Code ็จ้{account}",
|
|
43
|
-
accountTitle: "๐ {label}{badges}",
|
|
44
|
-
accountSeparator: "โโโโโโโโโโโโโโโโโโโโ",
|
|
45
|
-
activeBadge: " โ
ๅฝๅไฝฟ็จ",
|
|
46
|
-
invalidCredentialBadge: " โ ๅฏ้ฅๆ ๆ",
|
|
47
|
-
cooldownBadge: " โณ ้้ขๅทๅดไธญ๏ผ้็ฝฎ {when}",
|
|
48
|
-
rateLimitBadge: " โณ ๅทฒ่พพ้้ข๏ผ็ญๅพ
็ชๅฃๆขๆต๏ผ",
|
|
49
|
-
unconfigured: " (ๆช้
็ฝฎ API ๅฏ้ฅ)",
|
|
50
|
-
blockedInvalidKey: "โ API ๅฏ้ฅๆ ๆๆๅทฒ่ฟๆ โ ๆๅก็ซฏๆ็ปไบๅ
จ้จ่ฏทๆฑ๏ผ401๏ผ๏ผ่ฏทๆฃๆฅ่ฏฅ่ดฆๆท็ๅฏ้ฅ้
็ฝฎ",
|
|
51
|
-
blockedServiceUnavailable: "โ ๏ธ Command Code ๆๅกๆๆถไธๅฏ็จ๏ผ5xx๏ผ๏ผ็จๅ้่ฏ",
|
|
52
|
-
blockedNetwork: "โ ๏ธ ๆ ๆณ่ฟๆฅ Command Code ๆๅก โ ่ฏทๆฃๆฅ็ฝ็ปๆ API ๅฐๅ",
|
|
53
|
-
planLine: " ๐ฆ ๅฅ้ค {name}{status}{period}",
|
|
54
|
-
planPeriodSuffix: " ยท ่ดฆๆๆชๆญข {date}",
|
|
55
|
-
usageHeader: "โโ ่ฏทๆฑ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ",
|
|
56
|
-
requestsLine: " ๐ฌ ่ฏทๆฑ {n} ๆฌก / ๅคฑ่ดฅ {f} ๆๅ็ {r}%",
|
|
57
|
-
costLine: " ๐ฐ ่ฑ่ดน {money} ({credits} credits)",
|
|
58
|
-
tokensLine: " ๐ค Token {in} ๅ
ฅ / {out} ๅบ",
|
|
59
|
-
creditsHeader: "โโ ไฟก็จ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ",
|
|
60
|
-
monthlyLine: " ๐ณ ๆ้ขๅบฆ {monthly} (ๅทฒ่ดญ {purchased} / ่ต ้ {free})",
|
|
61
|
-
barLine: " โ {bar} {pct}%",
|
|
62
|
-
windowsHeader: "โโ ็ชๅฃ็จ้ โโโโโโโโโโโโโโโโโโโโโโโโโโ",
|
|
63
|
-
fiveHourLine: " โฑ 5 ๅฐๆถ {used} / {cap}{warn}",
|
|
64
|
-
weeklyLine: " ๐
ๆฏๅจ {used} / {cap}{warn}",
|
|
65
|
-
windowBarLine: " โ {bar} ้็ฝฎ {when}",
|
|
66
|
-
exceededWarning: " โ ๏ธ ่ถ
้!",
|
|
67
|
-
resetSuffix: "้็ฝฎ {when}",
|
|
68
|
-
partialFailures: "โ ๏ธ ้จๅ็ซฏ็นๅคฑ่ดฅ: {list}",
|
|
69
|
-
noData: "๏ผๆ ๆฐๆฎ โ ่ฏทๆฃๆฅ API ๅฏ้ฅ๏ผ",
|
|
70
|
-
errorText: "่ทๅ Command Code ็จ้ๅคฑ่ดฅ๏ผ{message}",
|
|
71
|
-
imageGate: "ๅฝๅไผ่ฏๅทฒๅ
ๅซๅพ็๏ผ่ๆจกๅ {model} ไธๆฏๆๅพ็่พๅ
ฅ๏ผ่ฏท้ๆฉๆฏๆๅพ็็ๆจกๅ๏ผๆๅ
็งป้คไผ่ฏไธญ็ๅพ็ใ"
|
|
72
|
-
},
|
|
73
|
-
en: {
|
|
74
|
-
title: "๐ Command Code usage{account}",
|
|
75
|
-
accountTitle: "๐ {label}{badges}",
|
|
76
|
-
accountSeparator: "โโโโโโโโโโโโโโโโโโโโ",
|
|
77
|
-
activeBadge: " โ
active",
|
|
78
|
-
invalidCredentialBadge: " โ invalid key",
|
|
79
|
-
cooldownBadge: " โณ cooling down, resets {when}",
|
|
80
|
-
rateLimitBadge: " โณ rate-limited (waiting for window probe)",
|
|
81
|
-
unconfigured: " (no API key configured)",
|
|
82
|
-
blockedInvalidKey: "โ API key invalid or expired โ the server rejected every request (401); check the key configured for this account",
|
|
83
|
-
blockedServiceUnavailable: "โ ๏ธ Command Code service temporarily unavailable (5xx); try again later",
|
|
84
|
-
blockedNetwork: "โ ๏ธ could not reach the Command Code service โ check your network or the API base setting",
|
|
85
|
-
planLine: " ๐ฆ Plan {name}{status}{period}",
|
|
86
|
-
planPeriodSuffix: " ยท period ends {date}",
|
|
87
|
-
usageHeader: "โโ Requests โโโโโโโโโโโโโโโโโโโโโโโโโโ",
|
|
88
|
-
requestsLine: " ๐ฌ Requests {n} / failed {f} success rate {r}%",
|
|
89
|
-
costLine: " ๐ฐ Spend {money} ({credits} credits)",
|
|
90
|
-
tokensLine: " ๐ค Tokens {in} in / {out} out",
|
|
91
|
-
creditsHeader: "โโ Credits โโโโโโโโโโโโโโโโโโโโโโโโโโโ",
|
|
92
|
-
monthlyLine: " ๐ณ Monthly {monthly} (purchased {purchased} / free {free})",
|
|
93
|
-
barLine: " โ {bar} {pct}%",
|
|
94
|
-
windowsHeader: "โโ Window usage โโโโโโโโโโโโโโโโโโโโโโ",
|
|
95
|
-
fiveHourLine: " โฑ 5-hour {used} / {cap}{warn}",
|
|
96
|
-
weeklyLine: " ๐
Weekly {used} / {cap}{warn}",
|
|
97
|
-
windowBarLine: " โ {bar} resets {when}",
|
|
98
|
-
exceededWarning: " โ ๏ธ exceeded!",
|
|
99
|
-
resetSuffix: "resets {when}",
|
|
100
|
-
partialFailures: "โ ๏ธ some endpoints failed: {list}",
|
|
101
|
-
noData: "(no data โ check your API key)",
|
|
102
|
-
errorText: "Could not fetch Command Code usage: {message}",
|
|
103
|
-
imageGate: "This session already contains images, and model {model} does not accept image input; please select an image-capable model, or remove the images from the session first."
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
//#endregion
|
|
107
|
-
//#region src/client/sessions.ts
|
|
108
|
-
/**
|
|
109
|
-
* Friendly-error wrapper for the harness's image-session gate.
|
|
110
|
-
*
|
|
111
|
-
* The host rejects switching to a text-only model while the session already
|
|
112
|
-
* contains images with a `model-unavailable` error
|
|
113
|
-
* (`dsh-host-apiproxy`'s `session.selectModel` handler). That rejection is
|
|
114
|
-
* intentional and cannot be relaxed from the plugin side โ the adapter's
|
|
115
|
-
* `inputModalities` is exactly what makes the guard work. What we CAN do is
|
|
116
|
-
* make the error message friendlier: wrap the shared
|
|
117
|
-
* `connection.api.sessions.selectModel` face so a `model-unavailable`
|
|
118
|
-
* rejection shows a clear, actionable hint (with the requested model name)
|
|
119
|
-
* instead of the raw English harness message.
|
|
120
|
-
*
|
|
121
|
-
* The wrapper is deliberately narrow: only the `model-unavailable` code is
|
|
122
|
-
* rewritten, only when the message matches the image-session gate, and only
|
|
123
|
-
* the message text changes โ the error code and details pass through
|
|
124
|
-
* untouched so any caller that switches on `error.code` keeps working.
|
|
125
|
-
*
|
|
126
|
-
* The wire types are spelled structurally here (not imported from
|
|
127
|
-
* `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag an
|
|
128
|
-
* extra peer dependency into the package; the shapes are stable and the
|
|
129
|
-
* client build inlines them anyway.
|
|
130
|
-
*
|
|
131
|
-
* The wrapper takes a `getLocale` thunk because it is reached from a
|
|
132
|
-
* non-React path that has no `t` in scope; the supplied thunk reads the
|
|
133
|
-
* active locale at call time (typically `() => ctx.locale.getLocale().active`
|
|
134
|
-
* in the client entry), and the message template lives in the shared
|
|
135
|
-
* `commandcodeCommand` dictionary used by the Host-side `/commandcode`
|
|
136
|
-
* command โ the same bilingual surface serves both.
|
|
137
|
-
*
|
|
138
|
-
* This module is deliberately free of React and other client-platform
|
|
139
|
-
* imports so the node test runner can exercise it directly.
|
|
140
|
-
*/
|
|
141
|
-
/** Whether a selectModel rejection is the harness's image-session gate. */
|
|
142
|
-
function isImageSessionRejection(result) {
|
|
143
|
-
return !result.result.ok && result.result.error.code === "model-unavailable" && result.result.error.message.includes("does not accept image input");
|
|
144
|
-
}
|
|
145
|
-
/** Wrap the shared sessions API so selectModel failures read friendlier. */
|
|
146
|
-
function withFriendlyImageError(sessions, getLocale) {
|
|
147
|
-
const selectModel = sessions.selectModel.bind(sessions);
|
|
148
|
-
return {
|
|
149
|
-
...sessions,
|
|
150
|
-
selectModel: async (payload, signal) => {
|
|
151
|
-
const result = await selectModel(payload, signal);
|
|
152
|
-
if (!isImageSessionRejection(result)) return result;
|
|
153
|
-
const model = result.result.error.details?.model ?? payload.model;
|
|
154
|
-
const template = commandcodeCommand[getLocale()].imageGate ?? commandcodeCommand.en.imageGate;
|
|
155
|
-
return {
|
|
156
|
-
...result,
|
|
157
|
-
result: {
|
|
158
|
-
...result.result,
|
|
159
|
-
error: {
|
|
160
|
-
...result.result.error,
|
|
161
|
-
message: template.replace("{model}", model)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Install the friendly-error wrapper when a legacy sessions face is present.
|
|
170
|
-
*
|
|
171
|
-
* @returns whether the wrapper was installed. The rewrite is only UX polish;
|
|
172
|
-
* a 0.1.2 connection has no `api.sessions`, and its absence must never block
|
|
173
|
-
* the plugin from mounting its settings, credential, or usage surfaces.
|
|
174
|
-
*/
|
|
175
|
-
function installFriendlyImageError(connection, getLocale) {
|
|
176
|
-
const api = connection.api;
|
|
177
|
-
const sessions = api?.sessions;
|
|
178
|
-
if (api === void 0 || sessions === void 0 || typeof sessions.selectModel !== "function") return false;
|
|
179
|
-
api.sessions = withFriendlyImageError(sessions, getLocale);
|
|
180
|
-
return true;
|
|
181
|
-
}
|
|
182
|
-
//#endregion
|
|
183
39
|
//#region src/client/settings.ts
|
|
184
40
|
/**
|
|
185
41
|
* Browser controller for the "Command Code" settings page.
|
|
@@ -301,6 +157,10 @@ window.__ModuleLoader__.load({
|
|
|
301
157
|
min: 1,
|
|
302
158
|
max: MAX_TIMEOUT_MS
|
|
303
159
|
}),
|
|
160
|
+
numberField$1("transportMaxRetries", {
|
|
161
|
+
min: 0,
|
|
162
|
+
max: 50
|
|
163
|
+
}),
|
|
304
164
|
booleanField$1("filterModelsByPlan"),
|
|
305
165
|
booleanField$1("webSearch"),
|
|
306
166
|
booleanField$1("showSidebarQuota"),
|
|
@@ -454,6 +314,7 @@ window.__ModuleLoader__.load({
|
|
|
454
314
|
defaultWorkingDir: this.defaultWorkingDir,
|
|
455
315
|
requestTimeoutMs: this.field("requestTimeoutMs"),
|
|
456
316
|
streamIdleTimeoutMs: this.field("streamIdleTimeoutMs"),
|
|
317
|
+
transportMaxRetries: this.field("transportMaxRetries"),
|
|
457
318
|
filterModelsByPlan: this.field("filterModelsByPlan"),
|
|
458
319
|
webSearch: this.field("webSearch"),
|
|
459
320
|
showSidebarQuota: this.field("showSidebarQuota"),
|
|
@@ -2294,7 +2155,7 @@ window.__ModuleLoader__.load({
|
|
|
2294
2155
|
}
|
|
2295
2156
|
//#endregion
|
|
2296
2157
|
//#region package.json
|
|
2297
|
-
var version = "0.11.
|
|
2158
|
+
var version = "0.11.3";
|
|
2298
2159
|
var repository = {
|
|
2299
2160
|
"type": "git",
|
|
2300
2161
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -2493,6 +2354,7 @@ window.__ModuleLoader__.load({
|
|
|
2493
2354
|
"workingDir",
|
|
2494
2355
|
"requestTimeoutMs",
|
|
2495
2356
|
"streamIdleTimeoutMs",
|
|
2357
|
+
"transportMaxRetries",
|
|
2496
2358
|
"filterModelsByPlan",
|
|
2497
2359
|
"webSearch",
|
|
2498
2360
|
"showSidebarQuota"
|
|
@@ -2638,6 +2500,17 @@ window.__ModuleLoader__.load({
|
|
|
2638
2500
|
onReset: () => onReset("streamIdleTimeoutMs"),
|
|
2639
2501
|
t
|
|
2640
2502
|
}),
|
|
2503
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2504
|
+
id: "cc-transport-max-retries",
|
|
2505
|
+
label: t("transportMaxRetries"),
|
|
2506
|
+
hint: t("transportMaxRetriesHint"),
|
|
2507
|
+
state: state.transportMaxRetries,
|
|
2508
|
+
disabled,
|
|
2509
|
+
numeric: true,
|
|
2510
|
+
onEdit: (text) => onEdit("transportMaxRetries", text),
|
|
2511
|
+
onReset: () => onReset("transportMaxRetries"),
|
|
2512
|
+
t
|
|
2513
|
+
}),
|
|
2641
2514
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
2642
2515
|
id: "cc-filter-models-by-plan",
|
|
2643
2516
|
label: t("filterModelsByPlan"),
|
|
@@ -3981,12 +3854,68 @@ window.__ModuleLoader__.load({
|
|
|
3981
3854
|
}
|
|
3982
3855
|
//#endregion
|
|
3983
3856
|
//#region src/client/panel-copy.ts
|
|
3984
|
-
/** The panel
|
|
3985
|
-
const
|
|
3857
|
+
/** The locale namespace both panel slots bind their `t` seat to. */
|
|
3858
|
+
const PANEL_LOCALE_NS = "panel.commandcode";
|
|
3859
|
+
/** The panel's Simplified Chinese string table (the key-set source of truth). */
|
|
3860
|
+
const PANEL_COPY_ZH = {
|
|
3861
|
+
nav: "Command Code",
|
|
3862
|
+
subtitle: "ๅฅ้คใ้ขๅบฆไธ้
้ข็ชๅฃ",
|
|
3863
|
+
refresh: "ๅทๆฐ",
|
|
3864
|
+
refreshing: "ๅทๆฐไธญโฆ",
|
|
3865
|
+
close: "ๅ
ณ้ญ",
|
|
3866
|
+
closeHint: "่ฟๅไผ่ฏ",
|
|
3867
|
+
loading: "ๆญฃๅจ่ทๅ่ดฆๆท็จ้โฆ",
|
|
3868
|
+
noKey: "ๅฐๆช้
็ฝฎ API ๅฏ้ฅ",
|
|
3869
|
+
noKeyHint: "ๅจ ่ฎพ็ฝฎ โ Command Code ไธญ็ฒ่ดดๅฏ้ฅๆ็ปๅฝๅ๏ผ็นๅปๅทๆฐใ",
|
|
3870
|
+
plan: "ๅฅ้ค",
|
|
3871
|
+
credits: "้ขๅบฆ",
|
|
3872
|
+
limits: "้
้ข็ชๅฃ",
|
|
3873
|
+
usage: "็จ้",
|
|
3874
|
+
monthly: "ๆ้ขๅบฆ",
|
|
3875
|
+
monthlyLimit: "ๆ้ขๅบฆไธ้",
|
|
3876
|
+
monthlyUsed: "ๆฌๆๅทฒ็จ",
|
|
3877
|
+
remaining: "ๅฉไฝ",
|
|
3878
|
+
purchased: "ๅทฒ่ดญ",
|
|
3879
|
+
free: "่ต ้",
|
|
3880
|
+
fiveHour: "5 ๅฐๆถ็ชๅฃ",
|
|
3881
|
+
weekly: "ๆฏๅจ็ชๅฃ",
|
|
3882
|
+
fiveHourShort: "5 ๅฐๆถ",
|
|
3883
|
+
weeklyShort: "ๆฏๅจ",
|
|
3884
|
+
windowUnlimited: "ไธ้",
|
|
3885
|
+
exceeded: "ๅทฒ่ถ
้",
|
|
3886
|
+
exhausted: "ๅทฒ็จๅฐฝ",
|
|
3887
|
+
resets: "้็ฝฎไบ",
|
|
3888
|
+
requests: "่ฏทๆฑ",
|
|
3889
|
+
failed: "ๅคฑ่ดฅ",
|
|
3890
|
+
successRate: "ๆๅ็",
|
|
3891
|
+
spend: "่ฑ่ดน",
|
|
3892
|
+
tokens: "Token",
|
|
3893
|
+
tokensIn: "ๅ
ฅ",
|
|
3894
|
+
tokensOut: "ๅบ",
|
|
3895
|
+
periodEnds: "่ดฆๆๆชๆญข",
|
|
3896
|
+
updated: "ๆดๆฐไบ",
|
|
3897
|
+
partial: "้จๅ็ซฏ็นๆฐๆฎไธๅฏ็จ",
|
|
3898
|
+
active: "ๅฝๅไฝฟ็จ",
|
|
3899
|
+
coolingDown: "้้ขๅทๅดไธญ",
|
|
3900
|
+
invalidKey: "ๅฏ้ฅๆ ๆ",
|
|
3901
|
+
unconfigured: "ๆช้
็ฝฎ",
|
|
3902
|
+
unavailable: "ๆ ๆฐๆฎ",
|
|
3903
|
+
errorInvalidKey: "API ๅฏ้ฅๆ ๆๆๅทฒ่ฟๆ",
|
|
3904
|
+
errorInvalidKeyHint: "ๆๅก็ซฏๆ็ปไบๅ
จ้จ่ฏทๆฑ๏ผ401๏ผใ่ฏทๆฃๆฅ่ฏฅ่ดฆๆท็ๅฏ้ฅ๏ผๆๅฐ commandcode.ai ๆงๅถๅฐ้ๆฐ็ๆใ",
|
|
3905
|
+
errorServiceUnavailable: "Command Code ๆๅกๆๆถไธๅฏ็จ",
|
|
3906
|
+
errorServiceUnavailableHint: "ๆๅก็ซฏ่ฟๅ้่ฏฏ๏ผ5xx๏ผ๏ผ่ฏท็จๅ็นๅปๅทๆฐ้่ฏใ",
|
|
3907
|
+
errorNetwork: "ๆ ๆณ่ฟๆฅ Command Code ๆๅก",
|
|
3908
|
+
errorNetworkHint: "ๆๆ่ฏทๆฑ้ฝๆฒกๆๅฐ่พพๆๅก็ซฏใ่ฏทๆฃๆฅ็ฝ็ป่ฟๆฅๆ API ๅฐๅ่ฎพ็ฝฎใ",
|
|
3909
|
+
errorGeneric: "็จ้่ทๅๅคฑ่ดฅ"
|
|
3910
|
+
};
|
|
3911
|
+
/** The panel's English string table (must mirror {@link PANEL_COPY_ZH}). */
|
|
3912
|
+
const PANEL_COPY_EN = {
|
|
3986
3913
|
nav: "Command Code",
|
|
3987
3914
|
subtitle: "Plans, credits and quota windows",
|
|
3988
3915
|
refresh: "Refresh",
|
|
3989
3916
|
refreshing: "Refreshingโฆ",
|
|
3917
|
+
close: "Close",
|
|
3918
|
+
closeHint: "Back to the conversation",
|
|
3990
3919
|
loading: "Loading account usageโฆ",
|
|
3991
3920
|
noKey: "No API key configured",
|
|
3992
3921
|
noKeyHint: "Paste a key โ or sign in โ under Settings โ Command Code, then refresh.",
|
|
@@ -4031,9 +3960,15 @@ window.__ModuleLoader__.load({
|
|
|
4031
3960
|
errorNetworkHint: "No request reached the server. Check your network connection or the API base setting.",
|
|
4032
3961
|
errorGeneric: "Could not fetch account usage"
|
|
4033
3962
|
};
|
|
4034
|
-
/**
|
|
4035
|
-
|
|
4036
|
-
|
|
3963
|
+
/** Every panel key, in the English table's declaration order. */
|
|
3964
|
+
const PANEL_KEYS = Object.keys(PANEL_COPY_EN);
|
|
3965
|
+
/**
|
|
3966
|
+
* The English translator. Used as the fallback when no locale seat is
|
|
3967
|
+
* available (a defensive path: every supported engine supplies one) and as the
|
|
3968
|
+
* default in tests that only assert the projection's figures.
|
|
3969
|
+
*/
|
|
3970
|
+
function panelTextEN(key) {
|
|
3971
|
+
return PANEL_COPY_EN[key] ?? key;
|
|
4037
3972
|
}
|
|
4038
3973
|
//#endregion
|
|
4039
3974
|
//#region src/client/panel.ts
|
|
@@ -4131,7 +4066,7 @@ window.__ModuleLoader__.load({
|
|
|
4131
4066
|
};
|
|
4132
4067
|
}
|
|
4133
4068
|
/** Build one account's view. */
|
|
4134
|
-
function accountView(entry) {
|
|
4069
|
+
function accountView(entry, t) {
|
|
4135
4070
|
const { report } = entry;
|
|
4136
4071
|
const account = report.account;
|
|
4137
4072
|
const plan = report.plan;
|
|
@@ -4142,7 +4077,7 @@ window.__ModuleLoader__.load({
|
|
|
4142
4077
|
stats.push({
|
|
4143
4078
|
label: "requests",
|
|
4144
4079
|
value: String(usage.completedCount),
|
|
4145
|
-
sub: `${usage.failedCount} ${
|
|
4080
|
+
sub: `${usage.failedCount} ${t("failed")}`
|
|
4146
4081
|
});
|
|
4147
4082
|
stats.push({
|
|
4148
4083
|
label: "successRate",
|
|
@@ -4157,7 +4092,7 @@ window.__ModuleLoader__.load({
|
|
|
4157
4092
|
stats.push({
|
|
4158
4093
|
label: "tokens",
|
|
4159
4094
|
value: formatTokensCompact(usage.totalTokensIn + usage.totalTokensOut),
|
|
4160
|
-
sub: `${formatTokensCompact(usage.totalTokensIn)} ${
|
|
4095
|
+
sub: `${formatTokensCompact(usage.totalTokensIn)} ${t("tokensIn")} / ${formatTokensCompact(usage.totalTokensOut)} ${t("tokensOut")}`
|
|
4161
4096
|
});
|
|
4162
4097
|
}
|
|
4163
4098
|
const windows = [];
|
|
@@ -4208,15 +4143,14 @@ window.__ModuleLoader__.load({
|
|
|
4208
4143
|
};
|
|
4209
4144
|
}
|
|
4210
4145
|
/**
|
|
4211
|
-
* Every panel string, resolved once per projection
|
|
4212
|
-
* (rather than per-field lookups in the components)
|
|
4213
|
-
* the render sites in lockstep: a key cannot be read
|
|
4214
|
-
* {@link
|
|
4146
|
+
* Every panel string, resolved once per projection through the translator.
|
|
4147
|
+
* One object with all keys (rather than per-field lookups in the components)
|
|
4148
|
+
* keeps the copy table and the render sites in lockstep: a key cannot be read
|
|
4149
|
+
* from `text` unless {@link PANEL_KEYS} declares it.
|
|
4215
4150
|
*/
|
|
4216
|
-
function panelStrings() {
|
|
4217
|
-
const keys = Object.keys(PANEL_COPY);
|
|
4151
|
+
function panelStrings(t) {
|
|
4218
4152
|
const out = {};
|
|
4219
|
-
for (const key of
|
|
4153
|
+
for (const key of PANEL_KEYS) out[key] = t(key);
|
|
4220
4154
|
return out;
|
|
4221
4155
|
}
|
|
4222
4156
|
/**
|
|
@@ -4228,6 +4162,7 @@ window.__ModuleLoader__.load({
|
|
|
4228
4162
|
*/
|
|
4229
4163
|
function buildPanelView(input) {
|
|
4230
4164
|
const { usage } = input;
|
|
4165
|
+
const t = input.t ?? panelTextEN;
|
|
4231
4166
|
const hidden = new Set(input.removingIds ?? []);
|
|
4232
4167
|
const seen = /* @__PURE__ */ new Set();
|
|
4233
4168
|
const entries = (usage.report?.accounts ?? []).filter((entry) => {
|
|
@@ -4236,7 +4171,7 @@ window.__ModuleLoader__.load({
|
|
|
4236
4171
|
seen.add(entry.id);
|
|
4237
4172
|
return true;
|
|
4238
4173
|
});
|
|
4239
|
-
const accounts = entries.map(accountView);
|
|
4174
|
+
const accounts = entries.map((entry) => accountView(entry, t));
|
|
4240
4175
|
const selectedEntry = entries.find((entry) => entry.active) ?? entries[0];
|
|
4241
4176
|
const selectedView = accounts.find((view) => view.id === selectedEntry?.id);
|
|
4242
4177
|
const footerBars = [];
|
|
@@ -4255,18 +4190,18 @@ window.__ModuleLoader__.load({
|
|
|
4255
4190
|
const totalCost = selectedEntry?.report.usage?.totalCost;
|
|
4256
4191
|
const cost = totalCost === void 0 ? "" : money(totalCost);
|
|
4257
4192
|
let status = "";
|
|
4258
|
-
if (entries.length > 0 && !entries.some((entry) => entry.configured)) status =
|
|
4259
|
-
else if (selectedView?.mark !== void 0 && selectedView.mark !== "active") status =
|
|
4260
|
-
else if (selectedEntry === void 0) status =
|
|
4261
|
-
const planName = selectedView !== void 0 && selectedView.planName !== "" ? selectedView.planName :
|
|
4262
|
-
const titleParts = planName ===
|
|
4193
|
+
if (entries.length > 0 && !entries.some((entry) => entry.configured)) status = t("unconfigured");
|
|
4194
|
+
else if (selectedView?.mark !== void 0 && selectedView.mark !== "active") status = t(selectedView.mark);
|
|
4195
|
+
else if (selectedEntry === void 0) status = t("unavailable");
|
|
4196
|
+
const planName = selectedView !== void 0 && selectedView.planName !== "" ? selectedView.planName : t("nav");
|
|
4197
|
+
const titleParts = planName === t("nav") ? [planName] : [t("nav"), planName];
|
|
4263
4198
|
for (const bar of footerBars) {
|
|
4264
4199
|
const figures = bar.detail === "" ? "" : ` ${bar.detail}`;
|
|
4265
|
-
titleParts.push(`${
|
|
4200
|
+
titleParts.push(`${t(bar.label)}${figures} (${bar.percent})`);
|
|
4266
4201
|
}
|
|
4267
|
-
if (cost !== "") titleParts.push(`${
|
|
4202
|
+
if (cost !== "") titleParts.push(`${t("spend")} ${cost}`);
|
|
4268
4203
|
return {
|
|
4269
|
-
text: panelStrings(),
|
|
4204
|
+
text: panelStrings(t),
|
|
4270
4205
|
planName,
|
|
4271
4206
|
status,
|
|
4272
4207
|
footerBars,
|
|
@@ -4352,11 +4287,11 @@ window.__ModuleLoader__.load({
|
|
|
4352
4287
|
* the sidebar footer card and the dashboard it opens in the center column.
|
|
4353
4288
|
*
|
|
4354
4289
|
* Both render one {@link PanelView} projected by `./panel.ts` โ no fact is
|
|
4355
|
-
* derived here. Strings arrive
|
|
4356
|
-
*
|
|
4357
|
-
*
|
|
4358
|
-
*
|
|
4359
|
-
*
|
|
4290
|
+
* derived here. Strings arrive already localized in `view.text`: the slots
|
|
4291
|
+
* declare the `panel.commandcode` locale namespace, so the renderer hands this
|
|
4292
|
+
* component a `t` seat that is passed into `buildPanelView` โ the panel follows
|
|
4293
|
+
* the harness's active language (a language switch mints a new `t`, so the
|
|
4294
|
+
* surfaces re-render without an extra channel).
|
|
4360
4295
|
*
|
|
4361
4296
|
* The footer card is the panel's home: the sidebar shell renders it in the foot
|
|
4362
4297
|
* area directly above the Settings seat, so each quota window's own spend and
|
|
@@ -4378,7 +4313,8 @@ window.__ModuleLoader__.load({
|
|
|
4378
4313
|
return buildPanelView({
|
|
4379
4314
|
usage,
|
|
4380
4315
|
apiKeyConfigured: settings.anyAccountConfigured,
|
|
4381
|
-
removingIds: settings.accountsRemoving
|
|
4316
|
+
removingIds: settings.accountsRemoving,
|
|
4317
|
+
t: props.t ?? panelTextEN
|
|
4382
4318
|
});
|
|
4383
4319
|
}
|
|
4384
4320
|
/**
|
|
@@ -4704,6 +4640,18 @@ window.__ModuleLoader__.load({
|
|
|
4704
4640
|
disabled: view.loading,
|
|
4705
4641
|
onClick: () => props.refresh(),
|
|
4706
4642
|
children: view.loading ? text("refreshing") : text("refresh")
|
|
4643
|
+
}),
|
|
4644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
4645
|
+
variant: "ghost",
|
|
4646
|
+
size: "sm",
|
|
4647
|
+
className: "ccp-close",
|
|
4648
|
+
"aria-label": text("close"),
|
|
4649
|
+
title: text("closeHint"),
|
|
4650
|
+
onClick: () => props.close(),
|
|
4651
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4652
|
+
"aria-hidden": "true",
|
|
4653
|
+
children: "ร"
|
|
4654
|
+
})
|
|
4707
4655
|
})
|
|
4708
4656
|
]
|
|
4709
4657
|
}),
|
|
@@ -5651,6 +5599,165 @@ window.__ModuleLoader__.load({
|
|
|
5651
5599
|
"data-ccp-session-cost-anchor": ""
|
|
5652
5600
|
});
|
|
5653
5601
|
}
|
|
5602
|
+
//#endregion
|
|
5603
|
+
//#region src/client/page-styles.ts
|
|
5604
|
+
/**
|
|
5605
|
+
* Stylesheet for the Command Code settings page โ and the Models-page provider
|
|
5606
|
+
* card, which shares its `cc-` classes.
|
|
5607
|
+
*
|
|
5608
|
+
* Returned as a string rather than injected here so the modules stay free of
|
|
5609
|
+
* DOM side effects at import time: `./index.ts` installs it once, keyed by
|
|
5610
|
+
* `PAGE_CSS_ID`. It is a module of its own rather than a literal inside the
|
|
5611
|
+
* client entry so `tests/styles.test.ts` can audit every rule without importing
|
|
5612
|
+
* the React tree (which pulls `*.module.css` through the primitives package and
|
|
5613
|
+
* needs a loader registered first).
|
|
5614
|
+
*
|
|
5615
|
+
* Every colour comes from a harness theme alias with a neutral fallback, so the
|
|
5616
|
+
* page follows the active theme (light/dark and any brand pack) without
|
|
5617
|
+
* hardcoded values. Classes are `cc-` prefixed to stay clear of the panel's
|
|
5618
|
+
* `ccp-` set.
|
|
5619
|
+
*
|
|
5620
|
+
* @module dsh-commandcode-provider/client/page-styles
|
|
5621
|
+
*/
|
|
5622
|
+
/**
|
|
5623
|
+
* Stylesheet id (the `data-plugin-css` value that makes injection idempotent).
|
|
5624
|
+
*
|
|
5625
|
+
* The package prefix must match the one the panel stylesheet uses
|
|
5626
|
+
* (`PANEL_CSS_ID` in `./panel-styles.ts`) and this package's real name: an id is
|
|
5627
|
+
* the injection's identity, so a stale fork prefix would let a second copy of
|
|
5628
|
+
* the plugin inject the same rules twice and would misreport the owner in the
|
|
5629
|
+
* DOM. The two ids must also stay distinct from each other โ they key two
|
|
5630
|
+
* separate style tags, and a shared id would make the second injection a no-op
|
|
5631
|
+
* that silently drops one stylesheet.
|
|
5632
|
+
*/
|
|
5633
|
+
const PAGE_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css";
|
|
5634
|
+
/** The settings-page stylesheet. */
|
|
5635
|
+
const PAGE_CSS = `
|
|
5636
|
+
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}
|
|
5637
|
+
.cc-title{margin:0;font-size:18px;font-weight:600}
|
|
5638
|
+
.cc-intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}
|
|
5639
|
+
.cc-readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5640
|
+
.cc-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:4px 16px}
|
|
5641
|
+
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
5642
|
+
.cc-field+.cc-field{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
5643
|
+
.cc-fieldHead{align-items:center;gap:8px;display:flex}
|
|
5644
|
+
.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}
|
|
5645
|
+
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
5646
|
+
.cc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5647
|
+
.cc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}
|
|
5648
|
+
.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
5649
|
+
.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
5650
|
+
.cc-reset:disabled{cursor:default;opacity:.5}
|
|
5651
|
+
.cc-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}
|
|
5652
|
+
.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
5653
|
+
.cc-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
|
|
5654
|
+
/* The routing-rule model multi-select: a button trigger that opens an
|
|
5655
|
+
* anchored Menu of checkbox rows. The trigger mirrors .cc-input sizing so it
|
|
5656
|
+
* sits flush with the sibling account select. */
|
|
5657
|
+
.cc-ruleTrigger{align-items:center;gap:8px;display:flex;width:100%;text-align:left;cursor:pointer}
|
|
5658
|
+
.cc-ruleTrigger:disabled{cursor:default}
|
|
5659
|
+
.cc-ruleTriggerText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
5660
|
+
.cc-ruleCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg)}
|
|
5661
|
+
.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}
|
|
5662
|
+
.cc-checkRow:hover{cursor:pointer}
|
|
5663
|
+
.cc-check{appearance:none;flex-shrink:0;width:15px;height:15px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-bg-layer-1);position:relative}
|
|
5664
|
+
.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
5665
|
+
.cc-check:checked::after{content:'';position:absolute;top:2px;left:5px;width:3px;height:7px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
|
|
5666
|
+
.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
5667
|
+
/* The model multi-select search box: stacked under the trigger while the
|
|
5668
|
+
* dropdown is open, same input sizing so the pair reads as one control. The
|
|
5669
|
+
* box lives inside the Menu anchor (which renders inside the Menu's root
|
|
5670
|
+
* span), so focusing/typing it never trips the Menu's outside-click close. */
|
|
5671
|
+
.cc-modelSelectAnchor{flex-direction:column;gap:6px;display:flex;width:100%}
|
|
5672
|
+
.cc-modelSearch{width:100%}
|
|
5673
|
+
.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}
|
|
5674
|
+
/* Selects need their own treatment to sit flush with the text inputs:
|
|
5675
|
+
* the UA stylesheet renders <select> border-box (34px total vs the inputs'
|
|
5676
|
+
* 36px) and forces its own menulist text metrics, so drop the native
|
|
5677
|
+
* chrome entirely (appearance:none), restore content-box so the outer box
|
|
5678
|
+
* matches the inputs again, and draw the chevron ourselves. Longhand
|
|
5679
|
+
* background-* only โ the shorthand would reset .cc-input's background. */
|
|
5680
|
+
select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box-sizing:content-box;padding-right:32px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23888f98' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center}
|
|
5681
|
+
.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}
|
|
5682
|
+
.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
|
|
5683
|
+
/* The Advanced card: its header row is one full-width toggle button; the
|
|
5684
|
+
* chevron is two borders on a rotated square (no icon dependency). */
|
|
5685
|
+
.cc-advancedHead{align-items:center;gap:8px;display:flex;width:100%;padding:12px 0;background:0 0;border:none;cursor:pointer;font:inherit;text-align:left}
|
|
5686
|
+
.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}
|
|
5687
|
+
.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}
|
|
5688
|
+
.cc-advancedSpacer{flex:1}
|
|
5689
|
+
.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:8px;height:8px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg);transition:transform .15s ease}
|
|
5690
|
+
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
5691
|
+
.cc-advancedBody{flex-direction:column;display:flex}
|
|
5692
|
+
.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
5693
|
+
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5694
|
+
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
5695
|
+
.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}
|
|
5696
|
+
.cc-toggleRow:has(.cc-toggle:disabled){cursor:default}
|
|
5697
|
+
.cc-toggle{appearance:none;flex-shrink:0;background:var(--dsw-alias-border-l2);border-radius:999px;width:30px;height:18px;margin:0;cursor:pointer;position:relative;transition:background .15s ease}
|
|
5698
|
+
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
5699
|
+
.cc-toggle::after{content:'';background:#fff;border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px;transition:left .15s ease}
|
|
5700
|
+
.cc-toggle:checked::after{left:14px}
|
|
5701
|
+
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
5702
|
+
.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}
|
|
5703
|
+
.cc-usageCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:14px 16px;flex-direction:column;gap:12px;display:flex}
|
|
5704
|
+
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
5705
|
+
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
5706
|
+
.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5707
|
+
.cc-usagePlan{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}
|
|
5708
|
+
.cc-usagePlanStatus{white-space:nowrap;color:var(--dsw-alias-label-error);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5709
|
+
.cc-usageRefresh{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
5710
|
+
.cc-usageRefresh:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
5711
|
+
.cc-usageRefresh:disabled{cursor:default;opacity:.5}
|
|
5712
|
+
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5713
|
+
.cc-usageError{align-items:center;gap:8px;color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5;display:flex}
|
|
5714
|
+
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
5715
|
+
.cc-usageStat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex}
|
|
5716
|
+
.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
5717
|
+
.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
|
|
5718
|
+
.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
5719
|
+
.cc-usageWindows{flex-direction:column;gap:16px;display:flex}
|
|
5720
|
+
.cc-usageWindow{flex-direction:column;gap:6px;display:flex}
|
|
5721
|
+
.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}
|
|
5722
|
+
.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;font-weight:500;line-height:1.5}
|
|
5723
|
+
.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:1.5}
|
|
5724
|
+
.cc-usageExceeded{color:var(--dsw-alias-label-error);font-size:11px;font-weight:500;line-height:1.5}
|
|
5725
|
+
.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:6px}
|
|
5726
|
+
.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
5727
|
+
.cc-usageBarFillWarn{background:var(--dsw-alias-label-error)}
|
|
5728
|
+
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle,.cc-toggle::after,.cc-usageBarFill{transition:none}}.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
5729
|
+
.cc-usageMeta{align-items:center;gap:8px;display:flex}
|
|
5730
|
+
.cc-accountReport{flex-direction:column;gap:12px;display:flex}
|
|
5731
|
+
.cc-tabs{flex-wrap:wrap;gap:6px;display:flex}
|
|
5732
|
+
.cc-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}
|
|
5733
|
+
.cc-tab:hover:not(.cc-tabActive){color:var(--dsw-alias-label-primary)}
|
|
5734
|
+
.cc-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
5735
|
+
.cc-tabDotOk{background:var(--dsw-alias-brand-primary);border-radius:50%;width:6px;height:6px}
|
|
5736
|
+
.cc-tabDotWarn{background:#d97706;border-radius:50%;width:6px;height:6px}
|
|
5737
|
+
.cc-tabDotError{background:var(--dsw-alias-label-error);border-radius:50%;width:6px;height:6px}
|
|
5738
|
+
.cc-usageMetaSpacer{flex:1}
|
|
5739
|
+
.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
5740
|
+
.cc-usagePartial{color:var(--dsw-alias-label-error);margin:0;font-size:11px;line-height:1.5}
|
|
5741
|
+
.cc-usageBlocked{border:1px solid var(--dsw-alias-label-error);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}
|
|
5742
|
+
.cc-usageBlockedTitle{color:var(--dsw-alias-label-error);margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
5743
|
+
.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}
|
|
5744
|
+
.cc-version{margin:4px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
5745
|
+
/* The Models-page provider panel root: unstyled by design โ the row card the
|
|
5746
|
+
* Models page owns supplies the surface, the panel only stacks its controls. */
|
|
5747
|
+
.cc-providerCard{flex-direction:column;display:flex}
|
|
5748
|
+
/* The update hint rides the footer version line: warning-tinted (with a
|
|
5749
|
+
* muted fallback for themes without the alias), quiet until hovered. */
|
|
5750
|
+
.cc-versionLink{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
5751
|
+
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
5752
|
+
/* The login panel rides the connection card as one more field row; the
|
|
5753
|
+
* authorization link is the only branded element on it. */
|
|
5754
|
+
.cc-loginLink{color:var(--dsw-alias-brand-primary);text-decoration:none;font-size:12px;line-height:1.5}
|
|
5755
|
+
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
5756
|
+
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
5757
|
+
.cc-loginError{color:var(--dsw-alias-label-error)}
|
|
5758
|
+
.cc-saved{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;font-weight:500;line-height:1.5}
|
|
5759
|
+
.cc-badgeWarn{background:var(--dsw-alias-state-warning-secondary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary))}
|
|
5760
|
+
`;
|
|
5654
5761
|
//#endregion
|
|
5655
5762
|
//#region src/client/panel-styles.ts
|
|
5656
5763
|
/**
|
|
@@ -5659,8 +5766,16 @@ window.__ModuleLoader__.load({
|
|
|
5659
5766
|
*
|
|
5660
5767
|
* Returned as a string rather than injected here so the modules stay free of
|
|
5661
5768
|
* DOM side effects at import time โ the client entry installs it once, keyed
|
|
5662
|
-
* by the same `data-plugin-css` attribute the settings-page stylesheet
|
|
5663
|
-
* and removes it again when the plugin's fiber
|
|
5769
|
+
* by the same `data-plugin-css` attribute the settings-page stylesheet
|
|
5770
|
+
* (`./page-styles.ts`) uses, and removes it again when the plugin's fiber
|
|
5771
|
+
* unwinds.
|
|
5772
|
+
*
|
|
5773
|
+
* These rules are GLOBAL CSS: every selector in here can match markup this
|
|
5774
|
+
* plugin did not render. So each one is either qualified by a `ccp-` class of
|
|
5775
|
+
* our own, or anchored to the sidebar region it has to lay out โ and the one
|
|
5776
|
+
* foreign anchor carries its justification in place (see the footer card
|
|
5777
|
+
* block; issue #48). `tests/styles.test.ts` audits that containment for both
|
|
5778
|
+
* stylesheets and simulates it against the real foreign class stems.
|
|
5664
5779
|
*
|
|
5665
5780
|
* Every colour comes from a harness theme alias with a neutral fallback, so
|
|
5666
5781
|
* the panel follows the active theme (light/dark and any brand pack) without
|
|
@@ -5673,9 +5788,12 @@ window.__ModuleLoader__.load({
|
|
|
5673
5788
|
* Stylesheet id (the `data-plugin-css` value that makes injection idempotent).
|
|
5674
5789
|
*
|
|
5675
5790
|
* The package prefix must match the one the settings-page stylesheet uses
|
|
5676
|
-
* (`
|
|
5677
|
-
* injection's identity, so a stale fork prefix would let a second copy of
|
|
5678
|
-
* plugin inject the same rules twice and would misreport the owner in the
|
|
5791
|
+
* (`PAGE_CSS_ID` in `./page-styles.ts`) and this package's real name: an id is
|
|
5792
|
+
* the injection's identity, so a stale fork prefix would let a second copy of
|
|
5793
|
+
* the plugin inject the same rules twice and would misreport the owner in the
|
|
5794
|
+
* DOM. The two ids must also stay distinct from each other โ they key two
|
|
5795
|
+
* separate style tags, and a shared id would make the second injection a no-op
|
|
5796
|
+
* that silently drops one stylesheet.
|
|
5679
5797
|
*/
|
|
5680
5798
|
const PANEL_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodePanel.module.css";
|
|
5681
5799
|
/** The panel stylesheet. */
|
|
@@ -5689,11 +5807,28 @@ window.__ModuleLoader__.load({
|
|
|
5689
5807
|
|
|
5690
5808
|
The shell's container is a flex ROW whose occupants (this card and ui-cordis's
|
|
5691
5809
|
footer chip) each declare a full-width line and shrink-proof flex, so as a row
|
|
5692
|
-
it would overflow the column
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5810
|
+
it would overflow the column: this card's flex:0 0 auto cannot shrink, and the
|
|
5811
|
+
chip's width:100% basis would absorb the whole overflow and collapse to
|
|
5812
|
+
nothing. Both were written for a full-width line, which is exactly what a
|
|
5813
|
+
column gives them. Matched by the CSS-module class STEM โ never a hashed name
|
|
5814
|
+
โ so a dsh that renames it degrades to the shell's own row rather than
|
|
5815
|
+
breaking.
|
|
5816
|
+
|
|
5817
|
+
THE ANCHOR IS LOAD-BEARING, and it is the whole reason this selector is not
|
|
5818
|
+
just [class*="_footerActions"] (issue #48). "footerActions" is NOT a stem this
|
|
5819
|
+
shell owns alone: @deepseek-ai/dsh-client-ui-user-questions renders the
|
|
5820
|
+
ask-user-question dialog's button row as Mbwy4a_footerActions, so the
|
|
5821
|
+
unanchored rule forced THAT row into a column too and stacked the dialog's
|
|
5822
|
+
side-by-side buttons on every page. "footArea" is declared by
|
|
5823
|
+
dsh-client-ui-sidebar alone โ verified against every client bundle of the
|
|
5824
|
+
0.1.6-alpha.1 engine, and against our own cc-/ccp- class names, which collide
|
|
5825
|
+
with no engine class โ so anchoring under it keeps the sidebar layout fix and
|
|
5826
|
+
cannot reach another component's markup. The descendant combinator (rather
|
|
5827
|
+
than a child one) deliberately survives a wrapper element appearing between
|
|
5828
|
+
the two: a renamed or restructured shell should degrade to its own row, not
|
|
5829
|
+
lose the fix. tests/styles.test.ts pins both halves of this โ the dialog row
|
|
5830
|
+
is no longer matched, the sidebar row still is. */
|
|
5831
|
+
[class*="_footArea"] [class*="_footerActions"]{flex-direction:column}
|
|
5697
5832
|
.ccp-foot{box-sizing:border-box;flex:0 0 auto;width:100%;min-width:0;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:1px solid transparent;border-radius:10px;flex-direction:column;gap:6px;margin:0 0 4px;padding:8px;display:flex}
|
|
5698
5833
|
.ccp-foot:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}
|
|
5699
5834
|
.ccp-foot:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}
|
|
@@ -5738,6 +5873,11 @@ window.__ModuleLoader__.load({
|
|
|
5738
5873
|
.ccp-subtitle{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
5739
5874
|
.ccp-spacer{flex:1}
|
|
5740
5875
|
.ccp-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5;font-variant-numeric:tabular-nums}
|
|
5876
|
+
/* The dashboard's exit: an icon-sized glyph button. The primitive's own
|
|
5877
|
+
geometry is kept (size="sm"); only the glyph is enlarged and optically
|
|
5878
|
+
centred, so it reads as a dismiss control rather than a text button. */
|
|
5879
|
+
.ccp-close{min-width:28px;justify-content:center;padding-left:0;padding-right:0}
|
|
5880
|
+
.ccp-close span{font-size:16px;line-height:1}
|
|
5741
5881
|
.ccp-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5742
5882
|
|
|
5743
5883
|
/* Notices: the no-key guidance, a blocked report, and a stale-data error. */
|
|
@@ -5814,6 +5954,8 @@ window.__ModuleLoader__.load({
|
|
|
5814
5954
|
requestTimeoutMsHint: "็ญๅพ
ๅๅบ้ฆไธชๅญ่็่ถ
ๆถ๏ผ้ป่ฎค 60000ใ",
|
|
5815
5955
|
streamIdleTimeoutMs: "ๆต็ฉบ้ฒ่ถ
ๆถ๏ผๆฏซ็ง๏ผ",
|
|
5816
5956
|
streamIdleTimeoutMsHint: "็ๆๆตๅๆปๅคไน
่งไธบๆญ่ฟ๏ผ้ป่ฎค 300000๏ผ้ฟๆ่ๆจกๅๅฏ้้ปๆฐๅ้๏ผ้ป่ฎคๅผๅปๆๆพๅฎฝ๏ผใ",
|
|
5957
|
+
transportMaxRetries: "็ฝ็ปๅคฑ่ดฅ้่ฏๆฌกๆฐ",
|
|
5958
|
+
transportMaxRetriesHint: "่ฟๆฅๅคฑ่ดฅๆถ่ชๅจ้่ฏๅ ๆฌก๏ผ้ป่ฎค 5๏ผๅๆฌก็ญๅพ
0.5+1+2+4+8 ็ง๏ผๅ่ฎก็บฆ 15 ็ง๏ผใ่ถ
่ฟๅ็ดๆฅๆฅ้๏ผไธๅๆๆๆฐ้้ฟ้ฟๆถ้ด็ญๅพ
๏ผๅกซ 0 ่กจ็คบไธ้่ฏใ้ๆตใ5xx ็ญ็ฑๆๅก็ซฏ่ฆๆฑ้่ฏ็ๅคฑ่ดฅไธๅๆญค้กนๅฝฑๅใ",
|
|
5817
5959
|
advancedSettings: "้ซ็บง่ฎพ็ฝฎ",
|
|
5818
5960
|
advancedSettingsHint: "API ๅฐๅใๅทฅไฝ็ฎๅฝใ่ถ
ๆถใๆจกๅ่ฟๆปคใ่็ฝๆ็ดขไธไพง่พนๆ ้ขๅบฆๅก็็ญไธๅธธไฟฎๆน็้้กนใ",
|
|
5819
5961
|
advancedOverriddenOne: "ๅทฒ่ชๅฎไน 1 ้กน",
|
|
@@ -5948,6 +6090,8 @@ window.__ModuleLoader__.load({
|
|
|
5948
6090
|
requestTimeoutMsHint: "Time to wait for the first response byte; default 60000.",
|
|
5949
6091
|
streamIdleTimeoutMs: "Stream idle timeout (ms)",
|
|
5950
6092
|
streamIdleTimeoutMsHint: "How long a stalled stream is treated as dead; default 300000 (deliberately generous โ long-thinking models can stay silent for minutes).",
|
|
6093
|
+
transportMaxRetries: "Transport retries",
|
|
6094
|
+
transportMaxRetriesHint: "How many times a failed connection is retried automatically; default 5 (waits of 0.5+1+2+4+8s, ~15s in total). After that the failure is reported instead of waiting on the exponential backoff. 0 disables the retries. Rate limits and 5xx answers keep their own, longer retry window.",
|
|
5951
6095
|
advancedSettings: "Advanced",
|
|
5952
6096
|
advancedSettingsHint: "Rarely touched options: API base URL, working directory, timeouts, model filtering, web search, and the sidebar quota card.",
|
|
5953
6097
|
advancedOverriddenOne: "1 customized",
|
|
@@ -6067,141 +6211,13 @@ window.__ModuleLoader__.load({
|
|
|
6067
6211
|
};
|
|
6068
6212
|
//#endregion
|
|
6069
6213
|
//#region src/client/index.ts
|
|
6070
|
-
/** CSS for the settings page, injected once (harness bundle convention). */
|
|
6071
|
-
const PAGE_CSS = `
|
|
6072
|
-
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}
|
|
6073
|
-
.cc-title{margin:0;font-size:18px;font-weight:600}
|
|
6074
|
-
.cc-intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}
|
|
6075
|
-
.cc-readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6076
|
-
.cc-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:4px 16px}
|
|
6077
|
-
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
6078
|
-
.cc-field+.cc-field{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
6079
|
-
.cc-fieldHead{align-items:center;gap:8px;display:flex}
|
|
6080
|
-
.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}
|
|
6081
|
-
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
6082
|
-
.cc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6083
|
-
.cc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}
|
|
6084
|
-
.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
6085
|
-
.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
6086
|
-
.cc-reset:disabled{cursor:default;opacity:.5}
|
|
6087
|
-
.cc-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}
|
|
6088
|
-
.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
6089
|
-
.cc-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
|
|
6090
|
-
/* The routing-rule model multi-select: a button trigger that opens an
|
|
6091
|
-
* anchored Menu of checkbox rows. The trigger mirrors .cc-input sizing so it
|
|
6092
|
-
* sits flush with the sibling account select. */
|
|
6093
|
-
.cc-ruleTrigger{align-items:center;gap:8px;display:flex;width:100%;text-align:left;cursor:pointer}
|
|
6094
|
-
.cc-ruleTrigger:disabled{cursor:default}
|
|
6095
|
-
.cc-ruleTriggerText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6096
|
-
.cc-ruleCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg)}
|
|
6097
|
-
.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}
|
|
6098
|
-
.cc-checkRow:hover{cursor:pointer}
|
|
6099
|
-
.cc-check{appearance:none;flex-shrink:0;width:15px;height:15px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-bg-layer-1);position:relative}
|
|
6100
|
-
.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
6101
|
-
.cc-check:checked::after{content:'';position:absolute;top:2px;left:5px;width:3px;height:7px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
|
|
6102
|
-
.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6103
|
-
/* The model multi-select search box: stacked under the trigger while the
|
|
6104
|
-
* dropdown is open, same input sizing so the pair reads as one control. The
|
|
6105
|
-
* box lives inside the Menu anchor (which renders inside the Menu's root
|
|
6106
|
-
* span), so focusing/typing it never trips the Menu's outside-click close. */
|
|
6107
|
-
.cc-modelSelectAnchor{flex-direction:column;gap:6px;display:flex;width:100%}
|
|
6108
|
-
.cc-modelSearch{width:100%}
|
|
6109
|
-
.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}
|
|
6110
|
-
/* Selects need their own treatment to sit flush with the text inputs:
|
|
6111
|
-
* the UA stylesheet renders <select> border-box (34px total vs the inputs'
|
|
6112
|
-
* 36px) and forces its own menulist text metrics, so drop the native
|
|
6113
|
-
* chrome entirely (appearance:none), restore content-box so the outer box
|
|
6114
|
-
* matches the inputs again, and draw the chevron ourselves. Longhand
|
|
6115
|
-
* background-* only โ the shorthand would reset .cc-input's background. */
|
|
6116
|
-
select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box-sizing:content-box;padding-right:32px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23888f98' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center}
|
|
6117
|
-
.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}
|
|
6118
|
-
.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
|
|
6119
|
-
/* The Advanced card: its header row is one full-width toggle button; the
|
|
6120
|
-
* chevron is two borders on a rotated square (no icon dependency). */
|
|
6121
|
-
.cc-advancedHead{align-items:center;gap:8px;display:flex;width:100%;padding:12px 0;background:0 0;border:none;cursor:pointer;font:inherit;text-align:left}
|
|
6122
|
-
.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}
|
|
6123
|
-
.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}
|
|
6124
|
-
.cc-advancedSpacer{flex:1}
|
|
6125
|
-
.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:8px;height:8px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg);transition:transform .15s ease}
|
|
6126
|
-
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
6127
|
-
.cc-advancedBody{flex-direction:column;display:flex}
|
|
6128
|
-
.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
6129
|
-
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6130
|
-
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
6131
|
-
.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}
|
|
6132
|
-
.cc-toggleRow:has(.cc-toggle:disabled){cursor:default}
|
|
6133
|
-
.cc-toggle{appearance:none;flex-shrink:0;background:var(--dsw-alias-border-l2);border-radius:999px;width:30px;height:18px;margin:0;cursor:pointer;position:relative;transition:background .15s ease}
|
|
6134
|
-
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
6135
|
-
.cc-toggle::after{content:'';background:#fff;border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px;transition:left .15s ease}
|
|
6136
|
-
.cc-toggle:checked::after{left:14px}
|
|
6137
|
-
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
6138
|
-
.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}
|
|
6139
|
-
.cc-usageCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:14px 16px;flex-direction:column;gap:12px;display:flex}
|
|
6140
|
-
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
6141
|
-
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
6142
|
-
.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6143
|
-
.cc-usagePlan{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}
|
|
6144
|
-
.cc-usagePlanStatus{white-space:nowrap;color:var(--dsw-alias-label-error);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6145
|
-
.cc-usageRefresh{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
6146
|
-
.cc-usageRefresh:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
6147
|
-
.cc-usageRefresh:disabled{cursor:default;opacity:.5}
|
|
6148
|
-
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6149
|
-
.cc-usageError{align-items:center;gap:8px;color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5;display:flex}
|
|
6150
|
-
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
6151
|
-
.cc-usageStat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex}
|
|
6152
|
-
.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
6153
|
-
.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
|
|
6154
|
-
.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
6155
|
-
.cc-usageWindows{flex-direction:column;gap:16px;display:flex}
|
|
6156
|
-
.cc-usageWindow{flex-direction:column;gap:6px;display:flex}
|
|
6157
|
-
.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}
|
|
6158
|
-
.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;font-weight:500;line-height:1.5}
|
|
6159
|
-
.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:1.5}
|
|
6160
|
-
.cc-usageExceeded{color:var(--dsw-alias-label-error);font-size:11px;font-weight:500;line-height:1.5}
|
|
6161
|
-
.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:6px}
|
|
6162
|
-
.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
6163
|
-
.cc-usageBarFillWarn{background:var(--dsw-alias-label-error)}
|
|
6164
|
-
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle,.cc-toggle::after,.cc-usageBarFill{transition:none}}.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
6165
|
-
.cc-usageMeta{align-items:center;gap:8px;display:flex}
|
|
6166
|
-
.cc-accountReport{flex-direction:column;gap:12px;display:flex}
|
|
6167
|
-
.cc-tabs{flex-wrap:wrap;gap:6px;display:flex}
|
|
6168
|
-
.cc-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}
|
|
6169
|
-
.cc-tab:hover:not(.cc-tabActive){color:var(--dsw-alias-label-primary)}
|
|
6170
|
-
.cc-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
6171
|
-
.cc-tabDotOk{background:var(--dsw-alias-brand-primary);border-radius:50%;width:6px;height:6px}
|
|
6172
|
-
.cc-tabDotWarn{background:#d97706;border-radius:50%;width:6px;height:6px}
|
|
6173
|
-
.cc-tabDotError{background:var(--dsw-alias-label-error);border-radius:50%;width:6px;height:6px}
|
|
6174
|
-
.cc-usageMetaSpacer{flex:1}
|
|
6175
|
-
.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
6176
|
-
.cc-usagePartial{color:var(--dsw-alias-label-error);margin:0;font-size:11px;line-height:1.5}
|
|
6177
|
-
.cc-usageBlocked{border:1px solid var(--dsw-alias-label-error);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}
|
|
6178
|
-
.cc-usageBlockedTitle{color:var(--dsw-alias-label-error);margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
6179
|
-
.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}
|
|
6180
|
-
.cc-version{margin:4px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
6181
|
-
/* The Models-page provider panel root: unstyled by design โ the row card the
|
|
6182
|
-
* Models page owns supplies the surface, the panel only stacks its controls. */
|
|
6183
|
-
.cc-providerCard{flex-direction:column;display:flex}
|
|
6184
|
-
/* The update hint rides the footer version line: warning-tinted (with a
|
|
6185
|
-
* muted fallback for themes without the alias), quiet until hovered. */
|
|
6186
|
-
.cc-versionLink{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
6187
|
-
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
6188
|
-
/* The login panel rides the connection card as one more field row; the
|
|
6189
|
-
* authorization link is the only branded element on it. */
|
|
6190
|
-
.cc-loginLink{color:var(--dsw-alias-brand-primary);text-decoration:none;font-size:12px;line-height:1.5}
|
|
6191
|
-
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
6192
|
-
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
6193
|
-
.cc-loginError{color:var(--dsw-alias-label-error)}
|
|
6194
|
-
.cc-saved{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;font-weight:500;line-height:1.5}
|
|
6195
|
-
.cc-badgeWarn{background:var(--dsw-alias-state-warning-secondary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary))}
|
|
6196
|
-
`;
|
|
6197
6214
|
/** Inject the page stylesheet once (idempotent per tag). */
|
|
6198
6215
|
function injectPageCss() {
|
|
6199
6216
|
if (typeof document === "undefined") return;
|
|
6200
|
-
|
|
6201
|
-
if (document.querySelector(`style[data-plugin-css="${id}"]`) !== null) return;
|
|
6217
|
+
if (document.querySelector(`style[data-plugin-css="@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css"]`) !== null) return;
|
|
6202
6218
|
const tag = document.createElement("style");
|
|
6203
6219
|
tag.dataset.plugin = "@mars-sea/dsh-commandcode-provider";
|
|
6204
|
-
tag.dataset.pluginCss =
|
|
6220
|
+
tag.dataset.pluginCss = PAGE_CSS_ID;
|
|
6205
6221
|
tag.textContent = PAGE_CSS;
|
|
6206
6222
|
document.head.appendChild(tag);
|
|
6207
6223
|
}
|
|
@@ -6231,6 +6247,15 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6231
6247
|
*/
|
|
6232
6248
|
const PANEL_ID = "commandcode-panel";
|
|
6233
6249
|
/**
|
|
6250
|
+
* ui-conversation's reserved `main` key, used only as the exit fallback for a
|
|
6251
|
+
* layout whose `selectPanel` predates the `null` "show the Conversation"
|
|
6252
|
+
* selection (see `close` in {@link applyClientSurfaces}). Declared locally for
|
|
6253
|
+
* the same reason as {@link PANEL_ID}: ui-conversation is not a dependency of
|
|
6254
|
+
* this bundle, and the key is a published contract of the layout (its README
|
|
6255
|
+
* names `conversation` as reserved for the Conversation).
|
|
6256
|
+
*/
|
|
6257
|
+
const CONVERSATION_PANEL_ID = "conversation";
|
|
6258
|
+
/**
|
|
6234
6259
|
* The composer figure's entry id in `conversation.composer.dock`. Its own id,
|
|
6235
6260
|
* not the shipped `stats` cell's: reusing `stats` would REPLACE the tokens /
|
|
6236
6261
|
* cache-hit / throughput readout rather than inject into it, and that readout
|
|
@@ -6245,12 +6270,15 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6245
6270
|
*/
|
|
6246
6271
|
function apply(ctx) {
|
|
6247
6272
|
injectPageCss();
|
|
6248
|
-
const connection = ctx.get("connection");
|
|
6249
|
-
if (connection !== void 0) installFriendlyImageError(connection, () => ctx.locale.getLocale().active === "zh" ? "zh" : "en");
|
|
6250
6273
|
ctx.effect(() => ctx.locale.register("settings.commandcode", {
|
|
6251
6274
|
zh,
|
|
6252
6275
|
en
|
|
6253
6276
|
}), "dsh-commandcode-provider: page copy");
|
|
6277
|
+
ctx.effect(() => ctx.locale.register(PANEL_LOCALE_NS, {
|
|
6278
|
+
zh: PANEL_COPY_ZH,
|
|
6279
|
+
en: PANEL_COPY_EN
|
|
6280
|
+
}), "dsh-commandcode-provider: panel copy");
|
|
6281
|
+
const connection = ctx.get("connection");
|
|
6254
6282
|
const legacyApi = adaptLegacyCredentials(connection?.api?.credentials);
|
|
6255
6283
|
if (legacyApi !== void 0) {
|
|
6256
6284
|
applyClientSurfaces(ctx, legacyApi, connection?.hostDescription);
|
|
@@ -6463,6 +6491,19 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6463
6491
|
open: () => {
|
|
6464
6492
|
const layout = ctx.get("layout");
|
|
6465
6493
|
if (typeof layout?.selectPanel === "function") layout.selectPanel(PANEL_ID);
|
|
6494
|
+
},
|
|
6495
|
+
close: () => {
|
|
6496
|
+
const layout = ctx.get("layout");
|
|
6497
|
+
if (typeof layout?.selectPanel !== "function") return;
|
|
6498
|
+
try {
|
|
6499
|
+
layout.selectPanel(null);
|
|
6500
|
+
} catch {
|
|
6501
|
+
try {
|
|
6502
|
+
layout.selectPanel(CONVERSATION_PANEL_ID);
|
|
6503
|
+
} catch (error) {
|
|
6504
|
+
console.error("[dsh-commandcode-provider] could not close the plans & quota panel:", error);
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6466
6507
|
}
|
|
6467
6508
|
});
|
|
6468
6509
|
ctx.effect(() => injectPanelCss(), "dsh-commandcode-provider: panel styles");
|
|
@@ -6470,6 +6511,7 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6470
6511
|
ctx.slots.inject("main", () => ctx.slots.register({
|
|
6471
6512
|
name: "main",
|
|
6472
6513
|
key: PANEL_ID,
|
|
6514
|
+
locale: PANEL_LOCALE_NS,
|
|
6473
6515
|
inject: panelFace
|
|
6474
6516
|
}, CommandCodePanel));
|
|
6475
6517
|
} catch (error) {
|
|
@@ -6482,6 +6524,7 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6482
6524
|
name: "sidebar.footer.action",
|
|
6483
6525
|
id: PANEL_ID,
|
|
6484
6526
|
order: 1,
|
|
6527
|
+
locale: PANEL_LOCALE_NS,
|
|
6485
6528
|
inject: panelFace
|
|
6486
6529
|
}, CommandCodeFooterEntry));
|
|
6487
6530
|
} catch (error) {
|
|
@@ -6509,8 +6552,6 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
6509
6552
|
//#endregion
|
|
6510
6553
|
exports.apply = apply;
|
|
6511
6554
|
exports.inject = inject;
|
|
6512
|
-
exports.isImageSessionRejection = isImageSessionRejection;
|
|
6513
|
-
exports.withFriendlyImageError = withFriendlyImageError;
|
|
6514
6555
|
return module.exports;
|
|
6515
6556
|
}
|
|
6516
6557
|
});
|