dsh-codearts 1.2.4 → 1.2.5

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 CHANGED
@@ -3,6 +3,38 @@
3
3
  本文件记录本插件的重要改动。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
4
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
5
5
 
6
+ ## [1.2.5] - 2026-11-05
7
+
8
+ ### 新增
9
+
10
+ - **设置卡片可以整页打开,并带一个可选的侧边栏图标**:DSH 的侧边栏图标列
11
+ (宿主槽位 `sidebar.panellist`)与中间列面板(`main`)配对使用 —— 同一个 id / key
12
+ 才算「点了哪一行就画哪一页」。这一页就是设置里那张卡片,外面套一层「返回对话 +
13
+ 标题 + 说明」,账号 / 模型 / 用量 / 显示四个页签一应俱全,不必每次都绕进设置。
14
+ **默认关闭**,在卡片「显示」页最后一个勾选框里打开:图标列是全宿主共用的资源,
15
+ 每个插件都默认占一格很快就会挤满,所以这一格交给用户自己决定。
16
+ - **`showSidebarPanel` 配置项与 `/api/codearts/dock` 的第三个键**:状态接口从
17
+ `{ credits, queue }` 扩成 `{ credits, queue, sidebar }`,POST 同样接受 `sidebar`。
18
+ 语义和另外两个相反 —— 那两个「缺省即显示」(老配置行为不变),这个是「缺省即关闭」
19
+ (没写过就是不要)。旧后端不返回 `sidebar` 时客户端按关闭处理,不报错。
20
+
21
+ ### 变更
22
+
23
+ - **侧边栏入口的开关落在「注册 / 不注册」上,不是「渲染 null」**:宿主是按槽位的
24
+ 注册条目本身去画导航行的,组件返回 null 只会留下一个空白但可点的按钮。所以客户端
25
+ 改成一个 sync 控制器:先拆掉旧注册,再看开关决定建不建,同一个 id / key 不会注册
26
+ 两份。关掉时如果用户正站在那一页上,先 `selectPanel(null)` 回对话,中间列不会停在
27
+ 一个已经没了的 key 上。`layout` 服务软取(`ctx.get` 缺服务返回 undefined 而不抛),
28
+ 没有它只是少一个返回按钮,不影响整块客户端加载。
29
+
30
+ ### 修复
31
+
32
+ - **槽位注册的异常不再冒成首屏渲染错误横幅**:`ctx.slots.inject` 的回调是延后执行的
33
+ (槽位被宿主声明后才跑),在那里抛出的错会从 renderer 的 `changed()` 里以微任务
34
+ 冒出来,外层的 try/catch 抓不到。现在每个 inject 回调内部各自 try/catch,注册失败
35
+ 返回空 disposer,只留一条 console 记录 —— 老宿主 / 非桌面端没有这两个槽位时,
36
+ 卡片其余部分照常可用。
37
+
6
38
  ## [1.2.4] - 2026-11-03
7
39
 
8
40
  ### 变更
package/README.en.md CHANGED
@@ -27,6 +27,10 @@ Brings Huawei Cloud CodeArts into DeepSeek Harness (DSH), so the models CodeArts
27
27
  which is exactly why a turn had to wait. CodeArts exposes no quota API, so these are the
28
28
  requests this machine sent through the plugin; the card links to the official usage page.
29
29
  - **Image input**: models with vision support accept pasted or dropped images in a chat.
30
+ - **Sidebar icon**: optional. Tick it on the card’s Display tab and a CodeArts icon joins
31
+ the DSH icon column, opening the full-page version of the settings card in the middle
32
+ column (config `showSidebarPanel`; off by default, since that column is shared by the
33
+ whole host).
30
34
  - **Fallback path**: you can also paste a bare security token in the card, for scripts or
31
35
  troubleshooting.
32
36
  - **CLI**: `status` / `models` / `usage` / `identity` / `doctor` / `logout` for checking
package/README.md CHANGED
@@ -14,6 +14,7 @@
14
14
  - **模型清单自动发现**:启动后与每小时各拉一次账号真实可用的模型(内置 / 限时福利 / agent-center 三路合并),失败时退回内置种子清单。
15
15
  - **本机用量**:卡片与 `dsh-codearts usage` 展示今日/累计的请求数与输入输出 token(按模型、按账号),以及每个账号的**会话槽位占用**(占用时正好解释了「为什么刚才要等半分钟」)。CodeArts 没有额度接口,这里只统计本机经插件发出的请求,官方额度明细见卡片上的链接。
16
16
  - **图片输入**:支持视觉的模型可直接在对话里粘贴或拖入图片。
17
+ - **侧边栏图标**:可选。在卡片「显示」页勾一下,DSH 左侧图标列里会多一个 CodeArts,点开直接在中间列显示整页版的设置卡片(配置项 `showSidebarPanel`,默认关闭 —— 那一列是全宿主共用的)。
17
18
  - **降级路径**:也可以在卡片里直接粘贴安全令牌,适用于脚本或排查场景。
18
19
  - **命令行**:`status` / `models` / `usage` / `identity` / `doctor` / `logout` 六个子命令,便于在无图形界面时检查登录状态、发现模型与查用量。
19
20
 
package/lib/bin.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { R as isBenefitModel, V as CodeArtsAccountStore, W as codeartsAccountsPath, d as fetchCallerIdentity, n as codeartsUsagePath, r as discoverModels, t as CodeArtsUsageTracker } from "./usage-DGIuT79_.mjs";
3
3
  import { existsSync, statSync } from "node:fs";
4
4
  //#region src/version.ts
5
- const CODEARTS_VERSION = "1.2.4";
5
+ const CODEARTS_VERSION = "1.2.5";
6
6
  //#endregion
7
7
  //#region src/bin.ts
