@mars-sea/dsh-commandcode-provider 0.8.3 → 0.9.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 +38 -0
- package/README.md +3 -0
- package/README.zh-CN.md +3 -0
- package/lib/client.js +563 -91
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +44 -4
- package/lib/index.js +146 -42
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -8,13 +8,114 @@ window.__ModuleLoader__.load({
|
|
|
8
8
|
let react = require("react");
|
|
9
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
|
+
//#region src/command-locales.ts
|
|
12
|
+
const commandcodeCommand = {
|
|
13
|
+
zh: {
|
|
14
|
+
title: "📊 Command Code 用量{account}",
|
|
15
|
+
accountTitle: "📊 {label}{badges}",
|
|
16
|
+
accountSeparator: "────────────────────",
|
|
17
|
+
activeBadge: " ✅ 当前使用",
|
|
18
|
+
invalidCredentialBadge: " ⛔ 密钥无效",
|
|
19
|
+
cooldownBadge: " ⏳ 限额冷却中,重置 {when}",
|
|
20
|
+
rateLimitBadge: " ⏳ 已达限额(等待窗口探测)",
|
|
21
|
+
unconfigured: " (未配置 API 密钥)",
|
|
22
|
+
blockedInvalidKey: "⛔ API 密钥无效或已过期 — 服务端拒绝了全部请求(401),请检查该账户的密钥配置",
|
|
23
|
+
blockedServiceUnavailable: "⚠️ Command Code 服务暂时不可用(5xx),稍后重试",
|
|
24
|
+
blockedNetwork: "⚠️ 无法连接 Command Code 服务 — 请检查网络或 API 地址",
|
|
25
|
+
planLine: " 📦 套餐 {name}{status}{period}",
|
|
26
|
+
planPeriodSuffix: " · 账期截止 {date}",
|
|
27
|
+
usageHeader: "── 请求 ──────────────────────────────",
|
|
28
|
+
requestsLine: " 💬 请求 {n} 次 / 失败 {f} 成功率 {r}%",
|
|
29
|
+
costLine: " 💰 花费 {money} ({credits} credits)",
|
|
30
|
+
tokensLine: " 🔤 Token {in} 入 / {out} 出",
|
|
31
|
+
creditsHeader: "── 信用 ──────────────────────────────",
|
|
32
|
+
monthlyLine: " 💳 月额度 {monthly} (已购 {purchased} / 赠送 {free})",
|
|
33
|
+
barLine: " └ {bar} {pct}%",
|
|
34
|
+
windowsHeader: "── 窗口用量 ──────────────────────────",
|
|
35
|
+
fiveHourLine: " ⏱ 5 小时 {used} / {cap}{warn}",
|
|
36
|
+
weeklyLine: " 📅 每周 {used} / {cap}{warn}",
|
|
37
|
+
windowBarLine: " └ {bar} 重置 {when}",
|
|
38
|
+
exceededWarning: " ⚠️ 超限!",
|
|
39
|
+
resetSuffix: "重置 {when}",
|
|
40
|
+
partialFailures: "⚠️ 部分端点失败: {list}",
|
|
41
|
+
noData: "(no data — check your API key)",
|
|
42
|
+
errorText: "Could not fetch Command Code usage: {message}",
|
|
43
|
+
imageGate: "当前会话已包含图片,而模型 {model} 不支持图片输入;请选择支持图片的模型,或先移除会话中的图片。"
|
|
44
|
+
},
|
|
45
|
+
en: {
|
|
46
|
+
title: "📊 Command Code usage{account}",
|
|
47
|
+
accountTitle: "📊 {label}{badges}",
|
|
48
|
+
accountSeparator: "────────────────────",
|
|
49
|
+
activeBadge: " ✅ active",
|
|
50
|
+
invalidCredentialBadge: " ⛔ invalid key",
|
|
51
|
+
cooldownBadge: " ⏳ cooling down, resets {when}",
|
|
52
|
+
rateLimitBadge: " ⏳ rate-limited (waiting for window probe)",
|
|
53
|
+
unconfigured: " (no API key configured)",
|
|
54
|
+
blockedInvalidKey: "⛔ API key invalid or expired — the server rejected every request (401); check the key configured for this account",
|
|
55
|
+
blockedServiceUnavailable: "⚠️ Command Code service temporarily unavailable (5xx); try again later",
|
|
56
|
+
blockedNetwork: "⚠️ could not reach the Command Code service — check your network or the API base setting",
|
|
57
|
+
planLine: " 📦 Plan {name}{status}{period}",
|
|
58
|
+
planPeriodSuffix: " · period ends {date}",
|
|
59
|
+
usageHeader: "── Requests ──────────────────────────",
|
|
60
|
+
requestsLine: " 💬 Requests {n} / failed {f} success rate {r}%",
|
|
61
|
+
costLine: " 💰 Spend {money} ({credits} credits)",
|
|
62
|
+
tokensLine: " 🔤 Tokens {in} in / {out} out",
|
|
63
|
+
creditsHeader: "── Credits ───────────────────────────",
|
|
64
|
+
monthlyLine: " 💳 Monthly {monthly} (purchased {purchased} / free {free})",
|
|
65
|
+
barLine: " └ {bar} {pct}%",
|
|
66
|
+
windowsHeader: "── Window usage ──────────────────────",
|
|
67
|
+
fiveHourLine: " ⏱ 5-hour {used} / {cap}{warn}",
|
|
68
|
+
weeklyLine: " 📅 Weekly {used} / {cap}{warn}",
|
|
69
|
+
windowBarLine: " └ {bar} resets {when}",
|
|
70
|
+
exceededWarning: " ⚠️ exceeded!",
|
|
71
|
+
resetSuffix: "resets {when}",
|
|
72
|
+
partialFailures: "⚠️ some endpoints failed: {list}",
|
|
73
|
+
noData: "(no data — check your API key)",
|
|
74
|
+
errorText: "Could not fetch Command Code usage: {message}",
|
|
75
|
+
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."
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
11
79
|
//#region src/client/sessions.ts
|
|
80
|
+
/**
|
|
81
|
+
* Friendly-error wrapper for the harness's image-session gate.
|
|
82
|
+
*
|
|
83
|
+
* The host rejects switching to a text-only model while the session already
|
|
84
|
+
* contains images with a `model-unavailable` error
|
|
85
|
+
* (`dsh-host-apiproxy`'s `session.selectModel` handler). That rejection is
|
|
86
|
+
* intentional and cannot be relaxed from the plugin side — the adapter's
|
|
87
|
+
* `inputModalities` is exactly what makes the guard work. What we CAN do is
|
|
88
|
+
* make the error message friendlier: wrap the shared
|
|
89
|
+
* `connection.api.sessions.selectModel` face so a `model-unavailable`
|
|
90
|
+
* rejection shows a clear, actionable hint (with the requested model name)
|
|
91
|
+
* instead of the raw English harness message.
|
|
92
|
+
*
|
|
93
|
+
* The wrapper is deliberately narrow: only the `model-unavailable` code is
|
|
94
|
+
* rewritten, only when the message matches the image-session gate, and only
|
|
95
|
+
* the message text changes — the error code and details pass through
|
|
96
|
+
* untouched so any caller that switches on `error.code` keeps working.
|
|
97
|
+
*
|
|
98
|
+
* The wire types are spelled structurally here (not imported from
|
|
99
|
+
* `@deepseek-ai/dsh-host-apiproxy`) so this client bundle does not drag an
|
|
100
|
+
* extra peer dependency into the package; the shapes are stable and the
|
|
101
|
+
* client build inlines them anyway.
|
|
102
|
+
*
|
|
103
|
+
* The wrapper takes a `getLocale` thunk because it is reached from a
|
|
104
|
+
* non-React path that has no `t` in scope; the supplied thunk reads the
|
|
105
|
+
* active locale at call time (typically `() => ctx.locale.getLocale().active`
|
|
106
|
+
* in the client entry), and the message template lives in the shared
|
|
107
|
+
* `commandcodeCommand` dictionary used by the Host-side `/commandcode`
|
|
108
|
+
* command — the same bilingual surface serves both.
|
|
109
|
+
*
|
|
110
|
+
* This module is deliberately free of React and other client-platform
|
|
111
|
+
* imports so the node test runner can exercise it directly.
|
|
112
|
+
*/
|
|
12
113
|
/** Whether a selectModel rejection is the harness's image-session gate. */
|
|
13
114
|
function isImageSessionRejection(result) {
|
|
14
115
|
return !result.result.ok && result.result.error.code === "model-unavailable" && result.result.error.message.includes("does not accept image input");
|
|
15
116
|
}
|
|
16
117
|
/** Wrap the shared sessions API so selectModel failures read friendlier. */
|
|
17
|
-
function withFriendlyImageError(sessions) {
|
|
118
|
+
function withFriendlyImageError(sessions, getLocale) {
|
|
18
119
|
const selectModel = sessions.selectModel.bind(sessions);
|
|
19
120
|
return {
|
|
20
121
|
...sessions,
|
|
@@ -22,13 +123,14 @@ window.__ModuleLoader__.load({
|
|
|
22
123
|
const result = await selectModel(payload, signal);
|
|
23
124
|
if (!isImageSessionRejection(result)) return result;
|
|
24
125
|
const model = result.result.error.details?.model ?? payload.model;
|
|
126
|
+
const template = commandcodeCommand[getLocale()].imageGate ?? commandcodeCommand.en.imageGate;
|
|
25
127
|
return {
|
|
26
128
|
...result,
|
|
27
129
|
result: {
|
|
28
130
|
...result.result,
|
|
29
131
|
error: {
|
|
30
132
|
...result.result.error,
|
|
31
|
-
message:
|
|
133
|
+
message: template.replace("{model}", model)
|
|
32
134
|
}
|
|
33
135
|
}
|
|
34
136
|
};
|
|
@@ -36,8 +138,8 @@ window.__ModuleLoader__.load({
|
|
|
36
138
|
};
|
|
37
139
|
}
|
|
38
140
|
/** Install the wrapper on a connection's shared sessions face. */
|
|
39
|
-
function installFriendlyImageError(connection) {
|
|
40
|
-
connection.api.sessions = withFriendlyImageError(connection.api.sessions);
|
|
141
|
+
function installFriendlyImageError(connection, getLocale) {
|
|
142
|
+
connection.api.sessions = withFriendlyImageError(connection.api.sessions, getLocale);
|
|
41
143
|
}
|
|
42
144
|
//#endregion
|
|
43
145
|
//#region src/client/settings.ts
|
|
@@ -1197,7 +1299,7 @@ window.__ModuleLoader__.load({
|
|
|
1197
1299
|
};
|
|
1198
1300
|
//#endregion
|
|
1199
1301
|
//#region package.json
|
|
1200
|
-
var version = "0.
|
|
1302
|
+
var version = "0.9.1";
|
|
1201
1303
|
var repository = {
|
|
1202
1304
|
"type": "git",
|
|
1203
1305
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -1377,9 +1479,19 @@ window.__ModuleLoader__.load({
|
|
|
1377
1479
|
*
|
|
1378
1480
|
* The layout mirrors the harness's settings pages: a max-width content
|
|
1379
1481
|
* column, labelled fields with hints, a reset affordance, and a
|
|
1380
|
-
* save/discard footer.
|
|
1482
|
+
* save/discard footer. Rarely touched connection facts (API base, working
|
|
1483
|
+
* directory, timeouts, plan filter) fold into a collapsed Advanced card
|
|
1484
|
+
* (`AdvancedSection`) so the page leads with the key and the usage facts.
|
|
1485
|
+
* Styles are injected once by the client entry
|
|
1381
1486
|
* (see src/client/index.ts) and class-prefixed `cc-` to stay local.
|
|
1382
1487
|
*/
|
|
1488
|
+
const ADVANCED_FIELDS = [
|
|
1489
|
+
"apiBase",
|
|
1490
|
+
"workingDir",
|
|
1491
|
+
"requestTimeoutMs",
|
|
1492
|
+
"streamIdleTimeoutMs",
|
|
1493
|
+
"filterModelsByPlan"
|
|
1494
|
+
];
|
|
1383
1495
|
/** One labelled field row in the page body. */
|
|
1384
1496
|
function Field({ id, label, hint, state, disabled, numeric, placeholder, onEdit, onReset, t }) {
|
|
1385
1497
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1429,6 +1541,114 @@ window.__ModuleLoader__.load({
|
|
|
1429
1541
|
return t("invalidNumber");
|
|
1430
1542
|
}
|
|
1431
1543
|
/**
|
|
1544
|
+
* The collapsed "Advanced" card: API base, working dir, both timeouts, and
|
|
1545
|
+
* the plan filter live here so the page leads with the facts a user actually
|
|
1546
|
+
* touches. Starts collapsed on every visit; expands on demand. While
|
|
1547
|
+
* collapsed, a badge names the customized count so a nonzero override stays
|
|
1548
|
+
* visible (a number field's error blocks save and must be reachable).
|
|
1549
|
+
*/
|
|
1550
|
+
function AdvancedSection({ state, disabled, t, onEdit, onReset }) {
|
|
1551
|
+
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
1552
|
+
const overridden = ADVANCED_FIELDS.filter((field) => state[field].overridden).length;
|
|
1553
|
+
const invalid = ADVANCED_FIELDS.some((field) => state[field].invalid);
|
|
1554
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1555
|
+
className: "cc-card",
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1558
|
+
type: "button",
|
|
1559
|
+
className: "cc-advancedHead",
|
|
1560
|
+
"aria-expanded": expanded,
|
|
1561
|
+
"aria-controls": "cc-advanced-body",
|
|
1562
|
+
onClick: () => setExpanded((value) => !value),
|
|
1563
|
+
children: [
|
|
1564
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1565
|
+
className: "cc-advancedTitle",
|
|
1566
|
+
children: t("advancedSettings")
|
|
1567
|
+
}),
|
|
1568
|
+
overridden > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1569
|
+
className: "cc-badge",
|
|
1570
|
+
children: overridden === 1 ? t("advancedOverriddenOne") : t("advancedOverriddenMany").replace("{count}", String(overridden))
|
|
1571
|
+
}) : null,
|
|
1572
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "cc-advancedSpacer" }),
|
|
1573
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1574
|
+
className: expanded ? "cc-chevron cc-chevronUp" : "cc-chevron",
|
|
1575
|
+
"aria-hidden": "true"
|
|
1576
|
+
})
|
|
1577
|
+
]
|
|
1578
|
+
}),
|
|
1579
|
+
expanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1580
|
+
id: "cc-advanced-body",
|
|
1581
|
+
className: "cc-advancedBody",
|
|
1582
|
+
children: [
|
|
1583
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1584
|
+
className: "cc-hint",
|
|
1585
|
+
children: t("advancedSettingsHint")
|
|
1586
|
+
}),
|
|
1587
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1588
|
+
id: "cc-api-base",
|
|
1589
|
+
label: t("apiBase"),
|
|
1590
|
+
hint: t("apiBaseHint"),
|
|
1591
|
+
state: state.apiBase,
|
|
1592
|
+
disabled,
|
|
1593
|
+
onEdit: (text) => onEdit("apiBase", text),
|
|
1594
|
+
onReset: () => onReset("apiBase"),
|
|
1595
|
+
t
|
|
1596
|
+
}),
|
|
1597
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1598
|
+
id: "cc-working-dir",
|
|
1599
|
+
label: t("workingDir"),
|
|
1600
|
+
hint: t("workingDirHint"),
|
|
1601
|
+
state: state.workingDir,
|
|
1602
|
+
disabled,
|
|
1603
|
+
placeholder: state.defaultWorkingDir,
|
|
1604
|
+
onEdit: (text) => onEdit("workingDir", text),
|
|
1605
|
+
onReset: () => onReset("workingDir"),
|
|
1606
|
+
t
|
|
1607
|
+
}),
|
|
1608
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1609
|
+
id: "cc-request-timeout",
|
|
1610
|
+
label: t("requestTimeoutMs"),
|
|
1611
|
+
hint: t("requestTimeoutMsHint"),
|
|
1612
|
+
state: state.requestTimeoutMs,
|
|
1613
|
+
disabled,
|
|
1614
|
+
numeric: true,
|
|
1615
|
+
onEdit: (text) => onEdit("requestTimeoutMs", text),
|
|
1616
|
+
onReset: () => onReset("requestTimeoutMs"),
|
|
1617
|
+
t
|
|
1618
|
+
}),
|
|
1619
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
1620
|
+
id: "cc-stream-idle-timeout",
|
|
1621
|
+
label: t("streamIdleTimeoutMs"),
|
|
1622
|
+
hint: t("streamIdleTimeoutMsHint"),
|
|
1623
|
+
state: state.streamIdleTimeoutMs,
|
|
1624
|
+
disabled,
|
|
1625
|
+
numeric: true,
|
|
1626
|
+
onEdit: (text) => onEdit("streamIdleTimeoutMs", text),
|
|
1627
|
+
onReset: () => onReset("streamIdleTimeoutMs"),
|
|
1628
|
+
t
|
|
1629
|
+
}),
|
|
1630
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
1631
|
+
id: "cc-filter-models-by-plan",
|
|
1632
|
+
label: t("filterModelsByPlan"),
|
|
1633
|
+
hint: t("filterModelsByPlanHint"),
|
|
1634
|
+
state: state.filterModelsByPlan,
|
|
1635
|
+
disabled,
|
|
1636
|
+
defaultChecked: true,
|
|
1637
|
+
onEdit: (text) => onEdit("filterModelsByPlan", text),
|
|
1638
|
+
onReset: () => onReset("filterModelsByPlan"),
|
|
1639
|
+
t
|
|
1640
|
+
})
|
|
1641
|
+
]
|
|
1642
|
+
}) : null,
|
|
1643
|
+
expanded && invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1644
|
+
className: "cc-invalid",
|
|
1645
|
+
role: "status",
|
|
1646
|
+
children: t("advancedInvalid")
|
|
1647
|
+
}) : null
|
|
1648
|
+
]
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1432
1652
|
* One boolean field row rendered as a toggle. The staged text is `'true'` /
|
|
1433
1653
|
* `'false'` / `''` (unset → `defaultChecked`); toggling stages the string the
|
|
1434
1654
|
* boolean field spec parses back into a real boolean on save.
|
|
@@ -1536,7 +1756,7 @@ window.__ModuleLoader__.load({
|
|
|
1536
1756
|
});
|
|
1537
1757
|
}
|
|
1538
1758
|
/** The per-reason copy for a failed login attempt. */
|
|
1539
|
-
function loginFailureCopy(reason, t) {
|
|
1759
|
+
function loginFailureCopy$1(reason, t) {
|
|
1540
1760
|
if (reason === "denied") return t("loginDenied");
|
|
1541
1761
|
if (reason === "timeout") return t("loginTimeout");
|
|
1542
1762
|
if (reason === "invalid-key") return t("loginInvalidKey");
|
|
@@ -1562,7 +1782,7 @@ window.__ModuleLoader__.load({
|
|
|
1562
1782
|
hint = `${t("loginSuccess")} ${state.userName ?? ""}${keyName}`.trim();
|
|
1563
1783
|
hintClass = "cc-loginDone";
|
|
1564
1784
|
} else if (state.phase === "failed") {
|
|
1565
|
-
hint = loginFailureCopy(state.reason, t);
|
|
1785
|
+
hint = loginFailureCopy$1(state.reason, t);
|
|
1566
1786
|
hintClass = "cc-loginError";
|
|
1567
1787
|
if (state.message !== void 0) hintTitle = state.message;
|
|
1568
1788
|
} else if (state.phase === "unavailable") {
|
|
@@ -2230,86 +2450,36 @@ window.__ModuleLoader__.load({
|
|
|
2230
2450
|
}),
|
|
2231
2451
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2232
2452
|
className: "cc-card",
|
|
2233
|
-
children: [
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
disabled,
|
|
2264
|
-
onEdit: (text) => props.edit("apiBase", text),
|
|
2265
|
-
onReset: () => props.resetField("apiBase"),
|
|
2266
|
-
t
|
|
2267
|
-
}),
|
|
2268
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2269
|
-
id: "cc-working-dir",
|
|
2270
|
-
label: t("workingDir"),
|
|
2271
|
-
hint: t("workingDirHint"),
|
|
2272
|
-
state: state.workingDir,
|
|
2273
|
-
disabled,
|
|
2274
|
-
placeholder: state.defaultWorkingDir,
|
|
2275
|
-
onEdit: (text) => props.edit("workingDir", text),
|
|
2276
|
-
onReset: () => props.resetField("workingDir"),
|
|
2277
|
-
t
|
|
2278
|
-
}),
|
|
2279
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2280
|
-
id: "cc-request-timeout",
|
|
2281
|
-
label: t("requestTimeoutMs"),
|
|
2282
|
-
hint: t("requestTimeoutMsHint"),
|
|
2283
|
-
state: state.requestTimeoutMs,
|
|
2284
|
-
disabled,
|
|
2285
|
-
numeric: true,
|
|
2286
|
-
onEdit: (text) => props.edit("requestTimeoutMs", text),
|
|
2287
|
-
onReset: () => props.resetField("requestTimeoutMs"),
|
|
2288
|
-
t
|
|
2289
|
-
}),
|
|
2290
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2291
|
-
id: "cc-stream-idle-timeout",
|
|
2292
|
-
label: t("streamIdleTimeoutMs"),
|
|
2293
|
-
hint: t("streamIdleTimeoutMsHint"),
|
|
2294
|
-
state: state.streamIdleTimeoutMs,
|
|
2295
|
-
disabled,
|
|
2296
|
-
numeric: true,
|
|
2297
|
-
onEdit: (text) => props.edit("streamIdleTimeoutMs", text),
|
|
2298
|
-
onReset: () => props.resetField("streamIdleTimeoutMs"),
|
|
2299
|
-
t
|
|
2300
|
-
}),
|
|
2301
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
2302
|
-
id: "cc-filter-models-by-plan",
|
|
2303
|
-
label: t("filterModelsByPlan"),
|
|
2304
|
-
hint: t("filterModelsByPlanHint"),
|
|
2305
|
-
state: state.filterModelsByPlan,
|
|
2306
|
-
disabled,
|
|
2307
|
-
defaultChecked: true,
|
|
2308
|
-
onEdit: (text) => props.edit("filterModelsByPlan", text),
|
|
2309
|
-
onReset: () => props.resetField("filterModelsByPlan"),
|
|
2310
|
-
t
|
|
2311
|
-
})
|
|
2312
|
-
]
|
|
2453
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretKeyField, {
|
|
2454
|
+
label: t("apiKey"),
|
|
2455
|
+
hint: keyLocked ? t("apiKeyLocked") : t("apiKeyHint"),
|
|
2456
|
+
state: state.apiKey,
|
|
2457
|
+
disabled: disabled || keyLocked,
|
|
2458
|
+
configured: state.apiKeyConfigured,
|
|
2459
|
+
configuredLabel: t("apiKeySet"),
|
|
2460
|
+
unconfiguredLabel: t("apiKeyUnset"),
|
|
2461
|
+
clearStaged: state.apiKeyClearStaged,
|
|
2462
|
+
showLabel: t("show"),
|
|
2463
|
+
hideLabel: t("hide"),
|
|
2464
|
+
clearLabel: t("usageKeyClear"),
|
|
2465
|
+
clearStagedLabel: t("usageKeyClearStaged"),
|
|
2466
|
+
undoClearLabel: t("usageUndoKeyClear"),
|
|
2467
|
+
onEdit: (text) => props.edit("apiKey", text),
|
|
2468
|
+
onToggleClear: () => props.toggleKeyClear("default")
|
|
2469
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LoginPanel, {
|
|
2470
|
+
state: login,
|
|
2471
|
+
disabled: disabled || keyLocked,
|
|
2472
|
+
t,
|
|
2473
|
+
onBegin: props.beginLogin,
|
|
2474
|
+
onCancel: props.cancelLogin
|
|
2475
|
+
})]
|
|
2476
|
+
}),
|
|
2477
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AdvancedSection, {
|
|
2478
|
+
state,
|
|
2479
|
+
disabled,
|
|
2480
|
+
t,
|
|
2481
|
+
onEdit: props.edit,
|
|
2482
|
+
onReset: props.resetField
|
|
2313
2483
|
}),
|
|
2314
2484
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2315
2485
|
className: "cc-footer",
|
|
@@ -2364,6 +2534,260 @@ window.__ModuleLoader__.load({
|
|
|
2364
2534
|
});
|
|
2365
2535
|
}
|
|
2366
2536
|
//#endregion
|
|
2537
|
+
//#region src/client/card.tsx
|
|
2538
|
+
/**
|
|
2539
|
+
* The Command Code provider card inside the harness Models settings page
|
|
2540
|
+
* (browser half). Rendered through the `settings.models.provider-card` keyed
|
|
2541
|
+
* slot introduced in dsh 0.1.2-alpha.1, registered with
|
|
2542
|
+
* `entryKey = 'llm-commandcode'` (the plugin's settings namespace, the key the
|
|
2543
|
+
* Models page dispatches for every Command Code provider row).
|
|
2544
|
+
*
|
|
2545
|
+
* The slot's owner props (`configured`, `keyConfigured`) mirror what the
|
|
2546
|
+
* Models page already knows; the authoritative credential facts still come
|
|
2547
|
+
* from this plugin's `CommandCodeSettingsController` shared with the dedicated
|
|
2548
|
+
* settings page, so the two surfaces can never disagree about whether a key
|
|
2549
|
+
* is stored.
|
|
2550
|
+
*
|
|
2551
|
+
* Not configured: an "Unconfigured" badge, a paste-a-key field, and the
|
|
2552
|
+
* official sign-in button — the whole flow a first-run user needs, inline.
|
|
2553
|
+
* Configured: a green "Configured" badge plus a pointer to the full
|
|
2554
|
+
* Command Code settings page for rotation, usage, and connection facts.
|
|
2555
|
+
*
|
|
2556
|
+
* The card renders nothing until the shared controller's first snapshot is
|
|
2557
|
+
* ready (`available`), which also keeps the stale-facts window of the older
|
|
2558
|
+
* join from ever being visible. A controller-less render (card mounted before
|
|
2559
|
+
* the section registered its inject face — the composition runs one apply)
|
|
2560
|
+
* degrades to the stateless registration-notice form.
|
|
2561
|
+
*
|
|
2562
|
+
* Styles ride the page stylesheet the client entry injects once (`cc-`
|
|
2563
|
+
* prefixed classes); the card adds no CSS of its own.
|
|
2564
|
+
*/
|
|
2565
|
+
/** Decide the card's posture from the injected face and the owner facts. */
|
|
2566
|
+
function cardMode(props) {
|
|
2567
|
+
if (props.useCommandCodeSettings === void 0) return { kind: "registration" };
|
|
2568
|
+
const snapshot = props.useCommandCodeSettings((state) => state);
|
|
2569
|
+
return {
|
|
2570
|
+
kind: "live",
|
|
2571
|
+
ready: snapshot.available,
|
|
2572
|
+
controllerConfigured: snapshot.apiKeyConfigured,
|
|
2573
|
+
writable: snapshot.writable,
|
|
2574
|
+
apiKeyWritable: snapshot.apiKeyWritable
|
|
2575
|
+
};
|
|
2576
|
+
}
|
|
2577
|
+
/** Status badge for the credential state (green when configured). */
|
|
2578
|
+
function StatusBadge({ ok, okLabel, pendingLabel }) {
|
|
2579
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2580
|
+
className: ok ? "cc-badge" : "cc-badgeMuted",
|
|
2581
|
+
children: ok ? okLabel : pendingLabel
|
|
2582
|
+
});
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* The per-reason copy for a failed login attempt (mirrors the settings
|
|
2586
|
+
* page's LoginPanel; the same reasons can surface from this card).
|
|
2587
|
+
*/
|
|
2588
|
+
function loginFailureCopy(reason, t) {
|
|
2589
|
+
if (reason === "denied") return t("loginDenied");
|
|
2590
|
+
if (reason === "timeout") return t("loginTimeout");
|
|
2591
|
+
if (reason === "invalid-key") return t("loginInvalidKey");
|
|
2592
|
+
if (reason === "network") return t("loginNetwork");
|
|
2593
|
+
if (reason === "unavailable") return t("loginStoreFailed");
|
|
2594
|
+
if (reason === "cancelled") return t("loginCancelled");
|
|
2595
|
+
return t("loginFailedGeneric");
|
|
2596
|
+
}
|
|
2597
|
+
/** The sign-in affordance row for the not-configured card (see LoginPanel). */
|
|
2598
|
+
function CardLoginRow({ state, disabled, t, onBegin, onCancel }) {
|
|
2599
|
+
const busy = state.phase === "starting" || state.phase === "waiting";
|
|
2600
|
+
let hint = t("loginHintIdle");
|
|
2601
|
+
let hintClass = "cc-hint";
|
|
2602
|
+
if (state.phase === "starting" || state.phase === "waiting") hint = t(state.phase === "starting" ? "loginStarting" : "loginWaiting");
|
|
2603
|
+
else if (state.phase === "success") {
|
|
2604
|
+
const keyName = state.keyName !== void 0 && state.keyName !== "" ? ` · ${state.keyName}` : "";
|
|
2605
|
+
hint = `${t("loginSuccess")} ${state.userName ?? ""}${keyName}`.trim();
|
|
2606
|
+
hintClass = "cc-loginDone";
|
|
2607
|
+
} else if (state.phase === "failed") {
|
|
2608
|
+
hint = loginFailureCopy(state.reason, t);
|
|
2609
|
+
hintClass = "cc-loginError";
|
|
2610
|
+
} else if (state.phase === "unavailable") {
|
|
2611
|
+
hint = `${t("loginUnavailable")} ${state.message ?? ""}`.trim();
|
|
2612
|
+
hintClass = "cc-loginError";
|
|
2613
|
+
}
|
|
2614
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2615
|
+
className: "cc-field",
|
|
2616
|
+
children: [
|
|
2617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2618
|
+
className: "cc-fieldHead",
|
|
2619
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2620
|
+
className: "cc-label",
|
|
2621
|
+
children: t("loginTitle")
|
|
2622
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2623
|
+
className: "cc-badges",
|
|
2624
|
+
children: busy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2625
|
+
type: "button",
|
|
2626
|
+
className: "cc-reset",
|
|
2627
|
+
onClick: onCancel,
|
|
2628
|
+
children: t("loginCancel")
|
|
2629
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2630
|
+
type: "button",
|
|
2631
|
+
className: "cc-reset",
|
|
2632
|
+
disabled,
|
|
2633
|
+
onClick: onBegin,
|
|
2634
|
+
children: t("loginButton")
|
|
2635
|
+
})
|
|
2636
|
+
})]
|
|
2637
|
+
}),
|
|
2638
|
+
state.authUrl !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2639
|
+
className: "cc-hint",
|
|
2640
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
2641
|
+
className: "cc-loginLink",
|
|
2642
|
+
href: state.authUrl,
|
|
2643
|
+
target: "_blank",
|
|
2644
|
+
rel: "noreferrer",
|
|
2645
|
+
children: t("loginOpenLink")
|
|
2646
|
+
})
|
|
2647
|
+
}) : null,
|
|
2648
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2649
|
+
className: hintClass,
|
|
2650
|
+
children: hint
|
|
2651
|
+
})
|
|
2652
|
+
]
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
/** Compact key field for the not-configured card. */
|
|
2656
|
+
function CardKeyField({ state, disabled, t, onEdit }) {
|
|
2657
|
+
const [visible, setVisible] = (0, react.useState)(false);
|
|
2658
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2659
|
+
className: "cc-field",
|
|
2660
|
+
children: [
|
|
2661
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2662
|
+
className: "cc-fieldHead",
|
|
2663
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
2664
|
+
className: "cc-label",
|
|
2665
|
+
htmlFor: "cc-card-api-key",
|
|
2666
|
+
children: t("apiKey")
|
|
2667
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2668
|
+
className: "cc-badges",
|
|
2669
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2670
|
+
type: "button",
|
|
2671
|
+
className: "cc-reset",
|
|
2672
|
+
disabled,
|
|
2673
|
+
onClick: () => setVisible((value) => !value),
|
|
2674
|
+
children: visible ? t("hide") : t("show")
|
|
2675
|
+
})
|
|
2676
|
+
})]
|
|
2677
|
+
}),
|
|
2678
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2679
|
+
id: "cc-card-api-key",
|
|
2680
|
+
className: "cc-input",
|
|
2681
|
+
type: visible ? "text" : "password",
|
|
2682
|
+
autoComplete: "off",
|
|
2683
|
+
spellCheck: false,
|
|
2684
|
+
value: state.text,
|
|
2685
|
+
disabled,
|
|
2686
|
+
onChange: (event) => onEdit(event.target.value)
|
|
2687
|
+
}),
|
|
2688
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2689
|
+
className: "cc-hint",
|
|
2690
|
+
children: t("apiKeyHint")
|
|
2691
|
+
})
|
|
2692
|
+
]
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
/** One "Configured" badge + pointer to the full settings page (footer area). */
|
|
2696
|
+
function CardConfiguredBody({ t }) {
|
|
2697
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2698
|
+
className: "cc-field",
|
|
2699
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2700
|
+
className: "cc-hint",
|
|
2701
|
+
children: t("cardConfiguredHint")
|
|
2702
|
+
})
|
|
2703
|
+
});
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* The slot component body. Dispatched on every Command Code provider card of
|
|
2707
|
+
* the Models page (saved row, first-run setup posture, and add-provider
|
|
2708
|
+
* draft).
|
|
2709
|
+
*/
|
|
2710
|
+
function CommandCodeProviderCard(props) {
|
|
2711
|
+
const { t } = props;
|
|
2712
|
+
const mode = cardMode(props);
|
|
2713
|
+
const state = props.useCommandCodeSettings !== void 0 ? props.useCommandCodeSettings((snapshot) => snapshot) : void 0;
|
|
2714
|
+
const login = props.useCommandCodeLogin !== void 0 ? props.useCommandCodeLogin((snapshot) => snapshot) : void 0;
|
|
2715
|
+
const dirty = state?.dirty ?? false;
|
|
2716
|
+
const saving = state?.saving ?? false;
|
|
2717
|
+
const invalid = state?.invalid ?? false;
|
|
2718
|
+
const failed = state?.failed ?? false;
|
|
2719
|
+
const savingBlocked = !dirty || invalid;
|
|
2720
|
+
const configured = mode.kind === "live" && mode.ready ? mode.controllerConfigured : props.keyConfigured;
|
|
2721
|
+
const disabled = mode.kind === "live" && (!mode.writable || state !== void 0 && !mode.apiKeyWritable);
|
|
2722
|
+
const showBody = mode.kind === "live" && mode.ready && state !== void 0;
|
|
2723
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2724
|
+
className: "cc-providerCard",
|
|
2725
|
+
"data-cc-models-card": "true",
|
|
2726
|
+
children: [
|
|
2727
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2728
|
+
className: "cc-field",
|
|
2729
|
+
children: [
|
|
2730
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2731
|
+
className: "cc-fieldHead",
|
|
2732
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2733
|
+
className: "cc-label",
|
|
2734
|
+
children: t("cardTitle")
|
|
2735
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2736
|
+
className: "cc-badges",
|
|
2737
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(StatusBadge, {
|
|
2738
|
+
ok: configured,
|
|
2739
|
+
okLabel: t("apiKeySet"),
|
|
2740
|
+
pendingLabel: t("apiKeyUnset")
|
|
2741
|
+
}), props.provider.active ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2742
|
+
className: "cc-badge",
|
|
2743
|
+
children: t("cardRouteActive")
|
|
2744
|
+
}) : null]
|
|
2745
|
+
})]
|
|
2746
|
+
}),
|
|
2747
|
+
mode.kind === "registration" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2748
|
+
className: "cc-hint",
|
|
2749
|
+
children: t("cardRegistrationHint")
|
|
2750
|
+
}) : null,
|
|
2751
|
+
mode.kind === "live" && !mode.ready ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2752
|
+
className: "cc-hint",
|
|
2753
|
+
children: t("cardLoadingHint")
|
|
2754
|
+
}) : null
|
|
2755
|
+
]
|
|
2756
|
+
}),
|
|
2757
|
+
showBody && !configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2758
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardKeyField, {
|
|
2759
|
+
state: state.apiKey,
|
|
2760
|
+
disabled,
|
|
2761
|
+
t,
|
|
2762
|
+
onEdit: (text) => props.edit("apiKey", text)
|
|
2763
|
+
}),
|
|
2764
|
+
login !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardLoginRow, {
|
|
2765
|
+
state: login,
|
|
2766
|
+
disabled,
|
|
2767
|
+
t,
|
|
2768
|
+
onBegin: props.beginLogin,
|
|
2769
|
+
onCancel: props.cancelLogin
|
|
2770
|
+
}) : null,
|
|
2771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2772
|
+
className: "cc-footer",
|
|
2773
|
+
children: [failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2774
|
+
className: "cc-failed",
|
|
2775
|
+
role: "status",
|
|
2776
|
+
children: t("saveFailed")
|
|
2777
|
+
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2778
|
+
type: "button",
|
|
2779
|
+
className: "cc-reset",
|
|
2780
|
+
disabled: savingBlocked || saving,
|
|
2781
|
+
onClick: props.save,
|
|
2782
|
+
children: t(saving ? "saving" : "save")
|
|
2783
|
+
})]
|
|
2784
|
+
})
|
|
2785
|
+
] }) : null,
|
|
2786
|
+
showBody && configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardConfiguredBody, { t }) : null
|
|
2787
|
+
]
|
|
2788
|
+
});
|
|
2789
|
+
}
|
|
2790
|
+
//#endregion
|
|
2367
2791
|
//#region src/client/locales.ts
|
|
2368
2792
|
const zh = {
|
|
2369
2793
|
nav: "Command Code",
|
|
@@ -2382,6 +2806,11 @@ window.__ModuleLoader__.load({
|
|
|
2382
2806
|
requestTimeoutMsHint: "等待响应首个字节的超时;默认 60000。",
|
|
2383
2807
|
streamIdleTimeoutMs: "流空闲超时(毫秒)",
|
|
2384
2808
|
streamIdleTimeoutMsHint: "生成流停滞多久视为断连;默认 300000(长思考模型可静默数分钟,默认值刻意放宽)。",
|
|
2809
|
+
advancedSettings: "高级设置",
|
|
2810
|
+
advancedSettingsHint: "API 地址、工作目录、超时与模型过滤等不常修改的选项。",
|
|
2811
|
+
advancedOverriddenOne: "已自定义 1 项",
|
|
2812
|
+
advancedOverriddenMany: "已自定义 {count} 项",
|
|
2813
|
+
advancedInvalid: "高级设置中有未填好的数字,请展开修正后再保存。",
|
|
2385
2814
|
filterModelsByPlan: "隐藏套餐外模型",
|
|
2386
2815
|
filterModelsByPlanHint: "开启后,模型选择器只列出当前套餐可用的模型;账户持有按需余额时会显示全部。",
|
|
2387
2816
|
accountsTitle: "多账户轮换",
|
|
@@ -2463,7 +2892,12 @@ window.__ModuleLoader__.load({
|
|
|
2463
2892
|
loginNetwork: "无法连接 Command Code 服务校验密钥,请检查网络后重试。",
|
|
2464
2893
|
loginStoreFailed: "密钥无法写入本机凭据服务,请手动粘贴。",
|
|
2465
2894
|
loginCancelled: "登录已取消。",
|
|
2466
|
-
loginFailedGeneric: "登录失败,请重试或手动粘贴密钥。"
|
|
2895
|
+
loginFailedGeneric: "登录失败,请重试或手动粘贴密钥。",
|
|
2896
|
+
cardTitle: "Command Code 连接",
|
|
2897
|
+
cardRouteActive: "已启用",
|
|
2898
|
+
cardLoadingHint: "正在读取 Command Code 配置…",
|
|
2899
|
+
cardRegistrationHint: "此卡片随 Command Code 插件注册,需要较新版本的 DeepSeek Harness 才会显示完整内容。",
|
|
2900
|
+
cardConfiguredHint: "API 密钥已就绪。如需更换密钥、添加多账户轮换、查看用量或修改 API 地址,请前往设置中的「Command Code」页。"
|
|
2467
2901
|
};
|
|
2468
2902
|
const en = {
|
|
2469
2903
|
nav: "Command Code",
|
|
@@ -2482,6 +2916,11 @@ window.__ModuleLoader__.load({
|
|
|
2482
2916
|
requestTimeoutMsHint: "Time to wait for the first response byte; default 60000.",
|
|
2483
2917
|
streamIdleTimeoutMs: "Stream idle timeout (ms)",
|
|
2484
2918
|
streamIdleTimeoutMsHint: "How long a stalled stream is treated as dead; default 300000 (deliberately generous — long-thinking models can stay silent for minutes).",
|
|
2919
|
+
advancedSettings: "Advanced",
|
|
2920
|
+
advancedSettingsHint: "Rarely touched options: API base URL, working directory, timeouts, and model filtering.",
|
|
2921
|
+
advancedOverriddenOne: "1 customized",
|
|
2922
|
+
advancedOverriddenMany: "{count} customized",
|
|
2923
|
+
advancedInvalid: "A number in Advanced settings is not ready to save; expand to fix it.",
|
|
2485
2924
|
filterModelsByPlan: "Hide out-of-plan models",
|
|
2486
2925
|
filterModelsByPlanHint: "When on, the model picker lists only models your subscription includes; any on-demand credit balance shows the full catalog.",
|
|
2487
2926
|
accountsTitle: "Account rotation",
|
|
@@ -2563,7 +3002,12 @@ window.__ModuleLoader__.load({
|
|
|
2563
3002
|
loginNetwork: "Could not reach the Command Code service to validate the key; check your network and retry.",
|
|
2564
3003
|
loginStoreFailed: "The key could not be stored in the local credential service; paste it manually.",
|
|
2565
3004
|
loginCancelled: "Sign-in cancelled.",
|
|
2566
|
-
loginFailedGeneric: "Sign-in failed; try again or paste the key manually."
|
|
3005
|
+
loginFailedGeneric: "Sign-in failed; try again or paste the key manually.",
|
|
3006
|
+
cardTitle: "Command Code connection",
|
|
3007
|
+
cardRouteActive: "Active",
|
|
3008
|
+
cardLoadingHint: "Loading the Command Code configuration…",
|
|
3009
|
+
cardRegistrationHint: "This card is contributed by the Command Code plugin; a newer DeepSeek Harness is needed to show the full controls.",
|
|
3010
|
+
cardConfiguredHint: "The API key is ready. To replace it, add account rotation, review usage, or change the API base, open the \"Command Code\" page in Settings."
|
|
2567
3011
|
};
|
|
2568
3012
|
//#endregion
|
|
2569
3013
|
//#region src/client/index.ts
|
|
@@ -2596,6 +3040,16 @@ window.__ModuleLoader__.load({
|
|
|
2596
3040
|
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}
|
|
2597
3041
|
.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}
|
|
2598
3042
|
.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
|
|
3043
|
+
/* The Advanced card: its header row is one full-width toggle button; the
|
|
3044
|
+
* chevron is two borders on a rotated square (no icon dependency). */
|
|
3045
|
+
.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}
|
|
3046
|
+
.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}
|
|
3047
|
+
.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}
|
|
3048
|
+
.cc-advancedSpacer{flex:1}
|
|
3049
|
+
.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}
|
|
3050
|
+
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
3051
|
+
.cc-advancedBody{flex-direction:column;display:flex}
|
|
3052
|
+
.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
2599
3053
|
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
2600
3054
|
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
2601
3055
|
.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}
|
|
@@ -2682,7 +3136,7 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
2682
3136
|
function apply(ctx) {
|
|
2683
3137
|
injectPageCss();
|
|
2684
3138
|
const connection = ctx.get("connection");
|
|
2685
|
-
if (connection !== void 0) installFriendlyImageError(connection);
|
|
3139
|
+
if (connection !== void 0) installFriendlyImageError(connection, () => ctx.locale.getLocale().active);
|
|
2686
3140
|
ctx.effect(() => ctx.locale.register("settings.commandcode", {
|
|
2687
3141
|
zh,
|
|
2688
3142
|
en
|
|
@@ -2800,6 +3254,24 @@ select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box
|
|
|
2800
3254
|
locale: "settings.commandcode",
|
|
2801
3255
|
inject: injected
|
|
2802
3256
|
}, CommandCodeSettingsPage));
|
|
3257
|
+
ctx.slots.inject("settings.models.provider-card", () => ctx.slots.register({
|
|
3258
|
+
name: "settings.models.provider-card",
|
|
3259
|
+
key: "llm-commandcode",
|
|
3260
|
+
locale: "settings.commandcode",
|
|
3261
|
+
inject: () => ({
|
|
3262
|
+
hooks: {
|
|
3263
|
+
commandCodeSettings: store,
|
|
3264
|
+
commandCodeLogin: loginStore
|
|
3265
|
+
},
|
|
3266
|
+
edit: (field, text) => controller.edit(field, text),
|
|
3267
|
+
save: () => void controller.save().then(() => {
|
|
3268
|
+
const settled = controller.state();
|
|
3269
|
+
if (!settled.failed && settled.anyAccountConfigured) usageController.refresh();
|
|
3270
|
+
}),
|
|
3271
|
+
beginLogin: () => void loginController.begin(),
|
|
3272
|
+
cancelLogin: () => void loginController.cancel()
|
|
3273
|
+
})
|
|
3274
|
+
}, CommandCodeProviderCard));
|
|
2803
3275
|
}
|
|
2804
3276
|
const inject = [
|
|
2805
3277
|
"slots",
|