dsh-llm-codebuddy-power 1.0.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -22
- package/README.md +84 -66
- package/README.zh.md +84 -66
- package/cordis.patch.yml +7 -7
- package/icon.svg +6 -0
- package/lib/cli-login.js +113 -110
- package/lib/client.js +491 -410
- package/lib/index.js +439 -273
- package/lib/types/adapter.d.ts +7 -1
- package/lib/types/auth-service.d.ts +68 -22
- package/lib/types/cli/login.d.ts +1 -2
- package/lib/types/client/AccountSwitcher.d.ts +1 -2
- package/lib/types/client/CodeBuddySection.d.ts +17 -12
- package/lib/types/client/TurnCreditPill.d.ts +5 -4
- package/lib/types/client/index.d.ts +6 -6
- package/lib/types/client/locales.d.ts +6 -4
- package/lib/types/client/store.d.ts +19 -13
- package/lib/types/client/wire.d.ts +20 -3
- package/lib/types/constants.d.ts +15 -0
- package/lib/types/index.d.ts +44 -22
- package/lib/types/prefs.d.ts +17 -13
- package/lib/types/serialize.d.ts +19 -10
- package/lib/types/session-store.d.ts +1 -1
- package/lib/types/session.d.ts +59 -29
- package/lib/types/settings.d.ts +10 -7
- package/lib/types/storage.d.ts +6 -13
- package/lib/types/usage.d.ts +4 -2
- package/package.json +37 -30
- package/lib/types/client/UsageIndicator.d.ts +0 -21
- package/lib/types/client/poll.d.ts +0 -19
- package/lib/types/credit-store.d.ts +0 -25
- package/lib/types/selection.d.ts +0 -35
package/lib/client.js
CHANGED
|
@@ -10,20 +10,7 @@ window.__ModuleLoader__.load({
|
|
|
10
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
11
11
|
let react_dom = require("react-dom");
|
|
12
12
|
//#region src/prefs.ts
|
|
13
|
-
/**
|
|
14
|
-
* CodeBuddy 界面偏好的命名空间契约,Host 与 Client 两面共享。
|
|
15
|
-
*
|
|
16
|
-
* 这些偏好是**插件自己的设置命名空间**里的一段:`Config` 提供部署级 base,
|
|
17
|
-
* 用户在 Web 设置页的写入落在 harness 的用户设置文档里,因此换浏览器、重启
|
|
18
|
-
* harness 后仍然生效 —— 其中「极简模式画图工具」还会被宿主读取来决定
|
|
19
|
-
* `codebuddy-draw` 对模型是否可见,存在浏览器里会让同一次部署因浏览器而异。
|
|
20
|
-
*
|
|
21
|
-
* 本文件必须保持零依赖:两面都会编译它,而 Client 面若因此引入 schemastery
|
|
22
|
-
* 就会把它打进浏览器产物(校验 schema 是宿主面的事,见 `./settings.ts`)。
|
|
23
|
-
*
|
|
24
|
-
* @module dsh-llm-codebuddy-power/prefs
|
|
25
|
-
*/
|
|
26
|
-
/** 本插件拥有的设置命名空间,与插件名一致。 */
|
|
13
|
+
/** 本插件的设置入口 id,与插件名一致。 */
|
|
27
14
|
const CODEBUDDY_SETTINGS_NAMESPACE = "llm-codebuddy-power";
|
|
28
15
|
/** 未覆盖任何一层时使用的偏好默认值。 */
|
|
29
16
|
const DEFAULT_CODEBUDDY_SETTINGS = {
|
|
@@ -33,7 +20,7 @@ window.__ModuleLoader__.load({
|
|
|
33
20
|
};
|
|
34
21
|
//#endregion
|
|
35
22
|
//#region \0dsh-css:D:\data\code\deepseek-harness\packages\my\dsh-llm-codebuddy-power\src\client\CodeBuddySection.module.css.mjs
|
|
36
|
-
const css$4 = ".-h11cq_section{flex-direction:column;gap:12px;
|
|
23
|
+
const css$4 = ".-h11cq_section{flex-direction:column;gap:12px;padding:8px 0;display:flex}.-h11cq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:18px;font-weight:600}.-h11cq_desc{color:var(--dsw-alias-label-secondary);margin:0;font-size:14px;line-height:22px}.-h11cq_muted{color:var(--dsw-alias-label-secondary);margin:0;font-size:14px}.-h11cq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:14px}.-h11cq_accountHeader{border-bottom:1px solid var(--dsw-alias-border-l2);flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:8px;padding-bottom:8px;display:flex}.-h11cq_splitButton{align-items:center;display:inline-flex}.-h11cq_splitMain{box-shadow:inset -1px 0 0 var(--dsw-alias-border-l3);border-right-width:0;border-top-right-radius:0;border-bottom-right-radius:0}.-h11cq_splitActionAnchor{display:inline-flex}.-h11cq_splitAction{border-top-left-radius:0;border-bottom-left-radius:0;padding:0 10px}.-h11cq_splitMain:focus-visible,.-h11cq_splitAction:focus-visible{outline-offset:-2px}.-h11cq_badges{flex-wrap:wrap;gap:8px;display:flex}.-h11cq_badge{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:16px;align-items:center;gap:6px;max-width:100%;min-height:32px;padding:0 4px 0 0;display:flex}.-h11cq_badgeInfo{align-self:stretch;align-items:center;min-width:0;padding-left:12px;display:flex}.-h11cq_badgeDragging{opacity:.4}.-h11cq_badgeDropBefore,.-h11cq_badgeDropAfter{position:relative}.-h11cq_badgeDropBefore:before,.-h11cq_badgeDropAfter:after{content:\"\";z-index:1;background:var(--dsw-alias-brand-primary);pointer-events:none;border-radius:1px;width:2px;position:absolute;top:0;bottom:0}.-h11cq_badgeDropBefore:before{left:-5px}.-h11cq_badgeDropAfter:after{right:-5px}.-h11cq_badgeInfoText{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;max-width:180px;font-size:13px;line-height:20px;overflow:hidden}.-h11cq_badge:not(:has(.-h11cq_badgeCheck)) .-h11cq_badgeInfo{padding-right:8px}.-h11cq_badgeActionAnchor{flex:none;display:inline-flex}.-h11cq_badgeAction{width:24px;height:24px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:12px;justify-content:center;align-items:center;padding:0;display:inline-flex}.-h11cq_badgeAction:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.-h11cq_badgeAction:disabled{cursor:default;opacity:.4}.-h11cq_badgeAction:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.-h11cq_badgeCheck{border:1px solid var(--dsw-alias-border-l3);width:20px;height:20px;color:var(--dsw-alias-label-primary-foreground);cursor:pointer;background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.-h11cq_badgeCheckOn{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-brand-primary)}.-h11cq_badgeCheck:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-h11cq_divider{background:var(--dsw-alias-border-l2);height:1px}.-h11cq_prefRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:8px 0;display:flex}.-h11cq_prefRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.-h11cq_prefTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.-h11cq_prefDesc{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:400;line-height:18px}.-h11cq_switch{box-sizing:border-box;background:var(--dsw-alias-border-l3);cursor:pointer;border:0;border-radius:10px;flex:none;width:36px;height:20px;padding:2px;position:relative}.-h11cq_switchOn{background:var(--dsw-alias-brand-primary)}.-h11cq_switch:disabled{cursor:default;opacity:.5}.-h11cq_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-h11cq_thumb{corner-shape:round;background:var(--dsw-alias-label-primary-foreground);border-radius:50%;width:16px;height:16px;transition:transform .12s;display:block}.-h11cq_switchOn .-h11cq_thumb{transform:translate(16px)}.-h11cq_prefInput{width:120px}";
|
|
37
24
|
const tagId$4 = "dsh-llm-codebuddy-power/CodeBuddySection.module.css";
|
|
38
25
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
|
|
39
26
|
const tag = document.createElement("style");
|
|
@@ -49,7 +36,6 @@ window.__ModuleLoader__.load({
|
|
|
49
36
|
"badgeActionAnchor": "-h11cq_badgeActionAnchor",
|
|
50
37
|
"badgeCheck": "-h11cq_badgeCheck",
|
|
51
38
|
"badgeCheckOn": "-h11cq_badgeCheckOn",
|
|
52
|
-
"badgeDefaultTag": "-h11cq_badgeDefaultTag",
|
|
53
39
|
"badgeDragging": "-h11cq_badgeDragging",
|
|
54
40
|
"badgeDropAfter": "-h11cq_badgeDropAfter",
|
|
55
41
|
"badgeDropBefore": "-h11cq_badgeDropBefore",
|
|
@@ -81,16 +67,16 @@ window.__ModuleLoader__.load({
|
|
|
81
67
|
* CodeBuddy 设置分区:多账号登录页。
|
|
82
68
|
*
|
|
83
69
|
* 展示全部已登录账号(每个账号一个徽章),在此发起浏览器登录以**追加**账号、
|
|
84
|
-
*
|
|
70
|
+
* 退出单个或选中的多个账号、拖拽排序;下方是两种登录状态下都渲染的
|
|
85
71
|
* 界面偏好行。退出是破坏性操作(会删除磁盘上的凭据),因此单个与批量都先弹确认框。
|
|
86
72
|
* 弹窗可见性由 shell 拥有,故此处不需要关闭控件。
|
|
87
73
|
*/
|
|
88
74
|
/** 客户端轮询已发起登录的间隔(毫秒)。 */
|
|
89
75
|
const POLL_INTERVAL_MS = 1500;
|
|
90
|
-
/**
|
|
76
|
+
/** 客户端等待登录完成的时长(毫秒),与宿主的 `LOGIN_TIMEOUT_MS` 对齐。 */
|
|
91
77
|
const POLL_DEADLINE_MS = 600 * 1e3;
|
|
92
78
|
/** 复制成功后图标保持对勾的时长(毫秒)。 */
|
|
93
|
-
const COPIED_FEEDBACK_MS = 1e3;
|
|
79
|
+
const COPIED_FEEDBACK_MS$1 = 1e3;
|
|
94
80
|
/**
|
|
95
81
|
* 解码 CodeBuddy 的 `departmentFullName`,它是 base64 编码的 UTF-8。
|
|
96
82
|
* 不是合法 base64 时回退为原始值。
|
|
@@ -134,24 +120,21 @@ window.__ModuleLoader__.load({
|
|
|
134
120
|
return e.clientX < rect.left + rect.width / 2 ? "before" : "after";
|
|
135
121
|
}
|
|
136
122
|
/**
|
|
137
|
-
* 一个账号徽章:整块信息区(昵称及其内边距)
|
|
123
|
+
* 一个账号徽章:整块信息区(昵称及其内边距)悬停看明细。
|
|
138
124
|
*
|
|
139
125
|
* 提示挂在整块信息区而不是只挂在昵称文字上:昵称常常很短,能触发提示的只有那几个
|
|
140
126
|
* 字;把锚点扩到这块区域的整个高度与左侧留白,徽章上除功能按钮外的地方都能唤起它。
|
|
141
127
|
* 不用"Tooltip 包住整个徽章、按钮上禁用"的写法 —— `Tooltip` 的 `disabled` 会直接
|
|
142
128
|
* 清空它的悬停/聚焦状态,从昵称移到按钮再移回来时提示不会再出现。
|
|
143
129
|
*
|
|
144
|
-
*
|
|
145
|
-
* "这是哪个账号、它是不是默认的"。唯一可点的例外是那个「默认」标记 —— 它标出默认
|
|
146
|
-
* 账号,自己也就是取消默认的入口。
|
|
130
|
+
* 徽章本身不承担任何管理动作:退出与排序都在顶部操作区,徽章只回答"这是哪个账号"。
|
|
147
131
|
*/
|
|
148
132
|
function AccountBadge(props) {
|
|
149
|
-
const { account,
|
|
133
|
+
const { account, multiSelect, checked, t, onToggleChecked, drag } = props;
|
|
150
134
|
const dragging = drag?.dragging ? ` ${CodeBuddySection_module_css_default.badgeDragging}` : "";
|
|
151
135
|
const marker = drag?.marker === "before" ? ` ${CodeBuddySection_module_css_default.badgeDropBefore}` : drag?.marker === "after" ? ` ${CodeBuddySection_module_css_default.badgeDropAfter}` : "";
|
|
152
136
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
153
137
|
className: `${CodeBuddySection_module_css_default.badge}${dragging}${marker}`,
|
|
154
|
-
"data-default": isDefault ? "" : void 0,
|
|
155
138
|
draggable: drag !== void 0,
|
|
156
139
|
onDragStart: drag === void 0 ? void 0 : (e) => {
|
|
157
140
|
e.dataTransfer.effectAllowed = "move";
|
|
@@ -168,43 +151,27 @@ window.__ModuleLoader__.load({
|
|
|
168
151
|
e.preventDefault();
|
|
169
152
|
drag.drop(badgeHalf(e));
|
|
170
153
|
},
|
|
171
|
-
children: [
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
154
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
155
|
+
label: accountDetail(account, t),
|
|
156
|
+
side: "top",
|
|
157
|
+
delayMs: 300,
|
|
158
|
+
maxWidth: 320,
|
|
159
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
160
|
+
className: CodeBuddySection_module_css_default.badgeInfo,
|
|
177
161
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
178
|
-
className: CodeBuddySection_module_css_default.
|
|
179
|
-
children:
|
|
180
|
-
className: CodeBuddySection_module_css_default.badgeInfoText,
|
|
181
|
-
children: account.nickname
|
|
182
|
-
})
|
|
162
|
+
className: CodeBuddySection_module_css_default.badgeInfoText,
|
|
163
|
+
children: account.nickname
|
|
183
164
|
})
|
|
184
|
-
}),
|
|
185
|
-
isDefault && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
186
|
-
label: t("clearDefault"),
|
|
187
|
-
side: "top",
|
|
188
|
-
delayMs: 300,
|
|
189
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
190
|
-
type: "button",
|
|
191
|
-
className: CodeBuddySection_module_css_default.badgeDefaultTag,
|
|
192
|
-
"aria-pressed": true,
|
|
193
|
-
"aria-label": `${t("clearDefault")}: ${account.nickname}`,
|
|
194
|
-
onClick: onClearDefault,
|
|
195
|
-
children: t("defaultTag")
|
|
196
|
-
})
|
|
197
|
-
}),
|
|
198
|
-
multiSelect && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
199
|
-
type: "button",
|
|
200
|
-
role: "checkbox",
|
|
201
|
-
"aria-checked": checked,
|
|
202
|
-
"aria-label": `${t("selectAccount")}: ${account.nickname}`,
|
|
203
|
-
className: `${CodeBuddySection_module_css_default.badgeCheck} ${checked ? CodeBuddySection_module_css_default.badgeCheckOn : ""}`,
|
|
204
|
-
onClick: onToggleChecked,
|
|
205
|
-
children: checked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 14 })
|
|
206
165
|
})
|
|
207
|
-
|
|
166
|
+
}), multiSelect && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
167
|
+
type: "button",
|
|
168
|
+
role: "checkbox",
|
|
169
|
+
"aria-checked": checked,
|
|
170
|
+
"aria-label": `${t("selectAccount")}: ${account.nickname}`,
|
|
171
|
+
className: `${CodeBuddySection_module_css_default.badgeCheck} ${checked ? CodeBuddySection_module_css_default.badgeCheckOn : ""}`,
|
|
172
|
+
onClick: onToggleChecked,
|
|
173
|
+
children: checked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 })
|
|
174
|
+
})]
|
|
208
175
|
});
|
|
209
176
|
}
|
|
210
177
|
/**
|
|
@@ -213,11 +180,10 @@ window.__ModuleLoader__.load({
|
|
|
213
180
|
* @returns 分区的元素树。
|
|
214
181
|
*/
|
|
215
182
|
function CodeBuddySection(props) {
|
|
216
|
-
const { t, useStore, usePrefs, refreshAccounts, startLogin, copyLoginLink, cancelLogin, pollLogin, logoutAccounts, reorderAccounts,
|
|
183
|
+
const { t, useStore, usePrefs, refreshAccounts, startLogin, resumeLogin, copyLoginLink, cancelLogin, pollLogin, logoutAccounts, reorderAccounts, setPref, actions } = props;
|
|
217
184
|
const phase = useStore((s) => s.phase);
|
|
218
185
|
const error = useStore((s) => s.error);
|
|
219
186
|
const accounts = useStore((s) => s.accounts);
|
|
220
|
-
const defaultUid = useStore((s) => s.defaultUid);
|
|
221
187
|
const loginState = useStore((s) => s.loginState);
|
|
222
188
|
const prefs = usePrefs((value) => value);
|
|
223
189
|
const [dangerText, setDangerText] = (0, react.useState)(() => String(prefs.dangerPct));
|
|
@@ -227,39 +193,54 @@ window.__ModuleLoader__.load({
|
|
|
227
193
|
const [checked, setChecked] = (0, react.useState)([]);
|
|
228
194
|
/** 待确认的退出目标;null 表示没有待确认的退出。 */
|
|
229
195
|
const [pendingLogout, setPendingLogout] = (0, react.useState)(null);
|
|
230
|
-
const halted = (0, react.useRef)(false);
|
|
231
|
-
/** 卸载后为 true;登录轮询就此停止,而不是触碰状态。 */
|
|
232
|
-
const isHalted = () => halted.current;
|
|
233
196
|
(0, react.useEffect)(() => {
|
|
234
197
|
refreshAccounts();
|
|
235
|
-
|
|
198
|
+
resumeLogin();
|
|
199
|
+
}, [refreshAccounts, resumeLogin]);
|
|
236
200
|
(0, react.useEffect)(() => {
|
|
237
201
|
if (loginState === null) return;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
202
|
+
const run = {
|
|
203
|
+
stopped: false,
|
|
204
|
+
abort: new AbortController()
|
|
205
|
+
};
|
|
206
|
+
/** 本次跑次是否已收尾(完成、超时、取消或卸载)。 */
|
|
207
|
+
const isStopped = () => run.stopped;
|
|
208
|
+
/**
|
|
209
|
+
* 收尾本次跑次:停掉轮询与截止定时器,并中止在飞的那次请求。
|
|
210
|
+
*
|
|
211
|
+
* 中止是必须的:宿主侧 `pollLogin` 现在立即作答,但**请求已经发出去**这件事
|
|
212
|
+
* 与定时器无关 —— 只清定时器,那一次请求仍占着连接,而浏览器对同一源的并发连接
|
|
213
|
+
* 数有限,积压后会把账号、用量等其余请求一起挤成待处理。
|
|
214
|
+
*/
|
|
215
|
+
const stop = () => {
|
|
216
|
+
run.stopped = true;
|
|
217
|
+
if (run.deadline !== void 0) window.clearTimeout(run.deadline);
|
|
218
|
+
if (run.poll !== void 0) window.clearTimeout(run.poll);
|
|
219
|
+
run.abort.abort();
|
|
220
|
+
};
|
|
221
|
+
run.deadline = window.setTimeout(() => {
|
|
222
|
+
if (isStopped()) return;
|
|
223
|
+
stop();
|
|
224
|
+
actions.setLoginState(null);
|
|
225
|
+
actions.fail(t("timeout"));
|
|
226
|
+
}, Math.max(0, loginState.startedAt + POLL_DEADLINE_MS - Date.now()));
|
|
241
227
|
const tick = async () => {
|
|
242
|
-
if (
|
|
228
|
+
if (isStopped()) return;
|
|
243
229
|
let done = false;
|
|
244
230
|
try {
|
|
245
|
-
done = await pollLogin(state);
|
|
231
|
+
done = await pollLogin(loginState.state, run.abort.signal);
|
|
246
232
|
} catch {
|
|
247
233
|
done = false;
|
|
248
234
|
}
|
|
249
|
-
if (
|
|
250
|
-
if (done)
|
|
251
|
-
|
|
252
|
-
actions.setLoginState(null);
|
|
253
|
-
actions.fail(t("timeout"));
|
|
235
|
+
if (isStopped()) return;
|
|
236
|
+
if (done) {
|
|
237
|
+
stop();
|
|
254
238
|
return;
|
|
255
239
|
}
|
|
256
|
-
|
|
240
|
+
run.poll = window.setTimeout(tick, POLL_INTERVAL_MS);
|
|
257
241
|
};
|
|
258
242
|
tick();
|
|
259
|
-
return
|
|
260
|
-
halted.current = true;
|
|
261
|
-
if (timer !== void 0) window.clearTimeout(timer);
|
|
262
|
-
};
|
|
243
|
+
return stop;
|
|
263
244
|
}, [
|
|
264
245
|
loginState,
|
|
265
246
|
pollLogin,
|
|
@@ -270,16 +251,17 @@ window.__ModuleLoader__.load({
|
|
|
270
251
|
startLogin();
|
|
271
252
|
}, [startLogin]);
|
|
272
253
|
/**
|
|
273
|
-
*
|
|
254
|
+
* 放弃这次登录:先清掉本地的握手状态,再通知宿主中止。
|
|
274
255
|
*
|
|
275
|
-
* 顺序不能反 ——
|
|
276
|
-
*
|
|
256
|
+
* 顺序不能反 —— 取消对用户是即刻的,而 `cancelLogin` 是一次宿主调用,等它返回才
|
|
257
|
+
* 收回按钮会让取消显得没反应。先清状态是安全的:那一次状态变更会让上面的 effect
|
|
258
|
+
* 收尾,正在飞的那次 `pollLogin` 返回后就此停手,不会再排下一次轮询。
|
|
277
259
|
*/
|
|
278
260
|
const onCancelLogin = (0, react.useCallback)(() => {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
261
|
+
const pending = loginState;
|
|
262
|
+
if (pending === null) return;
|
|
263
|
+
actions.setLoginState(null);
|
|
264
|
+
cancelLogin(pending.state);
|
|
283
265
|
}, [
|
|
284
266
|
loginState,
|
|
285
267
|
cancelLogin,
|
|
@@ -298,13 +280,9 @@ window.__ModuleLoader__.load({
|
|
|
298
280
|
copiedTimer.current = window.setTimeout(() => {
|
|
299
281
|
copiedTimer.current = void 0;
|
|
300
282
|
setCopied(false);
|
|
301
|
-
}, COPIED_FEEDBACK_MS);
|
|
283
|
+
}, COPIED_FEEDBACK_MS$1);
|
|
302
284
|
});
|
|
303
285
|
}, [copied, copyLoginLink]);
|
|
304
|
-
const [defaultMenuOpen, setDefaultMenuOpen] = (0, react.useState)(false);
|
|
305
|
-
const onClearDefault = (0, react.useCallback)(() => {
|
|
306
|
-
setDefault(null);
|
|
307
|
-
}, [setDefault]);
|
|
308
286
|
const onToggleChecked = (0, react.useCallback)((uid) => {
|
|
309
287
|
setChecked((current) => current.includes(uid) ? current.filter((item) => item !== uid) : [...current, uid]);
|
|
310
288
|
}, []);
|
|
@@ -348,10 +326,7 @@ window.__ModuleLoader__.load({
|
|
|
348
326
|
})
|
|
349
327
|
});
|
|
350
328
|
const pendingCount = pendingLogout?.length ?? 0;
|
|
351
|
-
|
|
352
|
-
id: account.uid,
|
|
353
|
-
label: account.nickname
|
|
354
|
-
}));
|
|
329
|
+
if (props.view === "summary") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: t("intro") });
|
|
355
330
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
356
331
|
className: CodeBuddySection_module_css_default.section,
|
|
357
332
|
children: [
|
|
@@ -390,37 +365,12 @@ window.__ModuleLoader__.load({
|
|
|
390
365
|
size: "md",
|
|
391
366
|
className: CodeBuddySection_module_css_default.splitAction,
|
|
392
367
|
"aria-label": loginState === null ? copied ? t("copied") : t("copyLoginLink") : t("cancelLogin"),
|
|
393
|
-
icon: loginState === null ? copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
368
|
+
icon: loginState === null ? copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 }),
|
|
394
369
|
onClick: loginState === null ? onCopyLoginLink : onCancelLogin
|
|
395
370
|
})
|
|
396
371
|
})
|
|
397
372
|
})]
|
|
398
373
|
}),
|
|
399
|
-
accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
400
|
-
open: defaultMenuOpen,
|
|
401
|
-
portal: true,
|
|
402
|
-
align: "start",
|
|
403
|
-
selectedId: defaultUid ?? void 0,
|
|
404
|
-
items: defaultItems,
|
|
405
|
-
onClose: () => {
|
|
406
|
-
setDefaultMenuOpen(false);
|
|
407
|
-
},
|
|
408
|
-
onSelect: (uid) => {
|
|
409
|
-
setDefaultMenuOpen(false);
|
|
410
|
-
if (uid === defaultUid) return;
|
|
411
|
-
setDefault(uid);
|
|
412
|
-
},
|
|
413
|
-
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
414
|
-
variant: "outline",
|
|
415
|
-
size: "md",
|
|
416
|
-
"aria-haspopup": "menu",
|
|
417
|
-
"aria-expanded": defaultMenuOpen,
|
|
418
|
-
onClick: () => {
|
|
419
|
-
setDefaultMenuOpen((current) => !current);
|
|
420
|
-
},
|
|
421
|
-
children: t("chooseDefault")
|
|
422
|
-
})
|
|
423
|
-
}),
|
|
424
374
|
accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
425
375
|
variant: "outline",
|
|
426
376
|
size: "md",
|
|
@@ -445,7 +395,7 @@ window.__ModuleLoader__.load({
|
|
|
445
395
|
onClick: () => {
|
|
446
396
|
setPendingLogout([...checked]);
|
|
447
397
|
},
|
|
448
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
398
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
|
|
449
399
|
})
|
|
450
400
|
})
|
|
451
401
|
})
|
|
@@ -458,11 +408,9 @@ window.__ModuleLoader__.load({
|
|
|
458
408
|
className: CodeBuddySection_module_css_default.badges,
|
|
459
409
|
children: accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountBadge, {
|
|
460
410
|
account,
|
|
461
|
-
isDefault: account.uid === defaultUid,
|
|
462
411
|
multiSelect,
|
|
463
412
|
checked: checked.includes(account.uid),
|
|
464
413
|
t,
|
|
465
|
-
onClearDefault,
|
|
466
414
|
onToggleChecked: () => {
|
|
467
415
|
onToggleChecked(account.uid);
|
|
468
416
|
},
|
|
@@ -524,6 +472,9 @@ window.__ModuleLoader__.load({
|
|
|
524
472
|
* 三行界面偏好,单独抽出以便与账号区解耦 —— 它们与登录状态无关。两个布尔行是
|
|
525
473
|
* 开关按钮(role="switch")而非下拉框:开关一次点击即可翻转,与文件浏览器的
|
|
526
474
|
* 显示隐藏开关一致。
|
|
475
|
+
*
|
|
476
|
+
* 两个用量项相邻:余量告警百分比只对圆环的填充色起作用,把它隔在画图工具之后会让
|
|
477
|
+
* "圆环显示不显示"与"圆环几时变红"分成两处去找。
|
|
527
478
|
*/
|
|
528
479
|
function UsagePrefRows(props) {
|
|
529
480
|
const { t, prefs, dangerText, setDangerText, setPref } = props;
|
|
@@ -551,29 +502,6 @@ window.__ModuleLoader__.load({
|
|
|
551
502
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeBuddySection_module_css_default.thumb })
|
|
552
503
|
})]
|
|
553
504
|
}),
|
|
554
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
555
|
-
className: CodeBuddySection_module_css_default.prefRow,
|
|
556
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
557
|
-
className: CodeBuddySection_module_css_default.prefRowText,
|
|
558
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
559
|
-
className: CodeBuddySection_module_css_default.prefTitle,
|
|
560
|
-
children: t("drawToolMinimal")
|
|
561
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
562
|
-
className: CodeBuddySection_module_css_default.prefDesc,
|
|
563
|
-
children: t("drawToolMinimalDesc")
|
|
564
|
-
})]
|
|
565
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
566
|
-
type: "button",
|
|
567
|
-
role: "switch",
|
|
568
|
-
"aria-checked": prefs.drawToolInMinimal,
|
|
569
|
-
"aria-label": t("drawToolMinimal"),
|
|
570
|
-
className: `${CodeBuddySection_module_css_default.switch} ${prefs.drawToolInMinimal ? CodeBuddySection_module_css_default.switchOn : ""}`,
|
|
571
|
-
onClick: () => {
|
|
572
|
-
setPref("drawToolInMinimal", !prefs.drawToolInMinimal);
|
|
573
|
-
},
|
|
574
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeBuddySection_module_css_default.thumb })
|
|
575
|
-
})]
|
|
576
|
-
}),
|
|
577
505
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
578
506
|
className: CodeBuddySection_module_css_default.prefRow,
|
|
579
507
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -604,12 +532,35 @@ window.__ModuleLoader__.load({
|
|
|
604
532
|
setPref("dangerPct", next);
|
|
605
533
|
}
|
|
606
534
|
})]
|
|
535
|
+
}),
|
|
536
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
537
|
+
className: CodeBuddySection_module_css_default.prefRow,
|
|
538
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
539
|
+
className: CodeBuddySection_module_css_default.prefRowText,
|
|
540
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
541
|
+
className: CodeBuddySection_module_css_default.prefTitle,
|
|
542
|
+
children: t("drawToolMinimal")
|
|
543
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
544
|
+
className: CodeBuddySection_module_css_default.prefDesc,
|
|
545
|
+
children: t("drawToolMinimalDesc")
|
|
546
|
+
})]
|
|
547
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
548
|
+
type: "button",
|
|
549
|
+
role: "switch",
|
|
550
|
+
"aria-checked": prefs.drawToolInMinimal,
|
|
551
|
+
"aria-label": t("drawToolMinimal"),
|
|
552
|
+
className: `${CodeBuddySection_module_css_default.switch} ${prefs.drawToolInMinimal ? CodeBuddySection_module_css_default.switchOn : ""}`,
|
|
553
|
+
onClick: () => {
|
|
554
|
+
setPref("drawToolInMinimal", !prefs.drawToolInMinimal);
|
|
555
|
+
},
|
|
556
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: CodeBuddySection_module_css_default.thumb })
|
|
557
|
+
})]
|
|
607
558
|
})
|
|
608
559
|
] });
|
|
609
560
|
}
|
|
610
561
|
//#endregion
|
|
611
562
|
//#region \0dsh-css:D:\data\code\deepseek-harness\packages\my\dsh-llm-codebuddy-power\src\client\AccountSwitcher.module.css.mjs
|
|
612
|
-
const css$3 = "._7gEqNa_root{flex:none;align-items:center;gap:4px;display:inline-flex}._7gEqNa_ringAnchor{align-items:center;display:inline-flex}._7gEqNa_trigger{box-sizing:border-box;min-width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));max-width:96px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0 6px;font-size:12px;line-height:1;display:inline-flex;overflow:hidden}._7gEqNa_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}._7gEqNa_trigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}
|
|
563
|
+
const css$3 = "._7gEqNa_root{flex:none;align-items:center;gap:4px;display:inline-flex}._7gEqNa_ringAnchor{align-items:center;display:inline-flex}._7gEqNa_trigger{box-sizing:border-box;min-width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));max-width:96px;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0 6px;font-size:12px;line-height:1;display:inline-flex;overflow:hidden}._7gEqNa_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}._7gEqNa_trigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
613
564
|
const tagId$3 = "dsh-llm-codebuddy-power/AccountSwitcher.module.css";
|
|
614
565
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
615
566
|
const tag = document.createElement("style");
|
|
@@ -619,7 +570,6 @@ window.__ModuleLoader__.load({
|
|
|
619
570
|
document.head.appendChild(tag);
|
|
620
571
|
}
|
|
621
572
|
var AccountSwitcher_module_css_default = {
|
|
622
|
-
"menuDefault": "_7gEqNa_menuDefault",
|
|
623
573
|
"ringAnchor": "_7gEqNa_ringAnchor",
|
|
624
574
|
"root": "_7gEqNa_root",
|
|
625
575
|
"trigger": "_7gEqNa_trigger"
|
|
@@ -676,6 +626,52 @@ window.__ModuleLoader__.load({
|
|
|
676
626
|
});
|
|
677
627
|
}
|
|
678
628
|
/**
|
|
629
|
+
* 把剩余赠送额度压成圆环中心那点宽度放得下的写法(`999`、`1.23k`、`12.3k`、`123k`、`1.23m`)。
|
|
630
|
+
*
|
|
631
|
+
* 单位内保留三位有效数字,而不是只换算能整除的值:额度常是 12000、15000 这类数,
|
|
632
|
+
* 只换算整除的会让同一处时而 `12000` 时而 `1.2k`。
|
|
633
|
+
*
|
|
634
|
+
* 先按量级定档、再只取整一次:每档都取整会把误差累积起来,`1_234_567` 会在 `k` 档
|
|
635
|
+
* 先被写成 `1235`、再进位成 `1.24m`,而它本应是 `1.23m`。定档只看量级,取整只做一次。
|
|
636
|
+
*
|
|
637
|
+
* 取整仍可能把本档推到一千(`999_600` → `1000`),此时再进一档,否则会写出 `1000k`
|
|
638
|
+
* 与相邻的 `1m` 并存成两种记法。
|
|
639
|
+
* @param value - 剩余赠送额度,非负。
|
|
640
|
+
* @returns 最多三位有效数字、带 `k`/`m`/`g` 单位的紧凑写法。
|
|
641
|
+
*/
|
|
642
|
+
function formatCompact(value) {
|
|
643
|
+
const units = [
|
|
644
|
+
"",
|
|
645
|
+
"k",
|
|
646
|
+
"m",
|
|
647
|
+
"g"
|
|
648
|
+
];
|
|
649
|
+
/** 按三位有效数字取整:大于等于 100 取整,大于等于 10 保留一位,其余保留两位。 */
|
|
650
|
+
const round3 = (scaled) => {
|
|
651
|
+
const digits = scaled >= 100 ? 0 : scaled >= 10 ? 1 : 2;
|
|
652
|
+
const rounded = Math.round(scaled * 10 ** digits) / 10 ** digits;
|
|
653
|
+
return {
|
|
654
|
+
text: rounded.toLocaleString(void 0, {
|
|
655
|
+
maximumFractionDigits: digits,
|
|
656
|
+
useGrouping: false
|
|
657
|
+
}),
|
|
658
|
+
carries: rounded >= 1e3
|
|
659
|
+
};
|
|
660
|
+
};
|
|
661
|
+
let scaled = value;
|
|
662
|
+
let unit = 0;
|
|
663
|
+
while (scaled >= 1e3 && unit < units.length - 1) {
|
|
664
|
+
scaled /= 1e3;
|
|
665
|
+
unit += 1;
|
|
666
|
+
}
|
|
667
|
+
let result = round3(scaled);
|
|
668
|
+
if (result.carries && unit < units.length - 1) {
|
|
669
|
+
unit += 1;
|
|
670
|
+
result = round3(scaled / 1e3);
|
|
671
|
+
}
|
|
672
|
+
return `${result.text}${units[unit]}`;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
679
675
|
* 构建圆环提示:合并后的已用/总量与百分比,其后是主池数值与它的重置时刻、赠送池,
|
|
680
676
|
* 最后是最近到期的赠送窗口明细。
|
|
681
677
|
*
|
|
@@ -702,7 +698,6 @@ window.__ModuleLoader__.load({
|
|
|
702
698
|
function AccountSwitcher(props) {
|
|
703
699
|
const { t, usePrefs, fetchAccounts, fetchSessionAccount, activate, fetchUsage } = props;
|
|
704
700
|
const [accounts, setAccounts] = (0, react.useState)([]);
|
|
705
|
-
const [defaultUid, setDefaultUid] = (0, react.useState)(null);
|
|
706
701
|
const prefs = usePrefs((value) => value);
|
|
707
702
|
/** 该会话此刻生效的账号 uid;未读到时为 null。 */
|
|
708
703
|
const [activeUid, setActiveUid] = (0, react.useState)(null);
|
|
@@ -725,7 +720,6 @@ window.__ModuleLoader__.load({
|
|
|
725
720
|
fetchAccounts().then((value) => {
|
|
726
721
|
if (stopped || value === null) return;
|
|
727
722
|
setAccounts(value.accounts);
|
|
728
|
-
setDefaultUid(value.defaultUid);
|
|
729
723
|
});
|
|
730
724
|
fetchSessionAccount().then((uid) => {
|
|
731
725
|
if (!stopped) setActiveUid(uid);
|
|
@@ -749,22 +743,21 @@ window.__ModuleLoader__.load({
|
|
|
749
743
|
prefs.showUsage
|
|
750
744
|
]);
|
|
751
745
|
if (accounts.length === 0) return null;
|
|
752
|
-
const active = accounts.find((account) => account.uid === activeUid) ?? accounts
|
|
746
|
+
const active = accounts.find((account) => account.uid === activeUid) ?? accounts[0];
|
|
753
747
|
if (active === void 0) return null;
|
|
754
748
|
const label = `${t("switchAccount")}: ${active.nickname}`;
|
|
755
749
|
const limit = (usage?.main?.limit ?? 0) + (usage?.gift?.limit ?? 0);
|
|
756
750
|
const used = (usage?.main?.used ?? 0) + (usage?.gift?.used ?? 0);
|
|
757
751
|
const pct = limit > 0 ? Math.min(Math.max(used / limit * 100, 0), 100) : void 0;
|
|
752
|
+
const giftLeft = Math.max((usage?.gift?.limit ?? 0) - (usage?.gift?.used ?? 0), 0);
|
|
753
|
+
const ringText = giftLeft > 0 ? formatCompact(giftLeft) : pct?.toFixed(2);
|
|
758
754
|
const tip = usage !== null && pct !== void 0 ? ringTooltip(usage, {
|
|
759
755
|
used,
|
|
760
756
|
limit
|
|
761
757
|
}, pct, t) : null;
|
|
762
758
|
const items = accounts.map((account) => ({
|
|
763
759
|
id: account.uid,
|
|
764
|
-
label: account.
|
|
765
|
-
className: AccountSwitcher_module_css_default.menuDefault,
|
|
766
|
-
children: t("defaultTag")
|
|
767
|
-
})] }) : account.nickname
|
|
760
|
+
label: account.nickname
|
|
768
761
|
}));
|
|
769
762
|
const size = RING_SIZE;
|
|
770
763
|
const stroke = RING_STROKE;
|
|
@@ -813,7 +806,7 @@ window.__ModuleLoader__.load({
|
|
|
813
806
|
fill: "var(--dsw-alias-label-primary)",
|
|
814
807
|
fontSize: RING_FONT_SIZE,
|
|
815
808
|
fontWeight: 600,
|
|
816
|
-
children:
|
|
809
|
+
children: ringText
|
|
817
810
|
})
|
|
818
811
|
]
|
|
819
812
|
})
|
|
@@ -837,7 +830,6 @@ window.__ModuleLoader__.load({
|
|
|
837
830
|
fetchAccounts().then((value) => {
|
|
838
831
|
if (value === null) return;
|
|
839
832
|
setAccounts(value.accounts);
|
|
840
|
-
setDefaultUid(value.defaultUid);
|
|
841
833
|
});
|
|
842
834
|
return;
|
|
843
835
|
}
|
|
@@ -916,7 +908,7 @@ window.__ModuleLoader__.load({
|
|
|
916
908
|
}
|
|
917
909
|
//#endregion
|
|
918
910
|
//#region \0dsh-css:D:\data\code\deepseek-harness\packages\my\dsh-llm-codebuddy-power\src\client\ModelPanel.module.css.mjs
|
|
919
|
-
const css$2 = ".pAq4ya_root{flex:none;display:inline-flex;position:relative}.pAq4ya_trigger{min-width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:4px;padding:6px;display:inline-flex}.pAq4ya_rate{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);font-size:12px}.pAq4ya_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.pAq4ya_trigger[data-inactive] svg{opacity:.36}.pAq4ya_trigger[data-inactive]:hover svg{opacity:.6}.pAq4ya_panel{z-index:1100;box-sizing:border-box;visibility:hidden
|
|
911
|
+
const css$2 = ".pAq4ya_root{flex:none;display:inline-flex;position:relative}.pAq4ya_trigger{min-width:calc(28px + var(--dsh-content-font-delta,0px));height:calc(28px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;gap:4px;padding:6px;display:inline-flex}.pAq4ya_rate{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);font-size:12px}.pAq4ya_trigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.pAq4ya_trigger[data-inactive] svg{opacity:.36}.pAq4ya_trigger[data-inactive]:hover svg{opacity:.6}.pAq4ya_panel{z-index:1100;box-sizing:border-box;visibility:hidden;--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:min(360px,100vw - 24px);max-height:min(560px,70vh);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border:0;flex-direction:column;gap:8px;padding:12px;font-size:13px;line-height:20px;display:flex;position:fixed;overflow:hidden}.pAq4ya_panel[data-positioned]{visibility:visible}.pAq4ya_header{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:baseline;gap:8px;padding-bottom:6px;display:flex}.pAq4ya_headerTitle{color:var(--dsw-alias-label-primary);font-weight:600}.pAq4ya_error{color:var(--dsw-alias-state-error-primary);font-size:12px}.pAq4ya_list{flex-direction:column;gap:2px;min-height:0;display:flex;overflow-y:auto}.pAq4ya_row{border-radius:8px;flex-direction:column;gap:2px;padding:6px 8px;display:flex}.pAq4ya_row:hover,.pAq4ya_rowSelected{background:var(--dsw-alias-interactive-bg-hover)}.pAq4ya_rowMain{text-align:left;width:100%;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border:0;flex-wrap:wrap;align-items:flex-start;gap:6px;padding:0;display:flex}.pAq4ya_rowName{white-space:nowrap;flex:none;font-weight:500}.pAq4ya_tag{border:.5px solid;border-radius:4px;flex:none;padding:0 5px;font-size:11px;line-height:16px}.pAq4ya_tagTier{color:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-border-l3)}.pAq4ya_rowTail{flex:none;align-items:baseline;gap:4px;margin-left:auto;display:inline-flex}.pAq4ya_credits{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.pAq4ya_creditsStruck{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;text-decoration:line-through}.pAq4ya_discounted{color:var(--dsw-alias-brand-primary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.pAq4ya_check{color:var(--dsw-alias-label-primary);flex:0 0 16px;place-items:center;display:grid}.pAq4ya_empty{text-align:center;color:var(--dsw-alias-label-tertiary);padding:16px 0}.pAq4ya_tip{z-index:1099;box-sizing:border-box;--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);max-width:calc(100vw - 16px);max-height:min(360px,70vh);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border:0;flex-direction:column;font-size:12px;line-height:18px;display:flex;position:fixed}.pAq4ya_tipScroll{overscroll-behavior:contain;flex-direction:column;gap:6px;min-height:0;padding:10px 12px;display:flex;overflow-y:auto}.pAq4ya_tipName{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.pAq4ya_tipDesc{color:var(--dsw-alias-label-secondary)}.pAq4ya_tipFeatures,.pAq4ya_tipSpend,.pAq4ya_tipPromo{align-items:baseline;gap:8px;display:flex}.pAq4ya_tipLabel{color:var(--dsw-alias-label-tertiary);flex:none}.pAq4ya_tipVal{text-align:right;margin-left:auto}.pAq4ya_tipCreditsStruck{color:var(--dsw-alias-label-tertiary);text-decoration:line-through}.pAq4ya_tipDiscounted{color:var(--dsw-alias-brand-primary);margin-left:4px}.pAq4ya_tipTier{color:var(--dsw-alias-label-secondary)}.pAq4ya_tipDivider{background:var(--dsw-alias-border-l2);height:.5px}.pAq4ya_tipCaps{color:var(--dsw-alias-label-secondary);align-items:center;gap:8px;display:flex}.pAq4ya_tipInput{border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);min-width:0;height:24px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:5px;flex:1;padding:0 6px;font-size:12px}.pAq4ya_tipInput:focus-visible{outline:1.5px solid var(--dsw-alias-brand-primary);outline-offset:1px}.pAq4ya_tipEffort{border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);max-width:100%;height:24px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;border-radius:5px;align-items:center;gap:4px;padding:0 6px 0 8px;font-size:12px;display:inline-flex}.pAq4ya_tipEffort:hover{background:var(--dsw-alias-interactive-bg-hover)}.pAq4ya_tipEffortMenu{min-width:0;margin-left:auto}.pAq4ya_tipEffortValue{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.pAq4ya_tipEffortChevron{color:var(--dsw-alias-label-tertiary);flex:none}.pAq4ya_tipValue{min-width:0;color:var(--dsw-alias-label-primary);font:inherit;flex:1;font-size:12px;line-height:20px}.pAq4ya_tipActions{justify-content:flex-end;gap:8px;display:flex}.pAq4ya_tipSave{background:var(--dsw-alias-button-primary-fill);height:28px;color:var(--dsw-alias-label-primary-foreground);cursor:pointer;font:inherit;border:0;border-radius:14px;padding:0 12px;font-size:12px;line-height:18px}.pAq4ya_tipSave:disabled{opacity:.4;cursor:not-allowed}.pAq4ya_tipSave:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.pAq4ya_tipAction{border:.5px solid var(--dsw-alias-border-l3);height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;background:0 0;border-radius:14px;padding:0 12px;font-size:12px;line-height:18px}.pAq4ya_tipAction:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.pAq4ya_tipLink{color:var(--dsw-alias-link);cursor:pointer;font:inherit;background:0 0;border:0;align-self:flex-start;padding:0;font-size:12px;line-height:18px}.pAq4ya_tipLink:hover{text-decoration:underline}.pAq4ya_tipLink:focus-visible{outline:1.5px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:3px}.pAq4ya_tipLinkChevron{margin-left:2px}@media (hover:none){.pAq4ya_row{padding:10px 8px}.pAq4ya_tipAction,.pAq4ya_tipSave{border-radius:18px;height:36px;padding:0 16px}.pAq4ya_tipLink{align-items:center;min-height:28px;display:inline-flex}.pAq4ya_tipInput{height:32px;font-size:14px}.pAq4ya_tipCaps{gap:10px}}";
|
|
920
912
|
const tagId$2 = "dsh-llm-codebuddy-power/ModelPanel.module.css";
|
|
921
913
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
922
914
|
const tag = document.createElement("style");
|
|
@@ -965,6 +957,7 @@ window.__ModuleLoader__.load({
|
|
|
965
957
|
"tipName": "pAq4ya_tipName",
|
|
966
958
|
"tipPromo": "pAq4ya_tipPromo",
|
|
967
959
|
"tipSave": "pAq4ya_tipSave",
|
|
960
|
+
"tipScroll": "pAq4ya_tipScroll",
|
|
968
961
|
"tipSpend": "pAq4ya_tipSpend",
|
|
969
962
|
"tipTier": "pAq4ya_tipTier",
|
|
970
963
|
"tipVal": "pAq4ya_tipVal",
|
|
@@ -1735,7 +1728,7 @@ window.__ModuleLoader__.load({
|
|
|
1735
1728
|
})]
|
|
1736
1729
|
})
|
|
1737
1730
|
}),
|
|
1738
|
-
state.open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
1731
|
+
state.open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
|
|
1739
1732
|
ref: panelRef,
|
|
1740
1733
|
className: ModelPanel_module_css_default.panel,
|
|
1741
1734
|
style: panelStyle,
|
|
@@ -1872,7 +1865,7 @@ window.__ModuleLoader__.load({
|
|
|
1872
1865
|
const hasMidSection = row.credits !== void 0 && row.credits.length > 0 || promotionText !== void 0 || promotionAction !== void 0;
|
|
1873
1866
|
const tipDiscounted = row.promotion?.discountedCredits;
|
|
1874
1867
|
const tipStrikeOriginal = tipDiscounted !== void 0 && row.promotion?.displayMode !== "replace";
|
|
1875
|
-
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1868
|
+
return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
|
|
1876
1869
|
ref: tipRef,
|
|
1877
1870
|
className: ModelPanel_module_css_default.tip,
|
|
1878
1871
|
role: "tooltip",
|
|
@@ -1881,206 +1874,209 @@ window.__ModuleLoader__.load({
|
|
|
1881
1874
|
top: tip.top,
|
|
1882
1875
|
width: tip.width
|
|
1883
1876
|
},
|
|
1884
|
-
children:
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
className: ModelPanel_module_css_default.
|
|
1897
|
-
children:
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
className: ModelPanel_module_css_default.tipLinkChevron,
|
|
1915
|
-
"aria-hidden": "true",
|
|
1916
|
-
children: "›"
|
|
1917
|
-
})]
|
|
1918
|
-
}),
|
|
1919
|
-
hasMidSection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: ModelPanel_module_css_default.tipDivider }),
|
|
1920
|
-
row.credits !== void 0 && row.credits.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1921
|
-
className: ModelPanel_module_css_default.tipSpend,
|
|
1922
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1923
|
-
className: ModelPanel_module_css_default.tipLabel,
|
|
1924
|
-
children: t("modelPanelSpendRate")
|
|
1925
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1926
|
-
className: ModelPanel_module_css_default.tipVal,
|
|
1927
|
-
children: [
|
|
1928
|
-
tipDiscounted === void 0 && row.credits,
|
|
1929
|
-
tipStrikeOriginal && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1930
|
-
className: ModelPanel_module_css_default.tipCreditsStruck,
|
|
1931
|
-
children: row.credits
|
|
1932
|
-
}),
|
|
1933
|
-
tipDiscounted !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1934
|
-
className: ModelPanel_module_css_default.tipDiscounted,
|
|
1935
|
-
style: row.promotion?.color === void 0 ? void 0 : { color: row.promotion.color },
|
|
1936
|
-
children: tipDiscounted
|
|
1937
|
-
})
|
|
1938
|
-
]
|
|
1939
|
-
})]
|
|
1940
|
-
}),
|
|
1941
|
-
promotionText !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1942
|
-
className: ModelPanel_module_css_default.tipPromo,
|
|
1943
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: promotionText })
|
|
1944
|
-
}),
|
|
1945
|
-
(promotionAction !== void 0 || tip.source === "touch") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1946
|
-
type: "button",
|
|
1947
|
-
className: ModelPanel_module_css_default.tipAction,
|
|
1948
|
-
onClick: (event) => {
|
|
1949
|
-
runAction(row, promotionAction, shouldRestoreFocus(event));
|
|
1950
|
-
},
|
|
1951
|
-
children: t("modelPanelUse")
|
|
1952
|
-
}),
|
|
1953
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: ModelPanel_module_css_default.tipDivider }),
|
|
1954
|
-
efforts !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1955
|
-
className: ModelPanel_module_css_default.tipCaps,
|
|
1956
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1957
|
-
className: ModelPanel_module_css_default.tipLabel,
|
|
1958
|
-
children: t("modelPanelEffort")
|
|
1959
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1960
|
-
open: effortOpen,
|
|
1961
|
-
portal: true,
|
|
1962
|
-
dense: true,
|
|
1963
|
-
side: "bottom",
|
|
1964
|
-
align: "end",
|
|
1965
|
-
selectedId: selectedEffort === void 0 ? EFFORT_DEFAULT_ID : selectedEffort,
|
|
1966
|
-
items: effortItems,
|
|
1967
|
-
onSelect: (id) => {
|
|
1968
|
-
chooseEffort(row, id === EFFORT_DEFAULT_ID ? void 0 : id);
|
|
1877
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1878
|
+
className: ModelPanel_module_css_default.tipScroll,
|
|
1879
|
+
children: [
|
|
1880
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1881
|
+
className: ModelPanel_module_css_default.tipName,
|
|
1882
|
+
children: row.name
|
|
1883
|
+
}),
|
|
1884
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1885
|
+
className: ModelPanel_module_css_default.tipDesc,
|
|
1886
|
+
children: description ?? t("modelPanelDescriptionMissing")
|
|
1887
|
+
}),
|
|
1888
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1889
|
+
className: ModelPanel_module_css_default.tipFeatures,
|
|
1890
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1891
|
+
className: ModelPanel_module_css_default.tipLabel,
|
|
1892
|
+
children: t("modelPanelFeatures")
|
|
1893
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1894
|
+
className: ModelPanel_module_css_default.tipVal,
|
|
1895
|
+
children: featureLabels(row, t)
|
|
1896
|
+
})]
|
|
1897
|
+
}),
|
|
1898
|
+
tierText !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1899
|
+
className: ModelPanel_module_css_default.tipTier,
|
|
1900
|
+
children: tierText
|
|
1901
|
+
}),
|
|
1902
|
+
tierAction !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1903
|
+
type: "button",
|
|
1904
|
+
className: ModelPanel_module_css_default.tipLink,
|
|
1905
|
+
onClick: (event) => {
|
|
1906
|
+
runAction(row, tierAction, shouldRestoreFocus(event));
|
|
1969
1907
|
},
|
|
1970
|
-
|
|
1971
|
-
|
|
1908
|
+
children: [t("modelPanelUpgrade"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1909
|
+
className: ModelPanel_module_css_default.tipLinkChevron,
|
|
1910
|
+
"aria-hidden": "true",
|
|
1911
|
+
children: "›"
|
|
1912
|
+
})]
|
|
1913
|
+
}),
|
|
1914
|
+
hasMidSection && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: ModelPanel_module_css_default.tipDivider }),
|
|
1915
|
+
row.credits !== void 0 && row.credits.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1916
|
+
className: ModelPanel_module_css_default.tipSpend,
|
|
1917
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1918
|
+
className: ModelPanel_module_css_default.tipLabel,
|
|
1919
|
+
children: t("modelPanelSpendRate")
|
|
1920
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1921
|
+
className: ModelPanel_module_css_default.tipVal,
|
|
1922
|
+
children: [
|
|
1923
|
+
tipDiscounted === void 0 && row.credits,
|
|
1924
|
+
tipStrikeOriginal && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1925
|
+
className: ModelPanel_module_css_default.tipCreditsStruck,
|
|
1926
|
+
children: row.credits
|
|
1927
|
+
}),
|
|
1928
|
+
tipDiscounted !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1929
|
+
className: ModelPanel_module_css_default.tipDiscounted,
|
|
1930
|
+
style: row.promotion?.color === void 0 ? void 0 : { color: row.promotion.color },
|
|
1931
|
+
children: tipDiscounted
|
|
1932
|
+
})
|
|
1933
|
+
]
|
|
1934
|
+
})]
|
|
1935
|
+
}),
|
|
1936
|
+
promotionText !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1937
|
+
className: ModelPanel_module_css_default.tipPromo,
|
|
1938
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: promotionText })
|
|
1939
|
+
}),
|
|
1940
|
+
(promotionAction !== void 0 || tip.source === "touch") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1941
|
+
type: "button",
|
|
1942
|
+
className: ModelPanel_module_css_default.tipAction,
|
|
1943
|
+
onClick: (event) => {
|
|
1944
|
+
runAction(row, promotionAction, shouldRestoreFocus(event));
|
|
1972
1945
|
},
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1946
|
+
children: t("modelPanelUse")
|
|
1947
|
+
}),
|
|
1948
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: ModelPanel_module_css_default.tipDivider }),
|
|
1949
|
+
efforts !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1950
|
+
className: ModelPanel_module_css_default.tipCaps,
|
|
1951
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1952
|
+
className: ModelPanel_module_css_default.tipLabel,
|
|
1953
|
+
children: t("modelPanelEffort")
|
|
1954
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1955
|
+
open: effortOpen,
|
|
1956
|
+
portal: true,
|
|
1957
|
+
dense: true,
|
|
1958
|
+
side: "bottom",
|
|
1959
|
+
align: "end",
|
|
1960
|
+
selectedId: selectedEffort === void 0 ? EFFORT_DEFAULT_ID : selectedEffort,
|
|
1961
|
+
items: effortItems,
|
|
1962
|
+
onSelect: (id) => {
|
|
1963
|
+
chooseEffort(row, id === EFFORT_DEFAULT_ID ? void 0 : id);
|
|
1981
1964
|
},
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
children: effortLabel
|
|
1985
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1986
|
-
className: ModelPanel_module_css_default.tipEffortChevron,
|
|
1987
|
-
"aria-hidden": true,
|
|
1988
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
|
|
1989
|
-
})]
|
|
1990
|
-
})
|
|
1991
|
-
})]
|
|
1992
|
-
}),
|
|
1993
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1994
|
-
className: ModelPanel_module_css_default.tipCaps,
|
|
1995
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1996
|
-
className: ModelPanel_module_css_default.tipLabel,
|
|
1997
|
-
children: t("modelPanelContextWindow")
|
|
1998
|
-
}), tipEdit.editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1999
|
-
type: "text",
|
|
2000
|
-
inputMode: "text",
|
|
2001
|
-
className: `${ModelPanel_module_css_default.tipInput} ${ModelPanel_module_css_default.tipVal}`,
|
|
2002
|
-
autoFocus: true,
|
|
2003
|
-
value: tipEdit.contextDraft,
|
|
2004
|
-
onChange: (event) => {
|
|
2005
|
-
const next = event.currentTarget.value;
|
|
2006
|
-
if (!DRAFT_PATTERN.test(next)) return;
|
|
2007
|
-
setTipEdit({
|
|
2008
|
-
...tipEdit,
|
|
2009
|
-
contextDraft: clampOnInput(next, row.contextWindowCap)
|
|
2010
|
-
});
|
|
2011
|
-
},
|
|
2012
|
-
onKeyDown: (event) => {
|
|
2013
|
-
if (event.key !== "Enter") return;
|
|
2014
|
-
event.preventDefault();
|
|
2015
|
-
saveTipEdit(row, tipEdit);
|
|
2016
|
-
}
|
|
2017
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2018
|
-
className: `${ModelPanel_module_css_default.tipValue} ${ModelPanel_module_css_default.tipVal}`,
|
|
2019
|
-
children: formatTokens(row.contextWindow)
|
|
2020
|
-
})]
|
|
2021
|
-
}),
|
|
2022
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2023
|
-
className: ModelPanel_module_css_default.tipCaps,
|
|
2024
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2025
|
-
className: ModelPanel_module_css_default.tipLabel,
|
|
2026
|
-
children: t("modelPanelMaxOutput")
|
|
2027
|
-
}), tipEdit.editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2028
|
-
type: "text",
|
|
2029
|
-
inputMode: "text",
|
|
2030
|
-
className: `${ModelPanel_module_css_default.tipInput} ${ModelPanel_module_css_default.tipVal}`,
|
|
2031
|
-
value: tipEdit.outputDraft,
|
|
2032
|
-
onChange: (event) => {
|
|
2033
|
-
const next = event.currentTarget.value;
|
|
2034
|
-
if (!DRAFT_PATTERN.test(next)) return;
|
|
2035
|
-
setTipEdit({
|
|
2036
|
-
...tipEdit,
|
|
2037
|
-
outputDraft: clampOnInput(next, row.maxOutputTokensCap)
|
|
2038
|
-
});
|
|
2039
|
-
},
|
|
2040
|
-
onKeyDown: (event) => {
|
|
2041
|
-
if (event.key !== "Enter") return;
|
|
2042
|
-
event.preventDefault();
|
|
2043
|
-
saveTipEdit(row, tipEdit);
|
|
2044
|
-
}
|
|
2045
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2046
|
-
className: `${ModelPanel_module_css_default.tipValue} ${ModelPanel_module_css_default.tipVal}`,
|
|
2047
|
-
children: formatTokens(row.maxOutputTokens)
|
|
2048
|
-
})]
|
|
2049
|
-
}),
|
|
2050
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2051
|
-
className: ModelPanel_module_css_default.tipActions,
|
|
2052
|
-
children: [
|
|
2053
|
-
tipEdit.editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2054
|
-
type: "button",
|
|
2055
|
-
className: ModelPanel_module_css_default.tipAction,
|
|
2056
|
-
disabled: tipEdit.saving,
|
|
2057
|
-
onClick: () => {
|
|
2058
|
-
restoreDefault(row);
|
|
1965
|
+
onClose: () => {
|
|
1966
|
+
setEffortOpen(false);
|
|
2059
1967
|
},
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
1968
|
+
className: ModelPanel_module_css_default.tipEffortMenu,
|
|
1969
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1970
|
+
type: "button",
|
|
1971
|
+
className: ModelPanel_module_css_default.tipEffort,
|
|
1972
|
+
"aria-haspopup": "menu",
|
|
1973
|
+
"aria-expanded": effortOpen,
|
|
1974
|
+
onClick: () => {
|
|
1975
|
+
setEffortOpen((open) => !open);
|
|
1976
|
+
},
|
|
1977
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1978
|
+
className: ModelPanel_module_css_default.tipEffortValue,
|
|
1979
|
+
children: effortLabel
|
|
1980
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1981
|
+
className: ModelPanel_module_css_default.tipEffortChevron,
|
|
1982
|
+
"aria-hidden": true,
|
|
1983
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {})
|
|
1984
|
+
})]
|
|
1985
|
+
})
|
|
1986
|
+
})]
|
|
1987
|
+
}),
|
|
1988
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1989
|
+
className: ModelPanel_module_css_default.tipCaps,
|
|
1990
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1991
|
+
className: ModelPanel_module_css_default.tipLabel,
|
|
1992
|
+
children: t("modelPanelContextWindow")
|
|
1993
|
+
}), tipEdit.editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1994
|
+
type: "text",
|
|
1995
|
+
inputMode: "text",
|
|
1996
|
+
className: `${ModelPanel_module_css_default.tipInput} ${ModelPanel_module_css_default.tipVal}`,
|
|
1997
|
+
autoFocus: true,
|
|
1998
|
+
value: tipEdit.contextDraft,
|
|
1999
|
+
onChange: (event) => {
|
|
2000
|
+
const next = event.currentTarget.value;
|
|
2001
|
+
if (!DRAFT_PATTERN.test(next)) return;
|
|
2002
|
+
setTipEdit({
|
|
2003
|
+
...tipEdit,
|
|
2004
|
+
contextDraft: clampOnInput(next, row.contextWindowCap)
|
|
2005
|
+
});
|
|
2068
2006
|
},
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2007
|
+
onKeyDown: (event) => {
|
|
2008
|
+
if (event.key !== "Enter") return;
|
|
2009
|
+
event.preventDefault();
|
|
2010
|
+
saveTipEdit(row, tipEdit);
|
|
2011
|
+
}
|
|
2012
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2013
|
+
className: `${ModelPanel_module_css_default.tipValue} ${ModelPanel_module_css_default.tipVal}`,
|
|
2014
|
+
children: formatTokens(row.contextWindow)
|
|
2015
|
+
})]
|
|
2016
|
+
}),
|
|
2017
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2018
|
+
className: ModelPanel_module_css_default.tipCaps,
|
|
2019
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2020
|
+
className: ModelPanel_module_css_default.tipLabel,
|
|
2021
|
+
children: t("modelPanelMaxOutput")
|
|
2022
|
+
}), tipEdit.editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2023
|
+
type: "text",
|
|
2024
|
+
inputMode: "text",
|
|
2025
|
+
className: `${ModelPanel_module_css_default.tipInput} ${ModelPanel_module_css_default.tipVal}`,
|
|
2026
|
+
value: tipEdit.outputDraft,
|
|
2027
|
+
onChange: (event) => {
|
|
2028
|
+
const next = event.currentTarget.value;
|
|
2029
|
+
if (!DRAFT_PATTERN.test(next)) return;
|
|
2030
|
+
setTipEdit({
|
|
2031
|
+
...tipEdit,
|
|
2032
|
+
outputDraft: clampOnInput(next, row.maxOutputTokensCap)
|
|
2033
|
+
});
|
|
2078
2034
|
},
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2035
|
+
onKeyDown: (event) => {
|
|
2036
|
+
if (event.key !== "Enter") return;
|
|
2037
|
+
event.preventDefault();
|
|
2038
|
+
saveTipEdit(row, tipEdit);
|
|
2039
|
+
}
|
|
2040
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2041
|
+
className: `${ModelPanel_module_css_default.tipValue} ${ModelPanel_module_css_default.tipVal}`,
|
|
2042
|
+
children: formatTokens(row.maxOutputTokens)
|
|
2043
|
+
})]
|
|
2044
|
+
}),
|
|
2045
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2046
|
+
className: ModelPanel_module_css_default.tipActions,
|
|
2047
|
+
children: [
|
|
2048
|
+
tipEdit.editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2049
|
+
type: "button",
|
|
2050
|
+
className: ModelPanel_module_css_default.tipAction,
|
|
2051
|
+
disabled: tipEdit.saving,
|
|
2052
|
+
onClick: () => {
|
|
2053
|
+
restoreDefault(row);
|
|
2054
|
+
},
|
|
2055
|
+
children: t("modelPanelRestoreDefault")
|
|
2056
|
+
}),
|
|
2057
|
+
tipEdit.editing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2058
|
+
type: "button",
|
|
2059
|
+
className: ModelPanel_module_css_default.tipAction,
|
|
2060
|
+
disabled: tipEdit.saving,
|
|
2061
|
+
onClick: () => {
|
|
2062
|
+
setTipEdit(draftsFor(row, false));
|
|
2063
|
+
},
|
|
2064
|
+
children: t("cancel")
|
|
2065
|
+
}),
|
|
2066
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2067
|
+
type: "button",
|
|
2068
|
+
className: ModelPanel_module_css_default.tipSave,
|
|
2069
|
+
disabled: tipEdit.saving,
|
|
2070
|
+
onClick: () => {
|
|
2071
|
+
if (tipEdit.editing) saveTipEdit(row, tipEdit);
|
|
2072
|
+
else setTipEdit(draftsFor(row, true));
|
|
2073
|
+
},
|
|
2074
|
+
children: tipEdit.editing ? tipEdit.saving ? t("modelPanelSaving") : t("modelPanelSave") : t("modelPanelEdit")
|
|
2075
|
+
})
|
|
2076
|
+
]
|
|
2077
|
+
})
|
|
2078
|
+
]
|
|
2079
|
+
})
|
|
2084
2080
|
}), document.body);
|
|
2085
2081
|
})()
|
|
2086
2082
|
]
|
|
@@ -2300,12 +2296,17 @@ window.__ModuleLoader__.load({
|
|
|
2300
2296
|
* 则渲染,无记录(非 CodeBuddy 轮)渲染为空。与官方 `TurnUsagePanel` 同构:
|
|
2301
2297
|
* 图标 + 文字标签,点击无详情面板(仅展示一条合计)。
|
|
2302
2298
|
*
|
|
2303
|
-
*
|
|
2304
|
-
* `recordCredit`),不是悬停时现查 ——
|
|
2305
|
-
*
|
|
2299
|
+
* 悬停提示附上本轮用过的账号与本轮请求 id:两者都在扣分那一刻随记录写入(见 host 的
|
|
2300
|
+
* `recordCredit`),不是悬停时现查 —— 一轮里用户可以切换账号,而请求 id 每轮重铸,
|
|
2301
|
+
* 现查会把整轮说成最后那个账号、或报出当前轮的 id。有 id 时点击 pill 复制它的完整值,
|
|
2302
|
+
* 因为显示在提示里的那个值就是用户要拿去对账的东西。
|
|
2306
2303
|
*
|
|
2307
2304
|
* @module dsh-llm-codebuddy-power/client/TurnCreditPill
|
|
2308
2305
|
*/
|
|
2306
|
+
/** 复制成功后 pill 文字保持「已复制」的时长(毫秒),与配置页的复制反馈一致。 */
|
|
2307
|
+
const COPIED_FEEDBACK_MS = 1e3;
|
|
2308
|
+
/** 提示里显示的请求 id 前几位;完整值由点击复制,不必全写在提示里。 */
|
|
2309
|
+
const TURN_REQUEST_ID_DISPLAY_CHARS = 6;
|
|
2309
2310
|
const pillStyle = {
|
|
2310
2311
|
display: "inline-flex",
|
|
2311
2312
|
alignItems: "center",
|
|
@@ -2320,13 +2321,29 @@ window.__ModuleLoader__.load({
|
|
|
2320
2321
|
whiteSpace: "nowrap"
|
|
2321
2322
|
};
|
|
2322
2323
|
/**
|
|
2324
|
+
* 可点击时在 pill 样式上补上按钮语义:指针与键盘反馈,并让字族跟随环境。
|
|
2325
|
+
*
|
|
2326
|
+
* 只覆盖 `fontFamily` 而不是 `font` 简写:后者会把 `pillStyle` 的 `fontSize` 一并重置为
|
|
2327
|
+
* 继承值,同一个 pill 在可点击与不可点击两种形态下就会是两个字号。
|
|
2328
|
+
*/
|
|
2329
|
+
const copyableStyle = {
|
|
2330
|
+
...pillStyle,
|
|
2331
|
+
fontFamily: "inherit",
|
|
2332
|
+
cursor: "pointer"
|
|
2333
|
+
};
|
|
2334
|
+
/**
|
|
2323
2335
|
* 每轮积分 pill。messageId 反查轮号后查该轮记录;无记录渲染为空(未用
|
|
2324
2336
|
* CodeBuddy 模型即一轮 0 分也渲染,有记录即证明用了 CodeBuddy)。只显示
|
|
2325
|
-
* 积分,模型由 dsh
|
|
2337
|
+
* 积分,模型由 dsh 用量自带;悬停给出本轮用过的账号与本轮请求 id。
|
|
2326
2338
|
*/
|
|
2327
2339
|
function TurnCreditPill(props) {
|
|
2328
2340
|
const { messageId, useChat, sessionId, creditOf, t } = props;
|
|
2329
2341
|
const [record, setRecord] = (0, react.useState)(void 0);
|
|
2342
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
2343
|
+
const copiedTimer = (0, react.useRef)(void 0);
|
|
2344
|
+
(0, react.useEffect)(() => () => {
|
|
2345
|
+
if (copiedTimer.current !== void 0) window.clearTimeout(copiedTimer.current);
|
|
2346
|
+
}, []);
|
|
2330
2347
|
const nodes = useChat((snapshot) => snapshot.legacy.nodes);
|
|
2331
2348
|
const turn = (0, react.useMemo)(() => {
|
|
2332
2349
|
for (const node of nodes) {
|
|
@@ -2355,21 +2372,50 @@ window.__ModuleLoader__.load({
|
|
|
2355
2372
|
turn
|
|
2356
2373
|
]);
|
|
2357
2374
|
if (record === void 0) return null;
|
|
2375
|
+
const requestId = record.requestId;
|
|
2358
2376
|
const creditText = (Math.round(record.credit * 100) / 100).toLocaleString(void 0, {
|
|
2359
2377
|
maximumFractionDigits: 2,
|
|
2360
2378
|
useGrouping: false
|
|
2361
2379
|
});
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2380
|
+
const tipLines = [t("turnCreditTip"), ...record.accounts.map((account) => t("turnCreditAccount", {
|
|
2381
|
+
nickname: account.nickname,
|
|
2382
|
+
uid: account.uidPrefix
|
|
2383
|
+
}))];
|
|
2384
|
+
if (requestId !== void 0) {
|
|
2385
|
+
tipLines.push(t("turnCreditRequestId", { requestId: requestId.slice(0, TURN_REQUEST_ID_DISPLAY_CHARS) }));
|
|
2386
|
+
tipLines.push(copied ? t("turnCreditCopiedTip") : t("turnCreditCopyTip"));
|
|
2387
|
+
}
|
|
2388
|
+
const tip = tipLines.join("\n");
|
|
2389
|
+
const onCopy = () => {
|
|
2390
|
+
if (requestId === void 0 || copied) return;
|
|
2391
|
+
(0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(requestId).then((ok) => {
|
|
2392
|
+
if (!ok) return;
|
|
2393
|
+
setCopied(true);
|
|
2394
|
+
copiedTimer.current = window.setTimeout(() => {
|
|
2395
|
+
copiedTimer.current = void 0;
|
|
2396
|
+
setCopied(false);
|
|
2397
|
+
}, COPIED_FEEDBACK_MS);
|
|
2398
|
+
});
|
|
2399
|
+
};
|
|
2400
|
+
if (requestId === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
2401
|
+
label: tip,
|
|
2367
2402
|
side: "bottom",
|
|
2368
2403
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2369
2404
|
style: pillStyle,
|
|
2370
2405
|
children: t("turnCredit", { credit: creditText })
|
|
2371
2406
|
})
|
|
2372
2407
|
});
|
|
2408
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
2409
|
+
label: tip,
|
|
2410
|
+
side: "bottom",
|
|
2411
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2412
|
+
type: "button",
|
|
2413
|
+
style: copyableStyle,
|
|
2414
|
+
"aria-label": t("turnCreditCopy"),
|
|
2415
|
+
onClick: onCopy,
|
|
2416
|
+
children: copied ? t("turnCreditCopied") : t("turnCredit", { credit: creditText })
|
|
2417
|
+
})
|
|
2418
|
+
});
|
|
2373
2419
|
}
|
|
2374
2420
|
//#endregion
|
|
2375
2421
|
//#region src/client/locales.ts
|
|
@@ -2398,9 +2444,6 @@ window.__ModuleLoader__.load({
|
|
|
2398
2444
|
logoutSelectedDesc: "Signing out removes the stored credentials; the {count} selected accounts must sign in again to be used.",
|
|
2399
2445
|
logoutConfirm: "Sign out",
|
|
2400
2446
|
cancel: "Cancel",
|
|
2401
|
-
chooseDefault: "Choose default",
|
|
2402
|
-
clearDefault: "Remove default",
|
|
2403
|
-
defaultTag: "Default",
|
|
2404
2447
|
nickname: "Nickname",
|
|
2405
2448
|
uid: "UID",
|
|
2406
2449
|
loginExpires: "Sign-in expires",
|
|
@@ -2430,6 +2473,11 @@ window.__ModuleLoader__.load({
|
|
|
2430
2473
|
turnCredit: "{credit} credits",
|
|
2431
2474
|
turnCreditTip: "CodeBuddy credits spent this turn",
|
|
2432
2475
|
turnCreditAccount: "Account: {nickname} ({uid}…)",
|
|
2476
|
+
turnCreditRequestId: "Request ID: {requestId}…",
|
|
2477
|
+
turnCreditCopy: "Copy this turn’s request ID",
|
|
2478
|
+
turnCreditCopyTip: "Click to copy this turn’s request ID",
|
|
2479
|
+
turnCreditCopied: "Copied",
|
|
2480
|
+
turnCreditCopiedTip: "Request ID copied",
|
|
2433
2481
|
modelPanelTrigger: "CodeBuddy models",
|
|
2434
2482
|
modelPanelTitle: "CodeBuddy models",
|
|
2435
2483
|
modelPanelEmpty: "No CodeBuddy models available.",
|
|
@@ -2474,9 +2522,6 @@ window.__ModuleLoader__.load({
|
|
|
2474
2522
|
logoutSelectedDesc: "退出会删除已存凭据,选中的 {count} 个账号需要重新登录才能继续使用。",
|
|
2475
2523
|
logoutConfirm: "退出",
|
|
2476
2524
|
cancel: "取消",
|
|
2477
|
-
chooseDefault: "选择默认",
|
|
2478
|
-
clearDefault: "取消默认",
|
|
2479
|
-
defaultTag: "默认",
|
|
2480
2525
|
nickname: "昵称",
|
|
2481
2526
|
uid: "UID",
|
|
2482
2527
|
loginExpires: "登录到期",
|
|
@@ -2506,6 +2551,11 @@ window.__ModuleLoader__.load({
|
|
|
2506
2551
|
turnCredit: "{credit} 分",
|
|
2507
2552
|
turnCreditTip: "本轮消耗的 CodeBuddy 积分",
|
|
2508
2553
|
turnCreditAccount: "账号:{nickname}({uid}…)",
|
|
2554
|
+
turnCreditRequestId: "请求 ID:{requestId}…",
|
|
2555
|
+
turnCreditCopy: "复制本轮请求 ID",
|
|
2556
|
+
turnCreditCopyTip: "点击复制本轮请求 ID",
|
|
2557
|
+
turnCreditCopied: "已复制",
|
|
2558
|
+
turnCreditCopiedTip: "请求 ID 已复制",
|
|
2509
2559
|
modelPanelTrigger: "CodeBuddy 模型",
|
|
2510
2560
|
modelPanelTitle: "CodeBuddy 模型",
|
|
2511
2561
|
modelPanelEmpty: "暂无可用 CodeBuddy 模型。",
|
|
@@ -2529,22 +2579,21 @@ window.__ModuleLoader__.load({
|
|
|
2529
2579
|
//#endregion
|
|
2530
2580
|
//#region src/client/store.ts
|
|
2531
2581
|
/**
|
|
2532
|
-
* CodeBuddy 页面 store
|
|
2582
|
+
* CodeBuddy 页面 store:配置页共享的账号快照。
|
|
2533
2583
|
*
|
|
2534
|
-
*
|
|
2535
|
-
*
|
|
2584
|
+
* 客户端插件在配置页条目下挂载本句柄,因此在该页完成的登录、退出或排序
|
|
2585
|
+
* 无需跨组件接线即可到达同一页面的各个徽章。
|
|
2536
2586
|
*
|
|
2537
|
-
*
|
|
2538
|
-
* 由 `./index.ts` 经 `ctx.
|
|
2539
|
-
* 注入面的 `hooks`
|
|
2540
|
-
*
|
|
2541
|
-
* 读取,导致开关与圆环之间有最多一个轮询周期的延迟。
|
|
2587
|
+
* **界面偏好不在这里**:它们是插件自己的 volatile 配置字段(见 `../prefs.ts`),
|
|
2588
|
+
* 由 `./index.ts` 经 `ctx.configForms.get()` 读取,并以一个派生的活快照经
|
|
2589
|
+
* 注入面的 `hooks` 隔舱同时下发给配置页与对话输入区的控件组 —— 后者处在另一个
|
|
2590
|
+
* 作用域,共享不了本句柄。
|
|
2542
2591
|
*
|
|
2543
2592
|
* @module dsh-llm-codebuddy-power/client/store
|
|
2544
2593
|
*/
|
|
2545
2594
|
/**
|
|
2546
2595
|
* 声明 CodeBuddy 页面状态与写入接口。
|
|
2547
|
-
* @returns store 句柄(在 apply
|
|
2596
|
+
* @returns store 句柄(在 apply 中挂载于配置页条目下)。
|
|
2548
2597
|
*/
|
|
2549
2598
|
function createCodeBuddyStore() {
|
|
2550
2599
|
return (0, _deepseek_ai_dsh_client_store.defineStore)({
|
|
@@ -2552,7 +2601,6 @@ window.__ModuleLoader__.load({
|
|
|
2552
2601
|
phase: "loading",
|
|
2553
2602
|
error: null,
|
|
2554
2603
|
accounts: [],
|
|
2555
|
-
defaultUid: null,
|
|
2556
2604
|
loginState: null
|
|
2557
2605
|
}),
|
|
2558
2606
|
actions: {
|
|
@@ -2564,14 +2612,21 @@ window.__ModuleLoader__.load({
|
|
|
2564
2612
|
draft.phase = "idle";
|
|
2565
2613
|
draft.error = null;
|
|
2566
2614
|
draft.accounts = result.accounts;
|
|
2567
|
-
draft.defaultUid = result.defaultUid ?? null;
|
|
2568
2615
|
},
|
|
2569
2616
|
fail: (draft, message) => {
|
|
2570
2617
|
draft.phase = "error";
|
|
2571
2618
|
draft.error = message;
|
|
2572
2619
|
},
|
|
2620
|
+
clearError: (draft) => {
|
|
2621
|
+
draft.error = null;
|
|
2622
|
+
if (draft.phase === "error") draft.phase = "idle";
|
|
2623
|
+
},
|
|
2573
2624
|
setLoginState: (draft, state) => {
|
|
2574
2625
|
draft.loginState = state;
|
|
2626
|
+
},
|
|
2627
|
+
adoptLogin: (draft, state) => {
|
|
2628
|
+
if (draft.loginState !== null) return;
|
|
2629
|
+
draft.loginState = state;
|
|
2575
2630
|
}
|
|
2576
2631
|
}
|
|
2577
2632
|
});
|
|
@@ -2583,14 +2638,27 @@ window.__ModuleLoader__.load({
|
|
|
2583
2638
|
/**
|
|
2584
2639
|
* 在共享通道上调用一个鉴权 endpoint。该通道调用按设计不做类型约束;
|
|
2585
2640
|
* endpoint 所记录的 payload 结构在此唯一的 wire 边界处恢复。
|
|
2641
|
+
* @param rpc - 当前连接的 RPC 调用器。
|
|
2642
|
+
* @param endpoint - 通道下的 endpoint 名。
|
|
2643
|
+
* @param payload - endpoint 自己的请求载荷。
|
|
2644
|
+
* @param signal - 可选取消;中止后该请求的连接随即释放,而不是等宿主应答。
|
|
2645
|
+
* @returns endpoint 自己声明的结果。
|
|
2586
2646
|
*/
|
|
2587
|
-
function authCall(rpc, endpoint, payload = {}) {
|
|
2588
|
-
return rpc.call(AUTH_CHANNEL, endpoint, payload).then((result) => result);
|
|
2647
|
+
function authCall(rpc, endpoint, payload = {}, signal) {
|
|
2648
|
+
return rpc.call(AUTH_CHANNEL, endpoint, payload, signal).then((result) => result);
|
|
2589
2649
|
}
|
|
2590
2650
|
//#endregion
|
|
2591
2651
|
//#region src/client/index.ts
|
|
2592
2652
|
/** 本插件拥有的字典命名空间。 */
|
|
2593
2653
|
const NS = "settings.codebuddy";
|
|
2654
|
+
/**
|
|
2655
|
+
* 本插件在 profile 里的包名,也是 Plugins 页派发配置的键。
|
|
2656
|
+
*
|
|
2657
|
+
* 该页以 `pkg.name` 派发 `plugins.bundle.config`(见 `PluginManagerPage` 的
|
|
2658
|
+
* `renderSlot(..., { entryKey: pkg.name })`),所以这里的值必须与 package.json 的
|
|
2659
|
+
* `name` 逐字一致;写错不会报错,只会让配置区静默地不出现。
|
|
2660
|
+
*/
|
|
2661
|
+
const BUNDLE_NAME = "dsh-llm-codebuddy-power";
|
|
2594
2662
|
/** 必需服务:插槽注册表、locale 服务、wire、共享模型目录服务(该面板读取
|
|
2595
2663
|
* 与官方选择器相同的 store)、uiConversation(附件图片 URL),以及设置作用域
|
|
2596
2664
|
* (界面偏好所在的命名空间)。
|
|
@@ -2607,7 +2675,7 @@ window.__ModuleLoader__.load({
|
|
|
2607
2675
|
"remote",
|
|
2608
2676
|
"remote.session",
|
|
2609
2677
|
"uiConversation",
|
|
2610
|
-
"
|
|
2678
|
+
"configForms"
|
|
2611
2679
|
];
|
|
2612
2680
|
/**
|
|
2613
2681
|
* 在插槽声明后注册 CodeBuddy 设置分区与对话内账号控件。
|
|
@@ -2621,10 +2689,10 @@ window.__ModuleLoader__.load({
|
|
|
2621
2689
|
const rpc = ctx.get("connection").rpc;
|
|
2622
2690
|
const store = createCodeBuddyStore();
|
|
2623
2691
|
const t = ctx.locale.bind(NS);
|
|
2624
|
-
const
|
|
2692
|
+
const prefsForm = ctx.configForms.get(CODEBUDDY_SETTINGS_NAMESPACE);
|
|
2625
2693
|
const prefsStore = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(DEFAULT_CODEBUDDY_SETTINGS);
|
|
2626
2694
|
const publishPrefs = () => {
|
|
2627
|
-
const section =
|
|
2695
|
+
const section = prefsForm.getSnapshot().value;
|
|
2628
2696
|
if (section === void 0) return;
|
|
2629
2697
|
const current = prefsStore.getSnapshot();
|
|
2630
2698
|
if (current.showUsage === section.showUsage && current.dangerPct === section.dangerPct && current.drawToolInMinimal === section.drawToolInMinimal) return;
|
|
@@ -2635,15 +2703,15 @@ window.__ModuleLoader__.load({
|
|
|
2635
2703
|
});
|
|
2636
2704
|
};
|
|
2637
2705
|
ctx.effect(() => {
|
|
2638
|
-
const off =
|
|
2706
|
+
const off = prefsForm.subscribe(publishPrefs);
|
|
2639
2707
|
publishPrefs();
|
|
2640
2708
|
return off;
|
|
2641
2709
|
}, "dsh-llm-codebuddy-power: settings prefs");
|
|
2642
2710
|
/** 写入一个偏好字段;用户层覆盖部署级 base。 */
|
|
2643
2711
|
const setPref = (field, value) => {
|
|
2644
|
-
|
|
2712
|
+
prefsForm.set(field, value);
|
|
2645
2713
|
};
|
|
2646
|
-
/**
|
|
2714
|
+
/** 读取账号集合并发布到配置页的 store。 */
|
|
2647
2715
|
const refreshAccounts = async (actions) => {
|
|
2648
2716
|
actions.start();
|
|
2649
2717
|
try {
|
|
@@ -2671,6 +2739,7 @@ window.__ModuleLoader__.load({
|
|
|
2671
2739
|
* @returns 复制模式下链接是否已进剪贴板;打开模式恒为 true。
|
|
2672
2740
|
*/
|
|
2673
2741
|
const beginLogin = async (openBrowser) => {
|
|
2742
|
+
actions.clearError();
|
|
2674
2743
|
const result = await authCall(rpc, "startLogin");
|
|
2675
2744
|
if (!result.ok) {
|
|
2676
2745
|
actions.fail(`${result.error.code}: ${result.error.message}`);
|
|
@@ -2683,12 +2752,32 @@ window.__ModuleLoader__.load({
|
|
|
2683
2752
|
}
|
|
2684
2753
|
actions.setLoginState({
|
|
2685
2754
|
state: result.value.state,
|
|
2686
|
-
startedAt: Date.now()
|
|
2755
|
+
startedAt: result.value.startedAt ?? Date.now()
|
|
2687
2756
|
});
|
|
2688
2757
|
return true;
|
|
2689
2758
|
};
|
|
2690
|
-
|
|
2691
|
-
|
|
2759
|
+
/**
|
|
2760
|
+
* 接回宿主仍在轮询的握手。浏览器刷新会丢掉本地的「登录中」状态,而宿主的
|
|
2761
|
+
* 握手还在等,不接回就会显示成可再次登录,用户点了便平白多出第二次握手。
|
|
2762
|
+
*/
|
|
2763
|
+
const resumeLogin = async () => {
|
|
2764
|
+
const result = await authCall(rpc, "pendingLogin");
|
|
2765
|
+
if (!result.ok || result.value === void 0) return;
|
|
2766
|
+
actions.adoptLogin(result.value);
|
|
2767
|
+
};
|
|
2768
|
+
/**
|
|
2769
|
+
* 轮询一次握手的结果。
|
|
2770
|
+
*
|
|
2771
|
+
* 宿主侧立即作答(不等待后台握手),因此这里每次都是一次短请求;`signal` 用于在
|
|
2772
|
+
* 组件收尾时真正中止那次在飞的请求并释放连接 —— 只清定时器的话,已经发出的
|
|
2773
|
+
* 请求仍会挂在网络上,而浏览器的同源连接数有限,积多了会把后续所有到该源的
|
|
2774
|
+
* 请求(账号、用量、会话账号)一起挤成待处理。
|
|
2775
|
+
* @param state - 握手 id。
|
|
2776
|
+
* @param signal - 本次轮询的取消信号。
|
|
2777
|
+
* @returns 该握手是否已完成且账号已持久化。
|
|
2778
|
+
*/
|
|
2779
|
+
const pollLogin = async (state, signal) => {
|
|
2780
|
+
const result = await authCall(rpc, "pollLogin", { state }, signal);
|
|
2692
2781
|
if (!result.ok || !result.value.done) return false;
|
|
2693
2782
|
actions.setLoginState(null);
|
|
2694
2783
|
await refreshAccounts(actions);
|
|
@@ -2704,33 +2793,28 @@ window.__ModuleLoader__.load({
|
|
|
2704
2793
|
if (result.ok) await refreshAccounts(actions);
|
|
2705
2794
|
else actions.fail(`${result.error.code}: ${result.error.message}`);
|
|
2706
2795
|
};
|
|
2707
|
-
const setDefault = async (uid) => {
|
|
2708
|
-
const result = await authCall(rpc, "setDefault", { uid: uid ?? "" });
|
|
2709
|
-
if (result.ok) await refreshAccounts(actions);
|
|
2710
|
-
else actions.fail(`${result.error.code}: ${result.error.message}`);
|
|
2711
|
-
};
|
|
2712
2796
|
return {
|
|
2713
2797
|
hooks: { prefs: prefsStore },
|
|
2714
2798
|
refreshAccounts: () => refreshAccounts(actions),
|
|
2715
2799
|
startLogin: async () => {
|
|
2716
2800
|
await beginLogin(true);
|
|
2717
2801
|
},
|
|
2802
|
+
resumeLogin,
|
|
2718
2803
|
copyLoginLink: () => beginLogin(false),
|
|
2719
|
-
cancelLogin: async (state) => {
|
|
2720
|
-
|
|
2804
|
+
cancelLogin: async (state, signal) => {
|
|
2805
|
+
try {
|
|
2806
|
+
await authCall(rpc, "cancelLogin", { state }, signal);
|
|
2807
|
+
} catch {}
|
|
2721
2808
|
},
|
|
2722
2809
|
pollLogin,
|
|
2723
2810
|
logoutAccounts,
|
|
2724
2811
|
reorderAccounts,
|
|
2725
|
-
setDefault,
|
|
2726
2812
|
setPref
|
|
2727
2813
|
};
|
|
2728
2814
|
};
|
|
2729
|
-
ctx.slots.inject("
|
|
2730
|
-
name: "
|
|
2731
|
-
|
|
2732
|
-
order: 25,
|
|
2733
|
-
label: () => t("nav"),
|
|
2815
|
+
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
|
|
2816
|
+
name: "plugins.bundle.config",
|
|
2817
|
+
key: BUNDLE_NAME,
|
|
2734
2818
|
store,
|
|
2735
2819
|
locale: NS,
|
|
2736
2820
|
inject: injected
|
|
@@ -2747,10 +2831,7 @@ window.__ModuleLoader__.load({
|
|
|
2747
2831
|
fetchAccounts: async () => {
|
|
2748
2832
|
const result = await authCall(rpc, "accounts");
|
|
2749
2833
|
if (!result.ok) return null;
|
|
2750
|
-
return {
|
|
2751
|
-
accounts: result.value.accounts,
|
|
2752
|
-
defaultUid: result.value.defaultUid ?? null
|
|
2753
|
-
};
|
|
2834
|
+
return { accounts: result.value.accounts };
|
|
2754
2835
|
},
|
|
2755
2836
|
fetchSessionAccount: async () => {
|
|
2756
2837
|
const result = await authCall(rpc, "sessionAccount", { sessionId });
|