8
8
  /**
@@ -124,6 +124,9 @@ interface CodeArtsSettingsKey {
124
124
  displayQueueToggle: string;
125
125
  displayNotWritable: string;
126
126
  displayFailed: string;
127
+ displaySidebarTitle: string;
128
+ displaySidebarHint: string;
129
+ displaySidebarToggle: string;
127
130
  queueDock: string;
128
131
  queueDockTitle: string;
129
132
  claimButton: string;
@@ -135,6 +138,8 @@ interface CodeArtsSettingsKey {
135
138
  claimAlready: string;
136
139
  claimUnavailable: string;
137
140
  claimFailed: string;
141
+ panelBack: string;
142
+ panelDesc: string;
138
143
  [key: string]: string;
139
144
  }
140
145
  //#endregion
@@ -157,6 +162,27 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
157
162
  children?: never;
158
163
  };
159
164
  };
165
+ /**
166
+ * 侧边栏那排图标(宿主 ui-sidebar 声明)。每个 list id 对应 main 面板里
167
+ * 同名的 key —— 宿主自己画按钮,只找我们要两样东西:一个显示用的
168
+ * label,和一个 glyph 组件(组件本身就是图标,宿主给 size / active)。
169
+ */
170
+ 'sidebar.panellist': {
171
+ kind: 'list';
172
+ scope: 'root';
173
+ owner: {
174
+ size: number;
175
+ active: boolean;
176
+ };
177
+ };
178
+ /** 中间列的面板(宿主 ui-layout 声明)。key 'conversation' 是保留给对话的。 */
179
+ 'main': {
180
+ kind: 'keyed';
181
+ scope: 'root';
182
+ owner: {
183
+ children?: never;
184
+ };
185
+ };
160
186
  }
161
187
  }
162
188
  declare const name = "dsh-codearts-client";
@@ -22,90 +22,129 @@ function stripModelSuffixes(name) {
22
22
  return base.replace(/\s*[((]\s*(?:(?:免费|福利)(?:\s+x\d+(?:\.\d+)?)?|x\d+(?:\.\d+)?)\s*[))]\s*$/, "").trim();
23
23
  }
24
24
  //#endregion
25
+ //#region src/client/panel-switch.ts
26
+ /**
27
+ * 「要不要在 DSH 侧边栏占一格」这个偏好,浏览器侧的单一真相。
28
+ *
29
+ * 为什么不靠组件返回 null 来隐藏:宿主是按**槽位里的注册条目**(entry metadata)
30
+ * 画侧边栏导航行的 —— 只要注册还在,那一行就在;渲染函数 return null 只会留下一个
31
+ * 「空白但可点」的按钮。所以开关必须落到「注册 / 不注册」上,这里只存那个意图,
32
+ * 真正的注册动作由 index.tsx 的 sync 控制器按它做。
33
+ *
34
+ * 默认 **false**:读不到配置时必须当作关闭。侧边栏那一格是所有插件共用的全局座位,
35
+ * 猜错的代价比「少一个入口」大得多(用户还能从「设置 → 插件」进同一张卡片)。
36
+ */
37
+ let wanted = false;
38
+ /** 当前是否要显示侧边栏入口。 */
39
+ function sidebarPanelWanted() {
40
+ return wanted;
41
+ }
42
+ const listeners = /* @__PURE__ */ new Set();
43
+ /**
44
+ * 改开关。值没变就直接返回 —— 调用方会在每次刷新状态时调用它,
45
+ * 无变化的重注册会让侧边栏闪一下。
46
+ */
47
+ function setSidebarPanelWanted(next) {
48
+ if (wanted === next) return;
49
+ wanted = next;
50
+ for (const listener of [...listeners]) try {
51
+ listener();
52
+ } catch (error) {
53
+ console.error("[dsh-codearts] sidebar panel listener failed:", error);
54
+ }
55
+ }
56
+ /** 订阅开关变化,返回取消订阅函数。 */
57
+ function subscribeSidebarPanelWanted(listener) {
58
+ listeners.add(listener);
59
+ return () => {
60
+ listeners.delete(listener);
61
+ };
62
+ }
63
+ //#endregion
25
64
  //#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPluginCard.module.css.mjs
26
- const css = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex:none;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}";
27
- const tagId = "dsh-codearts/CodeArtsPluginCard.module.css";
28
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
65
+ const css$1 = ".xoziZG_card{border:.5px solid var(--dsw-alias-settings-card-stroke);border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-settings-card-fill);max-width:720px}.xoziZG_header{align-items:flex-start;gap:12px;padding:14px 16px;display:flex}.xoziZG_headText{flex-direction:column;flex:1;gap:6px;min-width:0;display:flex}.xoziZG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px}.xoziZG_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.xoziZG_statusLine{color:var(--dsw-alias-label-primary);align-items:center;gap:6px;font-size:14px;font-weight:500;line-height:22px;display:inline-flex}.xoziZG_meta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:18px}.xoziZG_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding:4px 0 16px}.xoziZG_tabs{margin-top:12px}.xoziZG_tabPanel{padding-top:2px}.xoziZG_accountToolbar{gap:8px;margin-top:12px;display:flex}.xoziZG_accountToolbar>*{flex:1}.xoziZG_manualForm{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:12px}.xoziZG_accountCard{flex-direction:column;gap:10px;margin-top:12px;display:flex}.xoziZG_accountEntry{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-2)}.xoziZG_accountRow{align-items:center;gap:10px;padding:12px;display:flex}.xoziZG_claimAllRow{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;padding:10px 12px 0;display:flex}.xoziZG_avatar{background:var(--dsw-alias-bg-layer-3);width:32px;height:32px;color:var(--dsw-alias-label-primary);border-radius:50%;flex:none;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:inline-flex}.xoziZG_accountInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.xoziZG_accountNameRow{align-items:center;gap:6px;min-width:0;display:flex}.xoziZG_accountName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;overflow:hidden}.xoziZG_accountRowActions{flex:none;gap:6px;display:flex}.xoziZG_accountHint{color:var(--dsw-alias-label-tertiary);margin:0;padding:0 12px 12px;font-size:12px;line-height:18px}.xoziZG_creditBlock{border-top:.5px solid var(--dsw-alias-border-l2);padding:12px}.xoziZG_balanceRow{flex-wrap:wrap;align-items:baseline;gap:6px;display:flex}.xoziZG_balance{color:var(--dsw-alias-label-primary);letter-spacing:-.02em;font-variant-numeric:tabular-nums;font-size:28px;font-weight:600;line-height:34px}.xoziZG_balanceUnit{color:var(--dsw-alias-label-secondary);font-size:12px}.xoziZG_balanceMeta{color:var(--dsw-alias-label-tertiary);margin-left:2px;font-size:12px}.xoziZG_updated{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.xoziZG_creditRows{flex-direction:column;gap:4px;margin-top:8px;display:flex}.xoziZG_creditRow{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:space-between;align-items:baseline;gap:12px;font-size:12px;line-height:18px;display:flex}.xoziZG_usageBar{background:var(--dsw-alias-border-l2);border-radius:2px;height:4px;margin-top:4px;display:block;overflow:hidden}.xoziZG_usageFill{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .2s;display:block}.xoziZG_expiryRow{margin-top:2px}.xoziZG_expiryLabel{color:var(--dsw-alias-state-warn-label)}.xoziZG_bar{background:var(--dsw-alias-bg-layer-3);border-radius:2px;height:4px;margin-top:6px;display:block;overflow:hidden}.xoziZG_barFill{background:var(--dsw-alias-state-warn-primary);border-radius:2px;height:100%;display:block}.xoziZG_creditLink{margin-top:8px;display:inline-block}.xoziZG_creditFooter{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:8px;margin-top:12px;padding-top:10px;display:flex}.xoziZG_creditHint{color:var(--dsw-alias-label-tertiary);margin:8px 0 0;font-size:12px;line-height:18px}.xoziZG_section{margin-top:16px}.xoziZG_sectionHead{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.xoziZG_sectionLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500}.xoziZG_count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:12px}.xoziZG_hint{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px;line-height:20px}.xoziZG_error{color:var(--dsw-alias-state-error-primary);margin:10px 0 0;font-size:13px;line-height:20px}.xoziZG_actions{flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;display:flex}.xoziZG_danger{color:var(--dsw-alias-state-error-primary)}.xoziZG_link{appearance:none;color:var(--dsw-alias-brand-text);font:inherit;text-align:left;word-break:break-all;cursor:pointer;background:0 0;border:none;padding:0;font-size:12px}.xoziZG_link:hover{text-decoration:underline}.xoziZG_choices{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_choiceRow{border-radius:var(--dsw-radius-sm);align-items:center;gap:8px;margin:0 -6px;padding:5px 6px;display:flex}.xoziZG_choiceRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_statGrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin:10px 0 14px;display:grid}.xoziZG_statCard{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);flex-direction:column;gap:1px;padding:8px 10px;display:flex}.xoziZG_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.xoziZG_statValue{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:15px;line-height:20px}.xoziZG_statSub{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;line-height:16px}.xoziZG_modelChart{flex-direction:column;gap:2px;margin-top:8px;display:flex}.xoziZG_modelRow{font-variant-numeric:tabular-nums;border-radius:6px;grid-template-columns:minmax(0,1.2fr) minmax(48px,1fr) 56px 52px 64px;align-items:center;gap:8px;padding:4px 0;display:grid;position:relative}.xoziZG_modelRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.xoziZG_usageTip{z-index:5;border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);min-width:180px;max-width:260px;color:var(--dsw-alias-label-secondary);text-align:left;font-variant-numeric:tabular-nums;pointer-events:none;padding:8px 10px;font-size:12px;line-height:1.9;position:absolute;bottom:calc(100% + 6px);right:0;box-shadow:0 10px 28px #00000073}.xoziZG_usageTipName{max-width:240px;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_usageTipSep{background:var(--dsw-alias-border-l2);height:1px;margin:4px 0}.xoziZG_usageTipRow{justify-content:space-between;gap:24px;display:flex}.xoziZG_usageTipRow span:last-child{color:var(--dsw-alias-label-primary);font-weight:600}.xoziZG_modelName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:18px;overflow:hidden}.xoziZG_modelTrack{background:var(--dsw-alias-border-l2);border-radius:4px;height:8px;display:block;overflow:hidden}.xoziZG_modelFill{background:var(--dsw-alias-brand-primary);border-radius:4px;height:100%;transition:width .16s;display:block}.xoziZG_modelTokens,.xoziZG_modelShare,.xoziZG_modelRequests{color:var(--dsw-alias-label-secondary);text-align:right;white-space:nowrap;font-size:11px;line-height:16px}.xoziZG_modelRequests{color:var(--dsw-alias-label-tertiary)}.xoziZG_check{flex:1;min-width:0}.xoziZG_check>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.xoziZG_manual{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-md);margin-top:12px;padding:0 12px}.xoziZG_manual[open]{padding-bottom:12px}.xoziZG_manualSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;padding:9px 0;font-size:13px;list-style:none;display:flex}.xoziZG_manualSummary::-webkit-details-marker{display:none}.xoziZG_field{flex-direction:column;gap:5px;margin-top:10px;display:flex}.xoziZG_fieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px}.xoziZG_area{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;color:var(--dsw-alias-label-primary);padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:20px}.xoziZG_area::placeholder{color:var(--dsw-alias-label-dimmed)}.xoziZG_area:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}";
66
+ const tagId$1 = "dsh-codearts/CodeArtsPluginCard.module.css";
67
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
29
68
  const tag = document.createElement("style");
30
69
  tag.dataset.plugin = "dsh-codearts";
31
- tag.dataset.pluginCss = tagId;
32
- tag.textContent = css;
70
+ tag.dataset.pluginCss = tagId$1;
71
+ tag.textContent = css$1;
33
72
  document.head.appendChild(tag);
34
73
  }
35
74
  var CodeArtsPluginCard_module_css_default = {
36
- "field": "xoziZG_field",
37
- "manualForm": "xoziZG_manualForm",
38
- "accountRow": "xoziZG_accountRow",
39
- "section": "xoziZG_section",
40
- "expiryLabel": "xoziZG_expiryLabel",
75
+ "claimAllRow": "xoziZG_claimAllRow",
76
+ "bar": "xoziZG_bar",
77
+ "updated": "xoziZG_updated",
41
78
  "check": "xoziZG_check",
42
- "balance": "xoziZG_balance",
43
- "accountToolbar": "xoziZG_accountToolbar",
44
- "barFill": "xoziZG_barFill",
45
- "statLabel": "xoziZG_statLabel",
46
- "meta": "xoziZG_meta",
47
- "accountNameRow": "xoziZG_accountNameRow",
48
- "expiryRow": "xoziZG_expiryRow",
49
- "balanceUnit": "xoziZG_balanceUnit",
50
- "accountInfo": "xoziZG_accountInfo",
51
- "hint": "xoziZG_hint",
52
- "count": "xoziZG_count",
79
+ "expiryLabel": "xoziZG_expiryLabel",
80
+ "creditFooter": "xoziZG_creditFooter",
81
+ "accountName": "xoziZG_accountName",
53
82
  "choices": "xoziZG_choices",
54
- "usageFill": "xoziZG_usageFill",
55
83
  "card": "xoziZG_card",
84
+ "tabPanel": "xoziZG_tabPanel",
85
+ "sectionHead": "xoziZG_sectionHead",
86
+ "usageTipRow": "xoziZG_usageTipRow",
87
+ "fieldLabel": "xoziZG_fieldLabel",
88
+ "desc": "xoziZG_desc",
56
89
  "usageTipName": "xoziZG_usageTipName",
57
- "balanceRow": "xoziZG_balanceRow",
58
- "creditBlock": "xoziZG_creditBlock",
59
- "header": "xoziZG_header",
60
- "statSub": "xoziZG_statSub",
61
- "usageTip": "xoziZG_usageTip",
90
+ "modelFill": "xoziZG_modelFill",
91
+ "modelTrack": "xoziZG_modelTrack",
92
+ "hint": "xoziZG_hint",
93
+ "headText": "xoziZG_headText",
94
+ "creditRow": "xoziZG_creditRow",
95
+ "accountInfo": "xoziZG_accountInfo",
96
+ "modelRow": "xoziZG_modelRow",
97
+ "usageTipSep": "xoziZG_usageTipSep",
98
+ "creditHint": "xoziZG_creditHint",
62
99
  "modelRequests": "xoziZG_modelRequests",
100
+ "statGrid": "xoziZG_statGrid",
101
+ "accountCard": "xoziZG_accountCard",
102
+ "body": "xoziZG_body",
103
+ "name": "xoziZG_name",
104
+ "danger": "xoziZG_danger",
63
105
  "usageBar": "xoziZG_usageBar",
64
- "bar": "xoziZG_bar",
65
- "creditRow": "xoziZG_creditRow",
106
+ "accountRowActions": "xoziZG_accountRowActions",
107
+ "modelShare": "xoziZG_modelShare",
66
108
  "sectionLabel": "xoziZG_sectionLabel",
109
+ "field": "xoziZG_field",
110
+ "statusLine": "xoziZG_statusLine",
111
+ "area": "xoziZG_area",
67
112
  "accountEntry": "xoziZG_accountEntry",
68
- "modelTrack": "xoziZG_modelTrack",
69
- "link": "xoziZG_link",
70
- "updated": "xoziZG_updated",
71
- "desc": "xoziZG_desc",
72
- "avatar": "xoziZG_avatar",
73
- "creditHint": "xoziZG_creditHint",
74
- "tabPanel": "xoziZG_tabPanel",
75
- "fieldLabel": "xoziZG_fieldLabel",
76
- "modelName": "xoziZG_modelName",
77
- "danger": "xoziZG_danger",
113
+ "choiceRow": "xoziZG_choiceRow",
114
+ "accountRow": "xoziZG_accountRow",
78
115
  "statValue": "xoziZG_statValue",
79
- "area": "xoziZG_area",
80
- "claimAllRow": "xoziZG_claimAllRow",
81
- "tabs": "xoziZG_tabs",
82
- "usageTipSep": "xoziZG_usageTipSep",
83
- "name": "xoziZG_name",
84
- "headText": "xoziZG_headText",
85
- "accountRowActions": "xoziZG_accountRowActions",
86
- "sectionHead": "xoziZG_sectionHead",
87
- "modelRow": "xoziZG_modelRow",
88
- "modelFill": "xoziZG_modelFill",
89
- "accountHint": "xoziZG_accountHint",
90
- "modelChart": "xoziZG_modelChart",
116
+ "manualForm": "xoziZG_manualForm",
117
+ "balance": "xoziZG_balance",
118
+ "statLabel": "xoziZG_statLabel",
91
119
  "error": "xoziZG_error",
92
- "body": "xoziZG_body",
93
- "manualSummary": "xoziZG_manualSummary",
120
+ "barFill": "xoziZG_barFill",
121
+ "creditLink": "xoziZG_creditLink",
122
+ "avatar": "xoziZG_avatar",
94
123
  "balanceMeta": "xoziZG_balanceMeta",
95
- "statGrid": "xoziZG_statGrid",
96
- "choiceRow": "xoziZG_choiceRow",
97
- "modelShare": "xoziZG_modelShare",
98
- "accountName": "xoziZG_accountName",
124
+ "creditBlock": "xoziZG_creditBlock",
125
+ "manualSummary": "xoziZG_manualSummary",
126
+ "actions": "xoziZG_actions",
127
+ "accountToolbar": "xoziZG_accountToolbar",
128
+ "balanceRow": "xoziZG_balanceRow",
129
+ "meta": "xoziZG_meta",
130
+ "expiryRow": "xoziZG_expiryRow",
131
+ "count": "xoziZG_count",
132
+ "statCard": "xoziZG_statCard",
133
+ "usageFill": "xoziZG_usageFill",
99
134
  "modelTokens": "xoziZG_modelTokens",
100
- "creditLink": "xoziZG_creditLink",
101
- "creditFooter": "xoziZG_creditFooter",
102
- "manual": "xoziZG_manual",
103
- "statusLine": "xoziZG_statusLine",
135
+ "tabs": "xoziZG_tabs",
136
+ "link": "xoziZG_link",
104
137
  "creditRows": "xoziZG_creditRows",
105
- "statCard": "xoziZG_statCard",
106
- "accountCard": "xoziZG_accountCard",
107
- "usageTipRow": "xoziZG_usageTipRow",
108
- "actions": "xoziZG_actions"
138
+ "modelChart": "xoziZG_modelChart",
139
+ "statSub": "xoziZG_statSub",
140
+ "accountNameRow": "xoziZG_accountNameRow",
141
+ "balanceUnit": "xoziZG_balanceUnit",
142
+ "manual": "xoziZG_manual",
143
+ "accountHint": "xoziZG_accountHint",
144
+ "header": "xoziZG_header",
145
+ "usageTip": "xoziZG_usageTip",
146
+ "section": "xoziZG_section",
147
+ "modelName": "xoziZG_modelName"
109
148
  };
110
149
  //#endregion
111
150
  //#region src/client/CodeArtsPluginCard.tsx
@@ -155,10 +194,14 @@ function claimMessagesOf(data, accountIds, t) {
155
194
  for (const id of accountIds) out[id] = claimText(data, t);
156
195
  return out;
157
196
  }
158
- /** 开关的兜底值:后端没这条路由(老版本)时按「都显示」渲染,与原有行为一致。 */
197
+ /**
198
+ * 开关的兜底值:后端没这条路由(老版本)时按「都显示」渲染,与原有行为一致。
199
+ * 侧边栏那一格相反 —— 缺省关闭。
200
+ */
159
201
  const DOCK_DEFAULT = {
160
202
  credits: true,
161
- queue: true
203
+ queue: true,
204
+ sidebar: false
162
205
  };
163
206
  /** 一个 Tab 面板;未选中的用 hidden 留在 DOM 里,草稿和滚动位置都别丢。 */
164
207
  function TabPanel({ id, labelledBy, active, children }) {
@@ -650,14 +693,21 @@ function CodeArtsPluginCard({ t }) {
650
693
  const res = await fetch("/api/codearts/dock", { headers: { Accept: "application/json" } });
651
694
  if (!res.ok) return;
652
695
  const data = await res.json();
653
- if (data.dock !== void 0) setDock(data.dock);
696
+ if (data.dock !== void 0) {
697
+ const next = {
698
+ ...DOCK_DEFAULT,
699
+ ...data.dock
700
+ };
701
+ setDock(next);
702
+ setSidebarPanelWanted(next.sidebar);
703
+ }
654
704
  setDockWritable(data.writable === true);
655
705
  } catch {}
656
706
  }
657
707
  /**
658
708
  * 改一个开关:先按新值渲染,写失败再退回去。
659
709
  *
660
- * 这里不像模型勾选那样攒草稿再点保存 —— 只有两个布尔,攒草稿反而让用户猜
710
+ * 这里不像模型勾选那样攒草稿再点保存 —— 只有几个布尔,攒草稿反而让用户猜
661
711
  * 「我刚才那一下到底生效没有」。
662
712
  */
663
713
  async function toggleDock(key, on) {
@@ -668,6 +718,7 @@ function CodeArtsPluginCard({ t }) {
668
718
  });
669
719
  setDockSaving(true);
670
720
  setDockError(null);
721
+ if (key === "sidebar") setSidebarPanelWanted(on);
671
722
  try {
672
723
  const res = await fetch("/api/codearts/dock", {
673
724
  method: "POST",
@@ -682,9 +733,17 @@ function CodeArtsPluginCard({ t }) {
682
733
  throw new Error(typeof data.error === "string" ? data.error : `HTTP ${res.status}`);
683
734
  }
684
735
  const data = await res.json();
685
- if (data.dock !== void 0) setDock(data.dock);
736
+ if (data.dock !== void 0) {
737
+ const next = {
738
+ ...DOCK_DEFAULT,
739
+ ...data.dock
740
+ };
741
+ setDock(next);
742
+ setSidebarPanelWanted(next.sidebar);
743
+ }
686
744
  } catch (error) {
687
745
  setDock(previous);
746
+ if (key === "sidebar") setSidebarPanelWanted(previous.sidebar);
688
747
  setDockError(error instanceof Error ? error.message : String(error));
689
748
  } finally {
690
749
  setDockSaving(false);
@@ -1361,11 +1420,11 @@ function CodeArtsPluginCard({ t }) {
1361
1420
  t
1362
1421
  })
1363
1422
  }),
1364
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabPanel, {
1423
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TabPanel, {
1365
1424
  id: panelId("display"),
1366
1425
  labelledBy: tabId("display"),
1367
1426
  active: activeTab === "display",
1368
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1427
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1369
1428
  className: CodeArtsPluginCard_module_css_default.section,
1370
1429
  children: [
1371
1430
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1410,7 +1469,35 @@ function CodeArtsPluginCard({ t }) {
1410
1469
  children: t("displayFailed", { message: dockError })
1411
1470
  })
1412
1471
  ]
1413
- })
1472
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1473
+ className: CodeArtsPluginCard_module_css_default.section,
1474
+ children: [
1475
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1476
+ className: CodeArtsPluginCard_module_css_default.sectionHead,
1477
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1478
+ className: CodeArtsPluginCard_module_css_default.sectionLabel,
1479
+ children: t("displaySidebarTitle")
1480
+ })
1481
+ }),
1482
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1483
+ className: CodeArtsPluginCard_module_css_default.hint,
1484
+ children: t("displaySidebarHint")
1485
+ }),
1486
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1487
+ className: CodeArtsPluginCard_module_css_default.choices,
1488
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1489
+ className: CodeArtsPluginCard_module_css_default.choiceRow,
1490
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Checkbox, {
1491
+ className: CodeArtsPluginCard_module_css_default.check,
1492
+ checked: dock.sidebar,
1493
+ disabled: !dockWritable || dockSaving,
1494
+ onChange: (on) => void toggleDock("sidebar", on),
1495
+ label: t("displaySidebarToggle")
1496
+ })
1497
+ })
1498
+ })
1499
+ ]
1500
+ })]
1414
1501
  })
1415
1502
  ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1416
1503
  className: CodeArtsPluginCard_module_css_default.section,
@@ -1704,7 +1791,8 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
1704
1791
  const [modelInfo, setModelInfo] = (0, react.useState)({});
1705
1792
  const [flags, setFlags] = (0, react.useState)({
1706
1793
  credits: true,
1707
- queue: true
1794
+ queue: true,
1795
+ sidebar: false
1708
1796
  });
1709
1797
  const [queued, setQueued] = (0, react.useState)(null);
1710
1798
  const [anchor, setAnchor] = (0, react.useState)(null);
@@ -1740,7 +1828,8 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
1740
1828
  if (data === void 0 || !mounted.current) return;
1741
1829
  setFlags(data.dock ?? {
1742
1830
  credits: true,
1743
- queue: true
1831
+ queue: true,
1832
+ sidebar: false
1744
1833
  });
1745
1834
  setRows(rowsOf(data));
1746
1835
  setModelInfo(Object.fromEntries((data.models ?? []).map((model) => [model.id, {
@@ -2048,6 +2137,84 @@ function CodeArtsCreditDock({ useProjection, t, zone = "dock" }) {
2048
2137
  });
2049
2138
  }
2050
2139
  //#endregion
2140
+ //#region \0dsh-css:/home/runner/work/dsh-codearts/dsh-codearts/src/client/CodeArtsPanel.module.css.mjs
2141
+ const css = ".Z66cgG_page{box-sizing:border-box;height:100%;min-height:0;padding:calc(28px + var(--dsh-frame-top-clearance,0px)) clamp(24px, 4vw, 48px) 48px;color:var(--dsw-alias-label-primary);flex-direction:column;display:flex;overflow:auto}.Z66cgG_head{flex-direction:column;gap:6px;width:100%;max-width:860px;margin:0 auto;display:flex}.Z66cgG_back{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);align-self:flex-start;align-items:center;gap:6px;margin-bottom:10px;padding:5px 12px;font-size:13px;line-height:20px;display:inline-flex}.Z66cgG_back:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.Z66cgG_backCaret{border-bottom:1.6px solid;border-left:1.6px solid;width:7px;height:7px;display:inline-block;transform:rotate(45deg)}.Z66cgG_title{margin:0;font-size:20px;font-weight:600;line-height:1.4}.Z66cgG_desc{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}.Z66cgG_body{width:100%;max-width:860px;margin:20px auto 0}.Z66cgG_icon{flex:none;display:block}";
2142
+ const tagId = "dsh-codearts/CodeArtsPanel.module.css";
2143
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2144
+ const tag = document.createElement("style");
2145
+ tag.dataset.plugin = "dsh-codearts";
2146
+ tag.dataset.pluginCss = tagId;
2147
+ tag.textContent = css;
2148
+ document.head.appendChild(tag);
2149
+ }
2150
+ var CodeArtsPanel_module_css_default = {
2151
+ "icon": "Z66cgG_icon",
2152
+ "backCaret": "Z66cgG_backCaret",
2153
+ "title": "Z66cgG_title",
2154
+ "head": "Z66cgG_head",
2155
+ "desc": "Z66cgG_desc",
2156
+ "back": "Z66cgG_back",
2157
+ "page": "Z66cgG_page",
2158
+ "body": "Z66cgG_body"
2159
+ };
2160
+ //#endregion
2161
+ //#region src/client/CodeArtsPanel.tsx
2162
+ /** 侧边栏按钮里的图标。宿主按 { size, active } 渲染,我们用 currentColor 跟随主题。 */
2163
+ function CodeArtsPanelIcon({ size }) {
2164
+ const px = typeof size === "number" && size > 0 ? size : 16;
2165
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2166
+ className: CodeArtsPanel_module_css_default.icon,
2167
+ width: px,
2168
+ height: px,
2169
+ viewBox: "0 0 16 16",
2170
+ fill: "none",
2171
+ "aria-hidden": "true",
2172
+ focusable: "false",
2173
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2174
+ d: "M9.9 2.6a1.4 1.4 0 0 1 2 0l1.5 1.5a1.4 1.4 0 0 1 0 2l-6.4 6.4-3.6.9a.6.6 0 0 1-.7-.7l.9-3.6 6.3-6.5Z",
2175
+ stroke: "currentColor",
2176
+ strokeWidth: "1.2",
2177
+ strokeLinejoin: "round"
2178
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
2179
+ d: "M8.9 3.6 12.4 7.1",
2180
+ stroke: "currentColor",
2181
+ strokeWidth: "1.2",
2182
+ strokeLinecap: "round"
2183
+ })]
2184
+ });
2185
+ }
2186
+ /** 侧边栏入口页:一个返回按钮 + 标题,正文直接复用设置里那张卡片。 */
2187
+ function CodeArtsPanelPage({ t, backToConversation }) {
2188
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2189
+ className: CodeArtsPanel_module_css_default.page,
2190
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2191
+ className: CodeArtsPanel_module_css_default.head,
2192
+ children: [
2193
+ backToConversation !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2194
+ type: "button",
2195
+ className: CodeArtsPanel_module_css_default.back,
2196
+ onClick: backToConversation,
2197
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2198
+ className: CodeArtsPanel_module_css_default.backCaret,
2199
+ "aria-hidden": "true"
2200
+ }), t("panelBack")]
2201
+ }),
2202
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
2203
+ className: CodeArtsPanel_module_css_default.title,
2204
+ children: t("cardTitle")
2205
+ }),
2206
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2207
+ className: CodeArtsPanel_module_css_default.desc,
2208
+ children: t("panelDesc")
2209
+ })
2210
+ ]
2211
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2212
+ className: CodeArtsPanel_module_css_default.body,
2213
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeArtsPluginCard, { t })
2214
+ })]
2215
+ });
2216
+ }
2217
+ //#endregion
2051
2218
  //#region src/client/locales.ts
2052
2219
  const zh = {
2053
2220
  tabLabel: "CodeArts",
@@ -2170,6 +2337,9 @@ const zh = {
2170
2337
  displayQueueToggle: "显示上游排队位置",
2171
2338
  displayNotWritable: "这个宿主没给插件开配置存储,开关只能看不能改。",
2172
2339
  displayFailed: "保存失败:{message}",
2340
+ displaySidebarTitle: "侧边栏图标",
2341
+ displaySidebarHint: "勾上以后,DSH 左侧那一列图标里会多一个 CodeArts,点它直接在中间列打开当前这一页,不必每次都绕进设置。默认不勾:这列图标是全宿主共用的,每个插件都来占一格很快就挤满了。改完立刻生效,没有保存步骤。",
2342
+ displaySidebarToggle: "在侧边栏图标列显示 CodeArts",
2173
2343
  queueDock: "排队第 {position} 位",
2174
2344
  queueDockTitle: "上游排队:{model} · 第 {position} 位 / 共 {length} 条",
2175
2345
  claimButton: "签到领积分",
@@ -2180,7 +2350,9 @@ const zh = {
2180
2350
  claimDone: "已领取 {amount} 积分",
2181
2351
  claimAlready: "今日已领,明天再来",
2182
2352
  claimUnavailable: "这个账号当前没有可领的签到活动",
2183
- claimFailed: "领取失败:{message}"
2353
+ claimFailed: "领取失败:{message}",
2354
+ panelBack: "返回对话",
2355
+ panelDesc: "账号、模型开关与用量都在这一页里管,和设置 → 插件里那张卡片是同一份状态。"
2184
2356
  };
2185
2357
  const en = {
2186
2358
  tabLabel: "CodeArts",
@@ -2303,6 +2475,9 @@ const en = {
2303
2475
  displayQueueToggle: "Show the upstream queue position",
2304
2476
  displayNotWritable: "This host gives the plugin nowhere to persist settings, so the switches are read-only.",
2305
2477
  displayFailed: "Failed to save: {message}",
2478
+ displaySidebarTitle: "Sidebar icon",
2479
+ displaySidebarHint: "Once checked, a CodeArts icon joins the icon column on the left of DSH and opens this very page in the middle column, so you do not have to go through Settings each time. Off by default: that column is shared by the whole host, and it fills up quickly if every plugin claims a slot. Takes effect immediately — there is nothing to save.",
2480
+ displaySidebarToggle: "Show CodeArts in the sidebar icon column",
2306
2481
  queueDock: "Queued #{position}",
2307
2482
  queueDockTitle: "Upstream queue: {model} · position {position} of {length}",
2308
2483
  claimButton: "Claim daily credits",
@@ -2313,13 +2488,32 @@ const en = {
2313
2488
  claimDone: "Claimed {amount} credits",
2314
2489
  claimAlready: "Already claimed today — come back tomorrow",
2315
2490
  claimUnavailable: "No check-in campaign available for this account",
2316
- claimFailed: "Claim failed: {message}"
2491
+ claimFailed: "Claim failed: {message}",
2492
+ panelBack: "Back to chat",
2493
+ panelDesc: "Manage accounts, model switches and usage here — same state as the card under Settings → Plugins."
2317
2494
  };
2318
2495
  //#endregion
2319
2496
  //#region src/client/index.tsx
2320
2497
  const name = "dsh-codearts-client";
2321
2498
  const inject = ["slots", "locale"];
2499
+ /**
2500
+ * 侧边栏按钮的 id,同时也是中间列面板的 key —— 宿主靠这两个同名值把
2501
+ * 「点了哪一行」和「中间列画哪一页」配对。
2502
+ */
2503
+ const PANEL_ID = "dsh-codearts";
2322
2504
  function apply(ctx) {
2505
+ /**
2506
+ * 回对话页。软取 layout 服务:`ctx.get` 在服务没提供时返回 undefined 而不会抛,
2507
+ * 所以老宿主/非桌面端只是没有返回按钮,不影响整块 client 加载。
2508
+ * 故意不写进 `inject` —— 依赖缺失会让 apply 整个不跑。
2509
+ */
2510
+ const backToConversation = () => {
2511
+ try {
2512
+ ctx.get("layout")?.selectPanel?.(null);
2513
+ } catch (error) {
2514
+ console.error("[dsh-codearts] failed to switch back to conversation:", error);
2515
+ }
2516
+ };
2323
2517
  try {
2324
2518
  const namespace = "settings.codearts";
2325
2519
  ctx.effect(() => ctx.locale.register(namespace, {
@@ -2352,6 +2546,85 @@ function apply(ctx) {
2352
2546
  zone: "dock"
2353
2547
  })
2354
2548
  }, CodeArtsCreditDock));
2549
+ /** 每次 claim 拿到的 inject disposer;拆的时候逐个调用(连带注销里面的注册)。 */
2550
+ const panelClaims = [];
2551
+ const dropPanelSlots = () => {
2552
+ for (const dispose of panelClaims.splice(0)) try {
2553
+ dispose();
2554
+ } catch (error) {
2555
+ console.error("[dsh-codearts] failed to release sidebar panel:", error);
2556
+ }
2557
+ };
2558
+ const syncPanelRegistration = () => {
2559
+ dropPanelSlots();
2560
+ if (!sidebarPanelWanted()) return;
2561
+ try {
2562
+ panelClaims.push(ctx.slots.inject("sidebar.panellist", () => {
2563
+ try {
2564
+ return ctx.slots.register({
2565
+ name: "sidebar.panellist",
2566
+ id: PANEL_ID,
2567
+ order: 50,
2568
+ label: () => t("tabLabel"),
2569
+ locale: namespace
2570
+ }, CodeArtsPanelIcon);
2571
+ } catch (error) {
2572
+ console.error("[dsh-codearts] sidebar panel entry unavailable:", error);
2573
+ return () => {};
2574
+ }
2575
+ }));
2576
+ } catch (error) {
2577
+ console.error("[dsh-codearts] sidebar panel slot unavailable:", error);
2578
+ }
2579
+ try {
2580
+ panelClaims.push(ctx.slots.inject("main", () => {
2581
+ try {
2582
+ return ctx.slots.register({
2583
+ name: "main",
2584
+ key: PANEL_ID,
2585
+ locale: namespace,
2586
+ inject: () => ({
2587
+ t,
2588
+ backToConversation
2589
+ })
2590
+ }, CodeArtsPanelPage);
2591
+ } catch (error) {
2592
+ console.error("[dsh-codearts] main panel page unavailable:", error);
2593
+ return () => {};
2594
+ }
2595
+ }));
2596
+ } catch (error) {
2597
+ console.error("[dsh-codearts] main panel slot unavailable:", error);
2598
+ }
2599
+ };
2600
+ /**
2601
+ * 开关关掉时如果用户正站在那一页上,先回对话 —— 否则中间列会留在
2602
+ * 一个已经没了的 key 上。软取 layout:没有这个服务就跳过。
2603
+ */
2604
+ const leavePanelIfActive = () => {
2605
+ try {
2606
+ const layout = ctx.get("layout");
2607
+ if (layout?.panelInfo?.getSnapshot?.()?.activePanelId === PANEL_ID) layout.selectPanel?.(null);
2608
+ } catch {}
2609
+ };
2610
+ ctx.effect(() => {
2611
+ const off = subscribeSidebarPanelWanted(() => {
2612
+ if (!sidebarPanelWanted()) leavePanelIfActive();
2613
+ syncPanelRegistration();
2614
+ });
2615
+ syncPanelRegistration();
2616
+ return () => {
2617
+ off();
2618
+ dropPanelSlots();
2619
+ };
2620
+ }, "dsh-codearts: sidebar panel opt-in");
2621
+ (async () => {
2622
+ try {
2623
+ const res = await fetch("/api/codearts/dock", { headers: { Accept: "application/json" } });
2624
+ if (!res.ok) return;
2625
+ setSidebarPanelWanted((await res.json()).dock?.sidebar === true);
2626
+ } catch {}
2627
+ })();
2355
2628
  } catch (error) {
2356
2629
  console.error("[dsh-codearts] client card failed to load (host provider unaffected):", error);
2357
2630
  }
package/lib/index.d.mts CHANGED
@@ -1615,6 +1615,13 @@ interface Config {
1615
1615
  showCreditDock?: boolean;
1616
1616
  /** 等上游开流时那行「排队第 N 位」是否显示。缺省 = 显示。 */
1617
1617
  showQueueDock?: boolean;
1618
+ /**
1619
+ * 是否在 DSH 侧边栏的图标列里加一个 CodeArts 图标(点开在中间列显示整页版卡片)。
1620
+ *
1621
+ * 缺省 = **不显示**:图标列是全宿主共用的资源,每个插件都默认占一格很快就会挤满,
1622
+ * 而「设置 → 插件」里本来就能看到同一张卡片,所以这一格交给用户自己决定要不要。
1623
+ */
1624
+ showSidebarPanel?: boolean;
1618
1625
  }
1619
1626
  declare const Config: z<Config>;
1620
1627
  declare function apply(ctx: Context, rawConfig: Config): void;
package/lib/index.mjs CHANGED
@@ -1527,10 +1527,14 @@ function modelBadgesOf(models) {
1527
1527
  };
1528
1528
  });
1529
1529
  }
1530
- /** 开关的默认值:没有 settings provider(或老配置没这两个键)时保持原有行为 —— 都显示。 */
1530
+ /**
1531
+ * 开关的默认值:没有 settings provider(或老配置没这两个键)时保持原有行为 ——
1532
+ * 底部两行都显示;侧边栏相反,缺省不开(那一格是所有插件共用的全局座位)。
1533
+ */
1531
1534
  const DEFAULT_DOCK_FLAGS = {
1532
1535
  credits: true,
1533
- queue: true
1536
+ queue: true,
1537
+ sidebar: false
1534
1538
  };
1535
1539
  /**
1536
1540
  * 把逐账号的领取结果汇总成一条:HTTP 层只看 ok,卡片看 results 逐号展示。
@@ -1761,9 +1765,13 @@ function dockHandler(deps) {
1761
1765
  }
1762
1766
  try {
1763
1767
  const body = JSON.parse(await readBody(req));
1764
- const touched = ["credits", "queue"].filter((key) => body[key] !== void 0);
1768
+ const touched = [
1769
+ "credits",
1770
+ "queue",
1771
+ "sidebar"
1772
+ ].filter((key) => body[key] !== void 0);
1765
1773
  if (touched.length === 0 || touched.some((key) => typeof body[key] !== "boolean")) {
1766
- json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean}" });
1774
+ json(res, 400, { error: "expected {\"credits\"?: boolean, \"queue\"?: boolean, \"sidebar\"?: boolean}" });
1767
1775
  return;
1768
1776
  }
1769
1777
  if (!await deps.setDock(Object.fromEntries(touched.map((key) => [key, body[key]])))) {
@@ -2404,7 +2412,8 @@ function unwrapConfig(value) {
2404
2412
  const Config = z.object({
2405
2413
  enabledModels: z.array(z.string()).description("Model ids offered in the model pickers (empty means every model)").volatile(),
2406
2414
  showCreditDock: z.boolean().default(true).description("Show the remaining-credits line under the chat input box").volatile(),
2407
- showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile()
2415
+ showQueueDock: z.boolean().default(true).description("Show the upstream queue position under the chat input box").volatile(),
2416
+ showSidebarPanel: z.boolean().default(false).description("Show a CodeArts icon in the DSH sidebar icon column, opening this page in the middle column").volatile()
2408
2417
  });
2409
2418
  function settingsCompatNamespace(ctx) {
2410
2419
  return resolveSettingsNamespaceCompat(ctx, ctx.get("settings"), CODEARTS_SETTINGS_NS);
@@ -2479,14 +2488,16 @@ function apply(ctx, rawConfig) {
2479
2488
  };
2480
2489
  const dock = () => ({
2481
2490
  credits: current().showCreditDock !== false,
2482
- queue: current().showQueueDock !== false
2491
+ queue: current().showQueueDock !== false,
2492
+ sidebar: current().showSidebarPanel === true
2483
2493
  });
2484
2494
  const setDock = async (patch) => {
2485
2495
  const settings = ctx.get("settings");
2486
2496
  if (settings === void 0) return false;
2487
2497
  await settings.update(settingsCompatNamespace(ctx), {
2488
2498
  ...patch.credits === void 0 ? {} : { showCreditDock: patch.credits },
2489
- ...patch.queue === void 0 ? {} : { showQueueDock: patch.queue }
2499
+ ...patch.queue === void 0 ? {} : { showQueueDock: patch.queue },
2500
+ ...patch.sidebar === void 0 ? {} : { showSidebarPanel: patch.sidebar }
2490
2501
  });
2491
2502
  return true;
2492
2503
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "dsh-codearts",
3
3
  "displayName": "DSH CodeArts Connect",
4
4
  "description": "把华为云 CodeArts 接入 DeepSeek Harness —— 内置 OAuth2 登录(PKCE + DPoP),登录后即可在 DSH 对话窗口使用 CodeArts 的模型。",
5
- "version": "1.2.4",
5
+ "version": "1.2.5",
6
6
  "packageManager": "pnpm@11.24.0",
7
7
  "author": "elegant01",
8
8
  "keywords": [