@eddyskywalker/dsh-chatgpt-subscription 0.58.0 → 0.60.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -1
  3. package/lib/client.js +1714 -255
  4. package/lib/client.js.map +1 -1
  5. package/lib/codemode.js +1952 -0
  6. package/lib/index.js +587 -243
  7. package/lib/llm-compat-u9mor0uu.js +110 -0
  8. package/lib/types/client/CodexImageToolView.d.ts.map +1 -1
  9. package/lib/types/client/codemode/CodeRunToolView.d.ts +68 -0
  10. package/lib/types/client/codemode/CodeRunToolView.d.ts.map +1 -0
  11. package/lib/types/client/codemode/highlight.d.ts +25 -0
  12. package/lib/types/client/codemode/highlight.d.ts.map +1 -0
  13. package/lib/types/client/codemode/styles.d.ts +11 -0
  14. package/lib/types/client/codemode/styles.d.ts.map +1 -0
  15. package/lib/types/client/codemode/tool-name.d.ts +10 -0
  16. package/lib/types/client/codemode/tool-name.d.ts.map +1 -0
  17. package/lib/types/client/index.d.ts.map +1 -1
  18. package/lib/types/client/locales-ru/hub.d.ts.map +1 -1
  19. package/lib/types/client/locales.d.ts +23 -1
  20. package/lib/types/client/locales.d.ts.map +1 -1
  21. package/lib/types/client/progress-updates/progress-row.d.ts.map +1 -1
  22. package/lib/types/client/styles.d.ts.map +1 -1
  23. package/lib/types/compat.d.ts +10 -1
  24. package/lib/types/compat.d.ts.map +1 -1
  25. package/lib/types/entry-codemode.d.ts +37 -0
  26. package/lib/types/entry-codemode.d.ts.map +1 -0
  27. package/lib/types/host/agent-preset.d.ts +24 -2
  28. package/lib/types/host/agent-preset.d.ts.map +1 -1
  29. package/lib/types/host/antigravity/image-tool.d.ts +10 -2
  30. package/lib/types/host/antigravity/image-tool.d.ts.map +1 -1
  31. package/lib/types/host/cache-warmup/install.d.ts +10 -4
  32. package/lib/types/host/cache-warmup/install.d.ts.map +1 -1
  33. package/lib/types/host/cache-warmup/projection.d.ts +17 -0
  34. package/lib/types/host/cache-warmup/projection.d.ts.map +1 -1
  35. package/lib/types/host/codemode/discovery.d.ts +33 -0
  36. package/lib/types/host/codemode/discovery.d.ts.map +1 -0
  37. package/lib/types/host/codemode/executor.d.ts +140 -0
  38. package/lib/types/host/codemode/executor.d.ts.map +1 -0
  39. package/lib/types/host/codemode/retention.d.ts +34 -0
  40. package/lib/types/host/codemode/retention.d.ts.map +1 -0
  41. package/lib/types/host/codemode/rules.d.ts +193 -0
  42. package/lib/types/host/codemode/rules.d.ts.map +1 -0
  43. package/lib/types/host/codemode/scope.d.ts +59 -0
  44. package/lib/types/host/codemode/scope.d.ts.map +1 -0
  45. package/lib/types/host/codemode/transport.d.ts +299 -0
  46. package/lib/types/host/codemode/transport.d.ts.map +1 -0
  47. package/lib/types/host/codex-images.d.ts +12 -0
  48. package/lib/types/host/codex-images.d.ts.map +1 -1
  49. package/lib/types/host/command-code/model-catalog.d.ts +14 -14
  50. package/lib/types/host/command-code/model-catalog.d.ts.map +1 -1
  51. package/lib/types/host/command-code/routes.d.ts.map +1 -1
  52. package/lib/types/host/preset-sync.d.ts +19 -4
  53. package/lib/types/host/preset-sync.d.ts.map +1 -1
  54. package/package.json +6 -1
  55. package/presets/dispatch/README.md +13 -6
  56. package/presets/dispatch/agent.cordis.yml +19 -16
  57. package/presets/dispatch/preset.yml +1 -1
package/lib/client.js CHANGED
@@ -155,13 +155,41 @@ window.__ModuleLoader__.load({
155
155
  }
156
156
  //#endregion
157
157
  //#region src/client/CodexImageToolView.tsx
158
+ /**
159
+ * Aspect ratios the Gemini image tool accepts in its `aspectRatio` argument.
160
+ *
161
+ * Mirrors `ANTIGRAVITY_IMAGE_ASPECT_RATIOS` in the host tool schema. The card
162
+ * only *sizes a placeholder* with it, so a drift here degrades to the default
163
+ * square instead of producing a wrong request — the value is never sent
164
+ * anywhere, and the host enum stays the single authority over what is legal.
165
+ */
166
+ const IMAGE_ASPECT_RATIOS = /* @__PURE__ */ new Set([
167
+ "1:1",
168
+ "2:3",
169
+ "3:2",
170
+ "3:4",
171
+ "4:3",
172
+ "4:5",
173
+ "5:4",
174
+ "9:16",
175
+ "16:9",
176
+ "21:9",
177
+ "1:4",
178
+ "4:1",
179
+ "1:8",
180
+ "8:1"
181
+ ]);
182
+ /** The model picks its own shape when the call names no ratio; the card guesses square. */
183
+ const DEFAULT_IMAGE_ASPECT_RATIO = "1:1";
184
+ /** The tray's short side, in px: a hint of the frame, not a billboard. */
185
+ const PLACEHOLDER_SHORT_SIDE = 112;
158
186
  function CodexImageToolView({ block, loadImage, t }) {
159
187
  const settled = "kind" in block;
160
188
  const isError = settled ? block.isError : false;
161
- const prompt = promptFromBlock$1(block);
162
189
  const images = settled && !isError ? imageBlocks(block.content) : [];
163
190
  const label = isError ? t("imageToolFailed") : settled ? t("imageToolDone") : t("imageToolRunning");
164
- const summary = prompt ?? textSummary$1(settled ? block.content : []);
191
+ const summary = promptFromBlock$1(block) ?? textSummary$1(settled ? block.content : []);
192
+ const tray = settled ? null : placeholderTray(aspectRatioFromBlock(block));
165
193
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
166
194
  className: "dsh-codex-image-tool",
167
195
  "data-state": isError ? "error" : settled ? "done" : "running",
@@ -174,12 +202,15 @@ window.__ModuleLoader__.load({
174
202
  }),
175
203
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
176
204
  className: "dsh-codex-image-title",
205
+ role: "status",
206
+ "aria-live": "polite",
177
207
  children: label
178
208
  }),
179
- summary !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
209
+ summary === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
180
210
  className: "dsh-codex-image-summary",
211
+ title: summary,
181
212
  children: summary
182
- }) : null
213
+ })
183
214
  ]
184
215
  }), images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
185
216
  className: "dsh-codex-image-grid",
@@ -189,7 +220,19 @@ window.__ModuleLoader__.load({
189
220
  label: attachment.name ?? t("image"),
190
221
  t
191
222
  }, String(attachment.attachmentId)))
192
- }) : null]
223
+ }) : tray === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
224
+ className: "dsh-codex-image-grid",
225
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
226
+ className: "dsh-codex-image-placeholder",
227
+ "data-ratio": tray.ratio,
228
+ "data-short-side": tray.axis,
229
+ style: {
230
+ aspectRatio: tray.ratio.replace(":", " / "),
231
+ ...tray.size
232
+ },
233
+ "aria-hidden": "true"
234
+ })
235
+ })]
193
236
  });
194
237
  }
195
238
  function GeneratedImage({ attachment, load, label, t }) {
@@ -223,24 +266,64 @@ window.__ModuleLoader__.load({
223
266
  });
224
267
  }
225
268
  function promptFromBlock$1(block) {
226
- const partial = partialPromptFromBlock(block);
269
+ return argumentFromBlock(block, "prompt");
270
+ }
271
+ /**
272
+ * Size the tray from one short side and let the ratio derive the other.
273
+ *
274
+ * A portrait frame fixes its height, and its width then stays narrow on its own.
275
+ * A landscape frame — and the 4:1 / 8:1 strips are exactly the case that forced
276
+ * this — fixes its width instead: deriving an 8:1 width from a 112px height
277
+ * would be 896px, which `max-width` would then clamp into a near-square box and
278
+ * the strip would stop looking like a strip. `min(…, 100%)` hands a narrow
279
+ * column back to the card and the height shrinks with it, so the shape survives
280
+ * the clamp.
281
+ */
282
+ function placeholderTray(ratio) {
283
+ const [w, h] = ratio.split(":").map(Number);
284
+ return w !== void 0 && h !== void 0 && w >= h ? {
285
+ axis: "width",
286
+ ratio,
287
+ size: { width: `min(${Math.round(PLACEHOLDER_SHORT_SIDE * (w / h))}px, 100%)` }
288
+ } : {
289
+ axis: "height",
290
+ ratio,
291
+ size: { height: PLACEHOLDER_SHORT_SIDE }
292
+ };
293
+ }
294
+ /** The placeholder's shape: the call's own ratio when it is one the tool accepts. */
295
+ function aspectRatioFromBlock(block) {
296
+ const ratio = argumentFromBlock(block, "aspectRatio")?.trim();
297
+ return ratio !== void 0 && IMAGE_ASPECT_RATIOS.has(ratio) ? ratio : DEFAULT_IMAGE_ASPECT_RATIO;
298
+ }
299
+ /**
300
+ * One string argument, read from whichever shape the current stage carries.
301
+ *
302
+ * While the arguments are still streaming, the harness hands over a lazy view
303
+ * instead of the JSON, so `args.text(key)` is tried first; once they are
304
+ * complete the same argument comes back as `argsRaw`.
305
+ */
306
+ function argumentFromBlock(block, key) {
307
+ const partial = partialArgumentFromBlock(block, key);
227
308
  if (partial !== null) return partial;
228
309
  const raw = "kind" in block ? block.call?.argsRaw : dispatchedArgsRaw(block);
229
310
  if (typeof raw !== "string" || raw.trim() === "") return null;
230
311
  try {
231
312
  const value = JSON.parse(raw);
232
- return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.prompt === "string" ? value.prompt : null;
313
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
314
+ const found = value[key];
315
+ return typeof found === "string" ? found : null;
233
316
  } catch {
234
317
  return null;
235
318
  }
236
319
  }
237
- function partialPromptFromBlock(block) {
320
+ function partialArgumentFromBlock(block, key) {
238
321
  if (!("args" in block)) return null;
239
322
  const args = block.args;
240
323
  if (typeof args?.text !== "function") return null;
241
324
  try {
242
- const prompt = args.text.call(args, "prompt");
243
- return typeof prompt === "string" ? prompt : null;
325
+ const value = args.text.call(args, key);
326
+ return typeof value === "string" ? value : null;
244
327
  } catch {
245
328
  return null;
246
329
  }
@@ -2895,10 +2978,10 @@ window.__ModuleLoader__.load({
2895
2978
  "aria-label": label,
2896
2979
  "data-copied": copied ? "true" : "false",
2897
2980
  onClick,
2898
- children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyIcon, {})
2981
+ children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon$1, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyIcon$1, {})
2899
2982
  });
2900
2983
  }
2901
- function CopyIcon() {
2984
+ function CopyIcon$1() {
2902
2985
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2903
2986
  viewBox: "0 0 16 16",
2904
2987
  width: "14",
@@ -2922,7 +3005,7 @@ window.__ModuleLoader__.load({
2922
3005
  })]
2923
3006
  });
2924
3007
  }
2925
- function CheckIcon() {
3008
+ function CheckIcon$1() {
2926
3009
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2927
3010
  viewBox: "0 0 16 16",
2928
3011
  width: "14",
@@ -7010,7 +7093,7 @@ window.__ModuleLoader__.load({
7010
7093
  * rather than inferred from the JSX.
7011
7094
  */
7012
7095
  /** The card's own dictionary; stable identity keeps effect dependencies intact. */
7013
- const fallbackTranslate$5 = (key) => zh$11[key];
7096
+ const fallbackTranslate$6 = (key) => zh$11[key];
7014
7097
  /**
7015
7098
  * The shared pool card's labels, resolved through this card's dictionary.
7016
7099
  *
@@ -7105,7 +7188,7 @@ window.__ModuleLoader__.load({
7105
7188
  /** Device-code poll cadence. The host owns the real expiry. */
7106
7189
  const LOGIN_POLL_INTERVAL_MS$3 = 2e3;
7107
7190
  function useMinimaxCodeSection({ onModelChange }) {
7108
- const t = fallbackTranslate$5;
7191
+ const t = fallbackTranslate$6;
7109
7192
  const [status, setStatus] = (0, react.useState)(null);
7110
7193
  const [loading, setLoading] = (0, react.useState)(true);
7111
7194
  const [busy, setBusy] = (0, react.useState)(null);
@@ -8563,7 +8646,7 @@ window.__ModuleLoader__.load({
8563
8646
  const { status, loading, busy, error, flow, copied, connectionNotice, contextDrafts, savingModel, pool, resetCards, resetNotice, selectedResetCardId } = state;
8564
8647
  const { authenticated, account, quota, models, contextModels, overrideCount, poolLabels, resetCardList, resetCardFlows } = derived;
8565
8648
  const { login, cancelLogin, copyCode, logout, poolAction, setStrategy, toggleModel, setAllModels, setCheckinEnabled, runCheckinNow, updateEffort, saveContextWindow, resetContextWindow, resetAllContextWindows, refreshQuota, refreshResetCards, selectResetCard, useResetCard, testConnection, updateContextDraft } = actions;
8566
- const t = fallbackTranslate$5;
8649
+ const t = fallbackTranslate$6;
8567
8650
  const videoDefaultsRef = react.default.useRef(null);
8568
8651
  if (videoDefaultsRef.current === null) videoDefaultsRef.current = readVideoDefaults();
8569
8652
  const saveVideoDefaults = react.default.useCallback((next) => {
@@ -9341,7 +9424,7 @@ window.__ModuleLoader__.load({
9341
9424
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
9342
9425
  const LOGIN_POLL_INTERVAL_MS$2 = 2e3;
9343
9426
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
9344
- const fallbackTranslate$4 = (key) => zh$10[key];
9427
+ const fallbackTranslate$5 = (key) => zh$10[key];
9345
9428
  /**
9346
9429
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
9347
9430
  *
@@ -9405,7 +9488,7 @@ window.__ModuleLoader__.load({
9405
9488
  });
9406
9489
  }
9407
9490
  function useGlmCodingPlanSection({ onModelChange } = {}) {
9408
- const t = fallbackTranslate$4;
9491
+ const t = fallbackTranslate$5;
9409
9492
  const [status, setStatus] = (0, react.useState)(null);
9410
9493
  const [loading, setLoading] = (0, react.useState)(true);
9411
9494
  const [busy, setBusy] = (0, react.useState)(null);
@@ -12494,7 +12577,7 @@ window.__ModuleLoader__.load({
12494
12577
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
12495
12578
  const LOGIN_POLL_INTERVAL_MS$1 = 2e3;
12496
12579
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
12497
- const fallbackTranslate$3 = (key) => zh$7[key];
12580
+ const fallbackTranslate$4 = (key) => zh$7[key];
12498
12581
  /**
12499
12582
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
12500
12583
  *
@@ -12623,7 +12706,7 @@ window.__ModuleLoader__.load({
12623
12706
  /** 写侧的线路常量;卡片用它渲染说明,而不是渲染一条永远为 0 的进度条。 */
12624
12707
  const CACHE_WRITE_NOTE = STEP_CODE_CACHE_WRITE_NOTE;
12625
12708
  function useStepCodeSection({ onModelChange } = {}) {
12626
- const t = fallbackTranslate$3;
12709
+ const t = fallbackTranslate$4;
12627
12710
  const [status, setStatus] = (0, react.useState)(null);
12628
12711
  const [loading, setLoading] = (0, react.useState)(true);
12629
12712
  const [busy, setBusy] = (0, react.useState)(null);
@@ -16296,7 +16379,7 @@ window.__ModuleLoader__.load({
16296
16379
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
16297
16380
  const LOGIN_POLL_INTERVAL_MS = 2e3;
16298
16381
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
16299
- const fallbackTranslate$2 = (key) => zh$5[key];
16382
+ const fallbackTranslate$3 = (key) => zh$5[key];
16300
16383
  /**
16301
16384
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
16302
16385
  *
@@ -16395,7 +16478,7 @@ window.__ModuleLoader__.load({
16395
16478
  return stats.cacheReadTokens / denominator;
16396
16479
  }
16397
16480
  function useQoderSection({ onModelChange } = {}) {
16398
- const t = fallbackTranslate$2;
16481
+ const t = fallbackTranslate$3;
16399
16482
  const [status, setStatus] = (0, react.useState)(null);
16400
16483
  const [loading, setLoading] = (0, react.useState)(true);
16401
16484
  const [busy, setBusy] = (0, react.useState)(null);
@@ -20940,217 +21023,229 @@ window.__ModuleLoader__.load({
20940
21023
  //#endregion
20941
21024
  //#region src/client/locales.ts
20942
21025
  const NS = "dsh-chatgpt-subscription";
21026
+ const zh$2 = {
21027
+ ...accountPoolZh,
21028
+ title: "ChatGPT",
21029
+ hubTitle: "订阅服务",
21030
+ intro: "使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的模型。",
21031
+ account: "账号",
21032
+ signedOut: "尚未登录",
21033
+ signedIn: "已登录",
21034
+ plan: "套餐",
21035
+ accountId: "账号 ID",
21036
+ expires: "令牌到期",
21037
+ signIn: "使用 ChatGPT 登录",
21038
+ signInAgain: "重新登录",
21039
+ cancel: "取消登录",
21040
+ signOut: "注销",
21041
+ refreshToken: "刷新凭据",
21042
+ pending: "请在浏览器中完成登录。",
21043
+ popupBlocked: "浏览器拦截了登录窗口,请使用下面的链接继续。",
21044
+ continueLogin: "打开 ChatGPT 登录页",
21045
+ loading: "正在读取状态…",
21046
+ connection: "连接",
21047
+ testConnection: "测试连接",
21048
+ testing: "测试中…",
21049
+ latency: "最近延迟",
21050
+ selectAll: "全选",
21051
+ unselectAll: "全不选",
21052
+ models: "可用模型",
21053
+ modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
21054
+ proxySettings: "网络代理",
21055
+ proxyMode: "代理模式",
21056
+ proxyModeHint: "本插件的全部供应线路共用这一份代理设置,登录、令牌续期、模型目录与配额读取同样经过它;支持自动读取系统代理,修改后对后续请求生效。",
21057
+ proxyModeAuto: "系统代理(自动检测)",
21058
+ proxyModeCustom: "自定义代理",
21059
+ proxyModeDirect: "直连(禁用代理)",
21060
+ customProxyUrl: "自定义代理地址",
21061
+ customProxyUrlHint: "支持 HTTP/HTTPS/SOCKS5 代理地址,例如 http://127.0.0.1:7890",
21062
+ customProxyUrlPlaceholder: "例如: http://127.0.0.1:7890",
21063
+ saveProxyUrl: "保存代理地址",
21064
+ proxyDetected: "检测到系统代理",
21065
+ proxyDetectedEffective: "(已自动生效)",
21066
+ proxyNoneDetected: "未检测到系统代理,将使用直连",
21067
+ proxyDirectHint: "本插件的全部请求将直接连接,不经过任何代理服务器。",
21068
+ poolStorageTitle: "账号存储位置",
21069
+ poolStorageKeyring: "桌面密钥环",
21070
+ poolStorageCredentials: "DSH 凭据库",
21071
+ poolStorageKeyringHint: "仅限桌面安装:使用操作系统密钥环(DPAPI / 钥匙串 / Secret Service)。在服务器或无桌面的 Linux 主机上密钥环通常不可用,登录会失败——请改选 DSH 凭据库。",
21072
+ poolStorageCredentialsHint: "DSH 的标准密钥存储($DSH_HOME/.credentials.yaml)。POSIX 上强制 0600、创建者独占;Windows 上只有 profile ACL,没有权限位可强制。服务器以及任何没有桌面密钥环的主机都用它。静态不加密,靠宿主权限保护。",
21073
+ poolStorageEffective: "当前实际使用:{storage}",
21074
+ poolStorageBackendKeyring: "桌面密钥环(Secret Service),静态加密",
21075
+ poolStorageBackendDpapi: "Windows DPAPI,静态加密",
21076
+ poolStorageBackendKeychain: "macOS 钥匙串,静态加密",
21077
+ poolStorageBackendCredentials: "DSH 凭据库(.credentials.yaml),由文件权限保护",
21078
+ poolStorageSwitchWarning: "已保存在另一个存储里的账号会留在原处,切回去之前不会显示。不会做迁移。",
21079
+ poolStorageUnavailableKeyring: "这台主机上没有可用的桌面密钥环,因此号池无法读写。请把「账号存储位置」改成 DSH 凭据库。",
21080
+ poolStorageUnavailableCredentials: "这个 harness 没有凭据库(ctx.credentials),因此号池无法读写。请把「账号存储位置」改成桌面密钥环。",
21081
+ poolStorageUnavailableStore: "号池存储这次没有应答,所以这里没有列出账号——账号并没有被删除,存储恢复后重新打开本页即可。",
21082
+ enhancements: "增强功能",
21083
+ fastMode: "快速模式(1.5x 速度)",
21084
+ fastModeHint: "提升 Token 生成速度至约 1.5 倍;将以约 2x–2.5x 速度消耗 Codex 订阅额度。",
21085
+ outputVerbosity: "输出详细程度",
21086
+ outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。默认值与官方 Codex 客户端一致(低)。",
21087
+ verbosityLow: "低(保持回答简洁)",
21088
+ verbosityMedium: "中(兼顾细节与简洁)",
21089
+ verbosityHigh: "高(在回答中包含更多细节)",
21090
+ reasoningSummary: "推理摘要",
21091
+ reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。默认值与官方 Codex 客户端一致(不生成摘要,可省额度)。",
21092
+ summaryAuto: "自动(让模型选择摘要详细程度)",
21093
+ summaryConcise: "简洁(显示简要推理摘要)",
21094
+ summaryDetailed: "详细(显示更详细的推理摘要)",
21095
+ summaryNone: "无(不显示推理摘要)",
21096
+ searchProvider: "搜索来源",
21097
+ searchProviderHint: "选择 DSH 联网搜索使用默认来源,或改用当前 ChatGPT 订阅的 Codex 来源(自动走代理隧道)。抓取模式为 auto 时,抓取来源跟随此选择。",
21098
+ searchProviderDsh: "DSH 默认",
21099
+ searchProviderCodex: "ChatGPT(代理隧道)",
21100
+ fetchStatus: "抓取来源(只读)",
21101
+ fetchStatusHint: "以下内容由 Host 上报,只读展示。",
21102
+ fetchConfiguredProvider: "配置的抓取 Provider",
21103
+ fetchProviderDshDefault: "DSH 默认(Host 未固定抓取 provider)",
21104
+ switcherState: "抓取选择器状态",
21105
+ switcherStateIdle: "空闲(尚未应用选择)",
21106
+ switcherStateApplying: "应用中(正在切换 Host 的 web provider)",
21107
+ switcherStateApplied: "已应用",
21108
+ switcherStateMissing: "未找到可切换的 web 服务",
21109
+ switcherStateFailed: "切换失败,请检查 Host 日志",
21110
+ fetchMode: "抓取模式",
21111
+ fetchModeAuto: "auto(有可用代理或选了 ChatGPT 搜索时用插件抓取)",
21112
+ fetchModePlugin: "plugin(始终用本插件抓取)",
21113
+ fetchModeDsh: "dsh(保留 DSH 原有抓取来源)",
21114
+ fetchMaxBodyChars: "插件正文上限",
21115
+ fetchMaxResponseBytes: "插件响应体上限",
21116
+ characters: "字符",
21117
+ bytes: "字节",
21118
+ fetchLimitsInactive: "仅在实际使用插件抓取时生效;走 DSH 原有抓取来源时不适用这两个上限。",
21119
+ fetchConfigSource: "模式与上限在插件 Config 中修改(不是本页面偏好),修改后重载插件或重启 DSH 生效。",
21120
+ providerDefault: "使用 Provider 默认值",
21121
+ contextWindows: "模型上下文窗口",
21122
+ contextWindowsHint: "只列出已勾选「可用模型」的条目。默认取模型目录值(GPT-6 系列 384K,最高 872K;其余最高 1M),该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量;改过的模型可单独或一键恢复默认。",
21123
+ contextWindow: "上下文窗口",
21124
+ contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(GPT-6 系列为 872K,其余为 1M);可使用 K 或 M 后缀。",
21125
+ contextWindowReset: "恢复默认",
21126
+ contextWindowResetAll: "全部恢复默认",
21127
+ contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
21128
+ contextWindowsNoneEnabled: "还没有勾选任何模型。在上方「可用模型」里勾选后,这里会出现该模型的上下文窗口设置。",
21129
+ saveContextWindow: "保存上下文窗口",
21130
+ save: "保存",
21131
+ tokens: "tokens",
21132
+ quickQuota: "在输入框旁显示快捷用量",
21133
+ quickQuotaHint: "仅在当前会话选中 codex-chatgpt 模型时显示。",
21134
+ quota: "用量与限额",
21135
+ quotaIntro: "数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。",
21136
+ refreshQuota: "刷新用量",
21137
+ refreshing: "刷新中…",
21138
+ noQuota: "当前套餐未返回可显示的限额窗口。",
21139
+ quotaSignedOut: "登录后可查看订阅限额。",
21140
+ stale: "显示的是上次成功获取的数据。",
21141
+ updated: "更新时间",
21142
+ primary: "主要窗口",
21143
+ secondary: "次要窗口",
21144
+ limitWindow: "额度",
21145
+ used: "已使用",
21146
+ remaining: "剩余",
21147
+ available: "可用",
21148
+ unavailable: "不可用",
21149
+ unlimited: "无限",
21150
+ credits: "Credits",
21151
+ monthlySpend: "月度消费控制",
21152
+ resetCredits: "重置次数",
21153
+ resetCreditExpires: "到期时间",
21154
+ useResetCredit: "使用重置卡",
21155
+ usingResetCredit: "使用中…",
21156
+ useResetCreditConfirm: "使用后会立即消耗 1 次重置机会,并重置符合条件的 Codex 额度窗口。确定继续吗?",
21157
+ resetCreditUsed: "重置卡已使用,用量数据已刷新。",
21158
+ spendControlReached: "已触发月度消费控制,新的订阅调用可能被限制。",
21159
+ limit: "上限",
21160
+ exhausted: "额度已用尽",
21161
+ resets: "重置",
21162
+ quickQuotaLabel: "Codex 剩余",
21163
+ quickQuotaLoading: "用量…",
21164
+ imageToolRunning: "正在生成图片",
21165
+ imageToolDone: "已生成图片",
21166
+ imageToolFailed: "图片生成失败",
21167
+ image: "图片",
21168
+ openImage: "打开图片",
21169
+ openNamedImage: "打开 {name}",
21170
+ imageLoading: "加载图片…",
21171
+ imageLoadFailed: "图片加载失败,点击重试",
21172
+ imagePreviewClose: "关闭",
21173
+ imagePreviewOpenOriginal: "打开原图",
21174
+ retry: "重试",
21175
+ unknown: "未知",
21176
+ hubBack: "订阅服务",
21177
+ hubOverviewHint: "选择供应商以管理账号、模型与配额;右侧开关控制该供应商是否出现在模型列表中。",
21178
+ hubAccountCount: "{count} 个账号",
21179
+ hubNoAccounts: "暂无账号,点击进入添加",
21180
+ hubStateEnabled: "已启用",
21181
+ hubStateDisabled: "已停用",
21182
+ hubModelsEnabled: "{count} 个模型可用",
21183
+ hubModelsEnabledOfTotal: "{count}/{total} 个模型可用",
21184
+ hubStatusFailed: "状态读取失败",
21185
+ hubSwitchOn: "启用 {name}",
21186
+ hubSwitchOff: "停用 {name}",
21187
+ hubCardLabel: "{name},{annotation}",
21188
+ hubUpdateCheck: "检测更新",
21189
+ hubUpdateChecking: "检测中…",
21190
+ hubUpdateApply: "更新到 v{version}",
21191
+ hubUpdateApplying: "更新中…",
21192
+ hubUpdateUpToDate: "已是最新版本 {version}",
21193
+ hubUpdateLatestWithUnknownCurrent: "最新版本 {version},当前版本未知",
21194
+ hubUpdateAvailable: "有新版本 {version},当前 {current}",
21195
+ hubUpdateInstalled: "已安装 v{version},重启宿主后生效",
21196
+ hubUpdateInstalledReplaced: "已移除旧版并安装 v{version},重启宿主后生效",
21197
+ hubUpdateInstalledLive: "已安装 v{version},当前已生效,无需重启",
21198
+ hubUpdateInstalledReplacedLive: "已移除旧版并安装 v{version},当前已生效,无需重启",
21199
+ hubUpdateFailedRestored: "更新失败,已恢复 v{version}",
21200
+ hubUpdateFailedRollbackFailed: "更新失败,且旧版本也没能重新装回来——插件可能已不可用",
21201
+ hubUpdateFailedRollbackSkipped: "更新失败,且无法自动恢复原版本——插件可能已被移除",
21202
+ hubUpdateDevelopmentInstall: "有新版本 {version};当前是本地链接安装,无法自动更新",
21203
+ hubUpdatePluginManagerMissing: "有新版本 {version};宿主未提供 pluginManager,无法自动更新",
21204
+ hubUpdateManualOnly: "有新版本 {version};当前安装方式无法自动更新",
21205
+ hubUpdateCheckFailed: "检测失败:无法连接 npm 源,请检查网络或代理",
21206
+ hubUpdateCommandLabel: "手动更新命令",
21207
+ localCodexLoginImport: "导入本机登录",
21208
+ localCodexLoginImporting: "导入中…",
21209
+ deviceCodeLogin: "设备代码登录",
21210
+ deviceCodeLoginStarting: "获取代码…",
21211
+ deviceCodeLoginDetail: "用设备代码添加账号",
21212
+ deviceCodeHint: "在任意设备上打开下面的链接并输入这个代码,本页会自动完成登录:这条路不需要浏览器回调到本机端口。",
21213
+ deviceCodeLabel: "设备代码",
21214
+ deviceCodeOpen: "打开确认页面",
21215
+ deviceCodeCopy: "复制到剪贴板",
21216
+ deviceCodeWaiting: "等待确认… 剩余 {time}",
21217
+ stopImporting: "停止导入全部本机登录",
21218
+ stopImportingLabel: "停止导入全部本机登录(当前 {count} 个)",
21219
+ stopImportingBusy: "停止导入中…",
21220
+ stopImportingHint: "停止导入只会让本插件忘记本机 CLI 登录的副本;Codex CLI 自己的登录文件不会被删除或修改。账号池不允许逐条删除借来的凭据,所以这里一次会停止全部导入。",
21221
+ "cardName.chatgpt": "ChatGPT",
21222
+ "cardName.antigravity": "Antigravity",
21223
+ "cardName.command-code": "Command Code",
21224
+ "cardName.kimi-code": "Kimi Code",
21225
+ "cardName.minimax-code": "MiniMax Code",
21226
+ "cardName.glm-coding-plan": "GLM(ZCode 账号)",
21227
+ "cardName.claude": "Claude",
21228
+ "cardName.ollama": "Ollama",
21229
+ "cardName.step-code": "Step Code(Step Plan 订阅)",
21230
+ "cardName.cline-pass": "Cline Pass",
21231
+ "cardName.qoder": "Qoder(订阅)",
21232
+ "cardName.opendesign": "OpenDesign",
21233
+ "cardName.workbuddy": "WorkBuddy",
21234
+ modelChecklistCount: "已启用 {count}/{total}",
21235
+ codeRunTitle: "代码",
21236
+ codeRunOutput: "输出",
21237
+ codeRunCopy: "复制",
21238
+ codeRunCopied: "已复制",
21239
+ codeRunWrap: "自动换行",
21240
+ codeRunUnwrap: "取消自动换行",
21241
+ codeRunInspect: "查看轨迹",
21242
+ codeRunPreparing: "准备中",
21243
+ codeRunRunning: "运行中",
21244
+ codeRunFailed: "失败",
21245
+ codeRunStopped: "已停止"
21246
+ };
20943
21247
  const dictionaries$2 = {
20944
- zh: {
20945
- ...accountPoolZh,
20946
- title: "ChatGPT",
20947
- hubTitle: "订阅服务",
20948
- intro: "使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的模型。",
20949
- account: "账号",
20950
- signedOut: "尚未登录",
20951
- signedIn: "已登录",
20952
- plan: "套餐",
20953
- accountId: "账号 ID",
20954
- expires: "令牌到期",
20955
- signIn: "使用 ChatGPT 登录",
20956
- signInAgain: "重新登录",
20957
- cancel: "取消登录",
20958
- signOut: "注销",
20959
- refreshToken: "刷新凭据",
20960
- pending: "请在浏览器中完成登录。",
20961
- popupBlocked: "浏览器拦截了登录窗口,请使用下面的链接继续。",
20962
- continueLogin: "打开 ChatGPT 登录页",
20963
- loading: "正在读取状态…",
20964
- connection: "连接",
20965
- testConnection: "测试连接",
20966
- testing: "测试中…",
20967
- latency: "最近延迟",
20968
- selectAll: "全选",
20969
- unselectAll: "全不选",
20970
- models: "可用模型",
20971
- modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;全部取消勾选或关闭上方开关可在列表中隐藏该供应商。",
20972
- proxySettings: "网络代理",
20973
- proxyMode: "代理模式",
20974
- proxyModeHint: "本插件的全部供应线路共用这一份代理设置,登录、令牌续期、模型目录与配额读取同样经过它;支持自动读取系统代理,修改后对后续请求生效。",
20975
- proxyModeAuto: "系统代理(自动检测)",
20976
- proxyModeCustom: "自定义代理",
20977
- proxyModeDirect: "直连(禁用代理)",
20978
- customProxyUrl: "自定义代理地址",
20979
- customProxyUrlHint: "支持 HTTP/HTTPS/SOCKS5 代理地址,例如 http://127.0.0.1:7890",
20980
- customProxyUrlPlaceholder: "例如: http://127.0.0.1:7890",
20981
- saveProxyUrl: "保存代理地址",
20982
- proxyDetected: "检测到系统代理",
20983
- proxyDetectedEffective: "(已自动生效)",
20984
- proxyNoneDetected: "未检测到系统代理,将使用直连",
20985
- proxyDirectHint: "本插件的全部请求将直接连接,不经过任何代理服务器。",
20986
- poolStorageTitle: "账号存储位置",
20987
- poolStorageKeyring: "桌面密钥环",
20988
- poolStorageCredentials: "DSH 凭据库",
20989
- poolStorageKeyringHint: "仅限桌面安装:使用操作系统密钥环(DPAPI / 钥匙串 / Secret Service)。在服务器或无桌面的 Linux 主机上密钥环通常不可用,登录会失败——请改选 DSH 凭据库。",
20990
- poolStorageCredentialsHint: "DSH 的标准密钥存储($DSH_HOME/.credentials.yaml)。POSIX 上强制 0600、创建者独占;Windows 上只有 profile ACL,没有权限位可强制。服务器以及任何没有桌面密钥环的主机都用它。静态不加密,靠宿主权限保护。",
20991
- poolStorageEffective: "当前实际使用:{storage}",
20992
- poolStorageBackendKeyring: "桌面密钥环(Secret Service),静态加密",
20993
- poolStorageBackendDpapi: "Windows DPAPI,静态加密",
20994
- poolStorageBackendKeychain: "macOS 钥匙串,静态加密",
20995
- poolStorageBackendCredentials: "DSH 凭据库(.credentials.yaml),由文件权限保护",
20996
- poolStorageSwitchWarning: "已保存在另一个存储里的账号会留在原处,切回去之前不会显示。不会做迁移。",
20997
- poolStorageUnavailableKeyring: "这台主机上没有可用的桌面密钥环,因此号池无法读写。请把「账号存储位置」改成 DSH 凭据库。",
20998
- poolStorageUnavailableCredentials: "这个 harness 没有凭据库(ctx.credentials),因此号池无法读写。请把「账号存储位置」改成桌面密钥环。",
20999
- poolStorageUnavailableStore: "号池存储这次没有应答,所以这里没有列出账号——账号并没有被删除,存储恢复后重新打开本页即可。",
21000
- enhancements: "增强功能",
21001
- fastMode: "快速模式(1.5x 速度)",
21002
- fastModeHint: "提升 Token 生成速度至约 1.5 倍;将以约 2x–2.5x 速度消耗 Codex 订阅额度。",
21003
- outputVerbosity: "输出详细程度",
21004
- outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。默认值与官方 Codex 客户端一致(低)。",
21005
- verbosityLow: "低(保持回答简洁)",
21006
- verbosityMedium: "中(兼顾细节与简洁)",
21007
- verbosityHigh: "高(在回答中包含更多细节)",
21008
- reasoningSummary: "推理摘要",
21009
- reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。默认值与官方 Codex 客户端一致(不生成摘要,可省额度)。",
21010
- summaryAuto: "自动(让模型选择摘要详细程度)",
21011
- summaryConcise: "简洁(显示简要推理摘要)",
21012
- summaryDetailed: "详细(显示更详细的推理摘要)",
21013
- summaryNone: "无(不显示推理摘要)",
21014
- searchProvider: "搜索来源",
21015
- searchProviderHint: "选择 DSH 联网搜索使用默认来源,或改用当前 ChatGPT 订阅的 Codex 来源(自动走代理隧道)。抓取模式为 auto 时,抓取来源跟随此选择。",
21016
- searchProviderDsh: "DSH 默认",
21017
- searchProviderCodex: "ChatGPT(代理隧道)",
21018
- fetchStatus: "抓取来源(只读)",
21019
- fetchStatusHint: "以下内容由 Host 上报,只读展示。",
21020
- fetchConfiguredProvider: "配置的抓取 Provider",
21021
- fetchProviderDshDefault: "DSH 默认(Host 未固定抓取 provider)",
21022
- switcherState: "抓取选择器状态",
21023
- switcherStateIdle: "空闲(尚未应用选择)",
21024
- switcherStateApplying: "应用中(正在切换 Host 的 web provider)",
21025
- switcherStateApplied: "已应用",
21026
- switcherStateMissing: "未找到可切换的 web 服务",
21027
- switcherStateFailed: "切换失败,请检查 Host 日志",
21028
- fetchMode: "抓取模式",
21029
- fetchModeAuto: "auto(有可用代理或选了 ChatGPT 搜索时用插件抓取)",
21030
- fetchModePlugin: "plugin(始终用本插件抓取)",
21031
- fetchModeDsh: "dsh(保留 DSH 原有抓取来源)",
21032
- fetchMaxBodyChars: "插件正文上限",
21033
- fetchMaxResponseBytes: "插件响应体上限",
21034
- characters: "字符",
21035
- bytes: "字节",
21036
- fetchLimitsInactive: "仅在实际使用插件抓取时生效;走 DSH 原有抓取来源时不适用这两个上限。",
21037
- fetchConfigSource: "模式与上限在插件 Config 中修改(不是本页面偏好),修改后重载插件或重启 DSH 生效。",
21038
- providerDefault: "使用 Provider 默认值",
21039
- contextWindows: "模型上下文窗口",
21040
- contextWindowsHint: "只列出已勾选「可用模型」的条目。默认取模型目录值(GPT-6 系列 384K,最高 872K;其余最高 1M),该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量;改过的模型可单独或一键恢复默认。",
21041
- contextWindow: "上下文窗口",
21042
- contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(GPT-6 系列为 872K,其余为 1M);可使用 K 或 M 后缀。",
21043
- contextWindowReset: "恢复默认",
21044
- contextWindowResetAll: "全部恢复默认",
21045
- contextWindowResetAllConfirm: "确定把已改过的模型上下文窗口全部恢复为默认值吗?",
21046
- contextWindowsNoneEnabled: "还没有勾选任何模型。在上方「可用模型」里勾选后,这里会出现该模型的上下文窗口设置。",
21047
- saveContextWindow: "保存上下文窗口",
21048
- save: "保存",
21049
- tokens: "tokens",
21050
- quickQuota: "在输入框旁显示快捷用量",
21051
- quickQuotaHint: "仅在当前会话选中 codex-chatgpt 模型时显示。",
21052
- quota: "用量与限额",
21053
- quotaIntro: "数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。",
21054
- refreshQuota: "刷新用量",
21055
- refreshing: "刷新中…",
21056
- noQuota: "当前套餐未返回可显示的限额窗口。",
21057
- quotaSignedOut: "登录后可查看订阅限额。",
21058
- stale: "显示的是上次成功获取的数据。",
21059
- updated: "更新时间",
21060
- primary: "主要窗口",
21061
- secondary: "次要窗口",
21062
- limitWindow: "额度",
21063
- used: "已使用",
21064
- remaining: "剩余",
21065
- available: "可用",
21066
- unavailable: "不可用",
21067
- unlimited: "无限",
21068
- credits: "Credits",
21069
- monthlySpend: "月度消费控制",
21070
- resetCredits: "重置次数",
21071
- resetCreditExpires: "到期时间",
21072
- useResetCredit: "使用重置卡",
21073
- usingResetCredit: "使用中…",
21074
- useResetCreditConfirm: "使用后会立即消耗 1 次重置机会,并重置符合条件的 Codex 额度窗口。确定继续吗?",
21075
- resetCreditUsed: "重置卡已使用,用量数据已刷新。",
21076
- spendControlReached: "已触发月度消费控制,新的订阅调用可能被限制。",
21077
- limit: "上限",
21078
- exhausted: "额度已用尽",
21079
- resets: "重置",
21080
- quickQuotaLabel: "Codex 剩余",
21081
- quickQuotaLoading: "用量…",
21082
- imageToolRunning: "正在生成图片",
21083
- imageToolDone: "已生成图片",
21084
- imageToolFailed: "图片生成失败",
21085
- image: "图片",
21086
- openImage: "打开图片",
21087
- openNamedImage: "打开 {name}",
21088
- imageLoading: "加载图片…",
21089
- imageLoadFailed: "图片加载失败,点击重试",
21090
- imagePreviewClose: "关闭",
21091
- imagePreviewOpenOriginal: "打开原图",
21092
- retry: "重试",
21093
- unknown: "未知",
21094
- hubBack: "订阅服务",
21095
- hubOverviewHint: "选择供应商以管理账号、模型与配额;右侧开关控制该供应商是否出现在模型列表中。",
21096
- hubAccountCount: "{count} 个账号",
21097
- hubNoAccounts: "暂无账号,点击进入添加",
21098
- hubStateEnabled: "已启用",
21099
- hubStateDisabled: "已停用",
21100
- hubModelsEnabled: "{count} 个模型可用",
21101
- hubModelsEnabledOfTotal: "{count}/{total} 个模型可用",
21102
- hubStatusFailed: "状态读取失败",
21103
- hubSwitchOn: "启用 {name}",
21104
- hubSwitchOff: "停用 {name}",
21105
- hubCardLabel: "{name},{annotation}",
21106
- hubUpdateCheck: "检测更新",
21107
- hubUpdateChecking: "检测中…",
21108
- hubUpdateApply: "更新到 v{version}",
21109
- hubUpdateApplying: "更新中…",
21110
- hubUpdateUpToDate: "已是最新版本 {version}",
21111
- hubUpdateLatestWithUnknownCurrent: "最新版本 {version},当前版本未知",
21112
- hubUpdateAvailable: "有新版本 {version},当前 {current}",
21113
- hubUpdateInstalled: "已安装 v{version},重启宿主后生效",
21114
- hubUpdateInstalledReplaced: "已移除旧版并安装 v{version},重启宿主后生效",
21115
- hubUpdateInstalledLive: "已安装 v{version},当前已生效,无需重启",
21116
- hubUpdateInstalledReplacedLive: "已移除旧版并安装 v{version},当前已生效,无需重启",
21117
- hubUpdateFailedRestored: "更新失败,已恢复 v{version}",
21118
- hubUpdateFailedRollbackFailed: "更新失败,且旧版本也没能重新装回来——插件可能已不可用",
21119
- hubUpdateFailedRollbackSkipped: "更新失败,且无法自动恢复原版本——插件可能已被移除",
21120
- hubUpdateDevelopmentInstall: "有新版本 {version};当前是本地链接安装,无法自动更新",
21121
- hubUpdatePluginManagerMissing: "有新版本 {version};宿主未提供 pluginManager,无法自动更新",
21122
- hubUpdateManualOnly: "有新版本 {version};当前安装方式无法自动更新",
21123
- hubUpdateCheckFailed: "检测失败:无法连接 npm 源,请检查网络或代理",
21124
- hubUpdateCommandLabel: "手动更新命令",
21125
- localCodexLoginImport: "导入本机登录",
21126
- localCodexLoginImporting: "导入中…",
21127
- deviceCodeLogin: "设备代码登录",
21128
- deviceCodeLoginStarting: "获取代码…",
21129
- deviceCodeLoginDetail: "用设备代码添加账号",
21130
- deviceCodeHint: "在任意设备上打开下面的链接并输入这个代码,本页会自动完成登录:这条路不需要浏览器回调到本机端口。",
21131
- deviceCodeLabel: "设备代码",
21132
- deviceCodeOpen: "打开确认页面",
21133
- deviceCodeCopy: "复制到剪贴板",
21134
- deviceCodeWaiting: "等待确认… 剩余 {time}",
21135
- stopImporting: "停止导入全部本机登录",
21136
- stopImportingLabel: "停止导入全部本机登录(当前 {count} 个)",
21137
- stopImportingBusy: "停止导入中…",
21138
- stopImportingHint: "停止导入只会让本插件忘记本机 CLI 登录的副本;Codex CLI 自己的登录文件不会被删除或修改。账号池不允许逐条删除借来的凭据,所以这里一次会停止全部导入。",
21139
- "cardName.chatgpt": "ChatGPT",
21140
- "cardName.antigravity": "Antigravity",
21141
- "cardName.command-code": "Command Code",
21142
- "cardName.kimi-code": "Kimi Code",
21143
- "cardName.minimax-code": "MiniMax Code",
21144
- "cardName.glm-coding-plan": "GLM(ZCode 账号)",
21145
- "cardName.claude": "Claude",
21146
- "cardName.ollama": "Ollama",
21147
- "cardName.step-code": "Step Code(Step Plan 订阅)",
21148
- "cardName.cline-pass": "Cline Pass",
21149
- "cardName.qoder": "Qoder(订阅)",
21150
- "cardName.opendesign": "OpenDesign",
21151
- "cardName.workbuddy": "WorkBuddy",
21152
- modelChecklistCount: "已启用 {count}/{total}"
21153
- },
21248
+ zh: zh$2,
21154
21249
  en: {
21155
21250
  ...accountPoolEn,
21156
21251
  title: "ChatGPT",
@@ -21359,7 +21454,18 @@ window.__ModuleLoader__.load({
21359
21454
  "cardName.qoder": "Qoder Subscription",
21360
21455
  "cardName.opendesign": "OpenDesign",
21361
21456
  "cardName.workbuddy": "WorkBuddy",
21362
- modelChecklistCount: "{count}/{total} enabled"
21457
+ modelChecklistCount: "{count}/{total} enabled",
21458
+ codeRunTitle: "Code",
21459
+ codeRunOutput: "Output",
21460
+ codeRunCopy: "Copy",
21461
+ codeRunCopied: "Copied",
21462
+ codeRunWrap: "Wrap lines",
21463
+ codeRunUnwrap: "Do not wrap lines",
21464
+ codeRunInspect: "Inspect",
21465
+ codeRunPreparing: "Preparing",
21466
+ codeRunRunning: "Running",
21467
+ codeRunFailed: "Failed",
21468
+ codeRunStopped: "Stopped"
21363
21469
  }
21364
21470
  };
21365
21471
  //#endregion
@@ -22360,7 +22466,18 @@ window.__ModuleLoader__.load({
22360
22466
  "cardName.qoder": "Qoder (подписка)",
22361
22467
  "cardName.opendesign": "OpenDesign",
22362
22468
  "cardName.workbuddy": "WorkBuddy",
22363
- modelChecklistCount: "Включено {count}/{total}"
22469
+ modelChecklistCount: "Включено {count}/{total}",
22470
+ codeRunTitle: "Код",
22471
+ codeRunOutput: "Вывод",
22472
+ codeRunCopy: "Копировать",
22473
+ codeRunCopied: "Скопировано",
22474
+ codeRunWrap: "Переносить строки",
22475
+ codeRunUnwrap: "Не переносить строки",
22476
+ codeRunInspect: "Инспектор",
22477
+ codeRunPreparing: "Подготовка",
22478
+ codeRunRunning: "Выполняется",
22479
+ codeRunFailed: "Ошибка",
22480
+ codeRunStopped: "Остановлено"
22364
22481
  };
22365
22482
  //#endregion
22366
22483
  //#region src/client/locales-ru/kimi-code.ts
@@ -23564,18 +23681,32 @@ window.__ModuleLoader__.load({
23564
23681
  .dsh-codex-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
23565
23682
  .dsh-codex-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
23566
23683
  .dsh-codex-image-tool{border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:flex;flex-direction:column;gap:8px;margin:4px 0 4px 4px;max-width:520px;padding:10px 12px}
23567
- .dsh-codex-image-tool-head{align-items:center;display:flex;font-size:13px;gap:8px;min-width:0}
23684
+ /* One line, always. In a 320px column the label used to be squeezed until it
23685
+ stacked one character per row, which reads as broken text rather than a card.
23686
+ The dot and the label therefore keep their own size (flex:none + nowrap) and
23687
+ the summary is the only thing that gives way — it shrinks to zero width and
23688
+ ellipsizes, with the full prompt left in its title attribute. */
23689
+ .dsh-codex-image-tool-head{align-items:center;display:flex;flex-wrap:nowrap;font-size:13px;gap:8px;min-width:0}
23568
23690
  .dsh-codex-image-dot{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:50%;corner-shape:round;display:inline-block;flex:none;height:8px;width:8px}
23569
23691
  .dsh-codex-image-tool[data-state=error] .dsh-codex-image-dot{background:var(--dsw-alias-label-danger,#d94b4b)}
23570
- .dsh-codex-image-title{font-weight:600}
23571
- .dsh-codex-image-summary{color:var(--dsw-alias-label-tertiary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
23692
+ .dsh-codex-image-title{flex:none;font-weight:600;white-space:nowrap}
23693
+ .dsh-codex-image-summary{color:var(--dsw-alias-label-tertiary);flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
23572
23694
  .dsh-codex-image-grid{display:flex;flex-wrap:wrap;gap:8px}
23695
+ /* The tray the image will land in, drawn while the call is still running so the
23696
+ card does not jump from one text row to a full picture when the result
23697
+ arrives. Neither dimension is set here: the view fixes the short side (height
23698
+ for a portrait frame, width for a landscape one) and the inline aspect-ratio
23699
+ derives the other, which is what keeps the 4:1 and 8:1 strips from being
23700
+ clamped into squarer boxes. max-width is the card's edge. The breathe is the
23701
+ same restrained opacity pulse the settings skeleton uses, and the
23702
+ reduced-motion block below turns it off. */
23703
+ .dsh-codex-image-placeholder{animation:dsh-codex-pulse 2s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border:0.5px dashed var(--dsw-alias-border-l2);border-radius:8px;display:block;flex:none;max-width:100%}
23573
23704
  .dsh-codex-image-preview{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:block;max-height:260px;max-width:min(100%,360px);object-fit:contain}
23574
23705
  .dsh-codex-image-loading,.dsh-codex-image-failed{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-tertiary);display:inline-flex;font-size:12px;line-height:1.4;padding:18px 20px}
23575
23706
  .dsh-codex-image-failed{color:var(--dsw-alias-label-danger,#d94b4b)}
23576
23707
  @keyframes dsh-codex-pulse{0%,100%{opacity:.45}50%{opacity:.85}}
23577
23708
  @media(max-width:560px){.dsh-codex-row,.dsh-codex-pref-row,.dsh-codex-quota-fact,.dsh-codex-reset-credits{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value,.dsh-codex-quota-fact strong{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}.dsh-codex-segments{width:100%}.dsh-codex-select{max-width:none;width:100%}.dsh-codex-context-row{align-items:flex-start;flex-direction:column;gap:5px}.dsh-codex-segments label{flex:1}.dsh-codex-segments span{text-align:center}.dsh-codex-image-tool{max-width:100%;margin-left:0}}
23578
- @media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
23709
+ @media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}.dsh-codex-image-placeholder{animation:none}}
23579
23710
  `;
23580
23711
  /**
23581
23712
  * Install the ChatGPT tab's stylesheet as a document-owned, never-removed
@@ -27418,7 +27549,7 @@ window.__ModuleLoader__.load({
27418
27549
  }
27419
27550
  }
27420
27551
  /** 兜底翻译:只在没有 locale 服务时用到(测试、以及菜单渲染早于字典注册)。 */
27421
- function fallbackTranslate$1(key, params) {
27552
+ function fallbackTranslate$2(key, params) {
27422
27553
  const template = zh$11[key] ?? key;
27423
27554
  if (params === void 0) return template;
27424
27555
  return template.replace(/\{(\w+)\}/g, (_match, name) => String(params[name] ?? ""));
@@ -27434,7 +27565,7 @@ window.__ModuleLoader__.load({
27434
27565
  * @returns 一份可直接交给 `commandUi.register` 的贡献。
27435
27566
  */
27436
27567
  function createVideoCommand(ctx, options) {
27437
- const t = options.translate ?? fallbackTranslate$1;
27568
+ const t = options.translate ?? fallbackTranslate$2;
27438
27569
  const defaultsOf = options.defaults ?? (() => normalizeVideoDefaults({}));
27439
27570
  return {
27440
27571
  name: VIDEO_COMMAND_NAME,
@@ -27594,7 +27725,7 @@ window.__ModuleLoader__.load({
27594
27725
  defaults: request?.defaults ?? normalizeVideoDefaults({}),
27595
27726
  seedPrompt: request?.seedPrompt ?? "",
27596
27727
  listWorkspace,
27597
- t: fallbackTranslate$1
27728
+ t: fallbackTranslate$2
27598
27729
  });
27599
27730
  };
27600
27731
  }
@@ -27639,7 +27770,7 @@ window.__ModuleLoader__.load({
27639
27770
  return commandUi.register(createVideoCommand(ctx, {
27640
27771
  openForm: openVideoForm,
27641
27772
  defaults: () => readVideoDefaults(),
27642
- translate: fallbackTranslate$1
27773
+ translate: fallbackTranslate$2
27643
27774
  }));
27644
27775
  } catch {
27645
27776
  return () => {};
@@ -54629,7 +54760,7 @@ window.__ModuleLoader__.load({
54629
54760
  * @param params - `{name}` 模板参数。
54630
54761
  * @returns 该键的文案;缺键时回退为键本身。
54631
54762
  */
54632
- function fallbackTranslate(key, params) {
54763
+ function fallbackTranslate$1(key, params) {
54633
54764
  return interpolate(zh$1[key] ?? key, params);
54634
54765
  }
54635
54766
  /**
@@ -54929,7 +55060,7 @@ window.__ModuleLoader__.load({
54929
55060
  * @returns 面板标题文本。
54930
55061
  */
54931
55062
  function ProgressUpdatesTabTitle({ t }) {
54932
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: t === void 0 ? fallbackTranslate("progressTitle") : t("progressTitle") });
55063
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: t === void 0 ? fallbackTranslate$1("progressTitle") : t("progressTitle") });
54933
55064
  }
54934
55065
  //#endregion
54935
55066
  //#region src/client/progress-updates/progress-row.tsx
@@ -54970,22 +55101,36 @@ window.__ModuleLoader__.load({
54970
55101
  done: "rowDone",
54971
55102
  error: "rowError"
54972
55103
  };
54973
- /** 行的外框样式。 */
55104
+ /**
55105
+ * 行的外框样式。
55106
+ *
55107
+ * 字号与官方工具行标题对齐(13px):同一条时间线上混着 12px 的进展行与 13px 的
55108
+ * 工具行,读者看到的是两套字号。
55109
+ */
54974
55110
  const rowStyle = {
54975
55111
  display: "flex",
54976
55112
  flexDirection: "column",
54977
55113
  gap: "6px",
54978
55114
  width: "100%",
54979
- fontSize: "12px",
55115
+ fontSize: "13px",
54980
55116
  color: "var(--dsw-alias-label-primary, #1f2329)"
54981
55117
  };
54982
- /** 标题行按钮样式(整行可点,去掉原生按钮外观)。 */
55118
+ /**
55119
+ * 标题行按钮样式(整行可点,去掉原生按钮外观)。
55120
+ *
55121
+ * `minHeight: 36px` 与 `padding: 6px 0` 抄的是官方工具行那层 `_row_` 的实测取值
55122
+ * (`height:36px; min-height:36px; padding:6px 0`)。少了这两个值,进展行只有
55123
+ * 18px 左右,夹在一排 36px 的工具行里会明显更矮、更挤——用户报的就是这个。
55124
+ * 用 minHeight 而不是 height:正文换行、标题很长时允许它撑高,官方那种固定高度
55125
+ * 在文字折行时会把内容裁掉。
55126
+ */
54983
55127
  const headerStyle = {
54984
55128
  display: "flex",
54985
- alignItems: "baseline",
55129
+ alignItems: "center",
54986
55130
  gap: "8px",
54987
55131
  width: "100%",
54988
- padding: "0",
55132
+ minHeight: "36px",
55133
+ padding: "6px 0",
54989
55134
  border: "0",
54990
55135
  background: "transparent",
54991
55136
  color: "inherit",
@@ -54997,9 +55142,9 @@ window.__ModuleLoader__.load({
54997
55142
  const titleStyle = {
54998
55143
  flex: "1 1 auto",
54999
55144
  minWidth: "0",
55000
- fontSize: "12px",
55145
+ fontSize: "13px",
55001
55146
  fontWeight: 500,
55002
- lineHeight: "1.5",
55147
+ lineHeight: "16px",
55003
55148
  overflowWrap: "anywhere"
55004
55149
  };
55005
55150
  /** 状态词的小字样式。 */
@@ -55012,6 +55157,8 @@ window.__ModuleLoader__.load({
55012
55157
  /**
55013
55158
  * 正文样式:只管外边距、字号与颜色。
55014
55159
  *
55160
+ * 字号与标题一致(13px)—— 早先正文比标题小一号,展开后两节字不同大,读起来碎。
55161
+ *
55015
55162
  * **不再**在这里写 `whiteSpace: 'pre-wrap'`:正文交给 {@link MarkdownLite} 渲染,
55016
55163
  * 换行该不该保留由它产出的块级元素决定。早先这里是纯文本 `<p>{message}</p>`,
55017
55164
  * 于是列表符号、`**粗体**` 和管道符表格全部原样上屏 —— 同一份进展在侧栏面板里
@@ -55020,8 +55167,8 @@ window.__ModuleLoader__.load({
55020
55167
  const messageStyle = {
55021
55168
  overflowWrap: "anywhere",
55022
55169
  margin: "0",
55023
- fontSize: "12px",
55024
- lineHeight: "1.55",
55170
+ fontSize: "13px",
55171
+ lineHeight: "1.6",
55025
55172
  color: "var(--dsw-alias-label-secondary, #5b6270)"
55026
55173
  };
55027
55174
  /**
@@ -55073,7 +55220,7 @@ window.__ModuleLoader__.load({
55073
55220
  * @returns 一行进展;标题行常显,正文按交互展开。
55074
55221
  */
55075
55222
  function ProgressRow({ block, t }) {
55076
- const translate = (key) => t === void 0 ? fallbackTranslate(key) : t(key);
55223
+ const translate = (key) => t === void 0 ? fallbackTranslate$1(key) : t(key);
55077
55224
  const state = isSettled(block) ? block.isError === true ? "error" : "done" : "running";
55078
55225
  const { title, message } = progressOfBlock(block);
55079
55226
  const heading = title ?? message.split("\n").find((line) => line.trim() !== "") ?? translate("rowPending");
@@ -55400,7 +55547,7 @@ window.__ModuleLoader__.load({
55400
55547
  */
55401
55548
  function ProgressUpdatesSettingsSection(props) {
55402
55549
  const { openPanel, close, settings, t } = props;
55403
- const translate = (key) => t === void 0 ? fallbackTranslate(key) : t(key);
55550
+ const translate = (key) => t === void 0 ? fallbackTranslate$1(key) : t(key);
55404
55551
  const snapshot = (0, react.useSyncExternalStore)(settings?.subscribe ?? NO_SETTINGS_SUBSCRIBE, settings?.getSnapshot ?? NO_SETTINGS_READ, settings?.getSnapshot ?? NO_SETTINGS_READ);
55405
55552
  /** 写入被拒/失败时落在哪一行、说什么。 */
55406
55553
  const [failure, setFailure] = (0, react.useState)(void 0);
@@ -59025,6 +59172,1312 @@ window.__ModuleLoader__.load({
59025
59172
  return installPluginStyle(STYLE_NAME, SUBAGENT_CSS);
59026
59173
  }
59027
59174
  //#endregion
59175
+ //#region src/client/codemode/highlight.ts
59176
+ /** 宿主 `ui-theme/src/styles/shiki.css` 定义的标准变量表(带合理回退色以兼容测试环境)。 */
59177
+ const SHIKI_TOKEN_COLORS = {
59178
+ plain: void 0,
59179
+ keyword: "var(--shiki-token-keyword, #d6336c)",
59180
+ string: "var(--shiki-token-string, #2f9e44)",
59181
+ "string-expression": "var(--shiki-token-string-expression, #2b8a3e)",
59182
+ comment: "var(--shiki-token-comment, #868e96)",
59183
+ constant: "var(--shiki-token-constant, #1c7ed6)",
59184
+ function: "var(--shiki-token-function, #6741d9)",
59185
+ parameter: "var(--shiki-token-parameter, #e8590c)",
59186
+ punctuation: "var(--shiki-token-punctuation, #495057)"
59187
+ };
59188
+ /** 单字符数超长保护上限(与宿主 `TOKENIZE_MAX_LINE_LENGTH` 对齐,防止超长单行卡顿)。 */
59189
+ const MAX_HIGHLIGHT_CHARS = 1e5;
59190
+ const TS_KEYWORDS = /* @__PURE__ */ new Set([
59191
+ "as",
59192
+ "async",
59193
+ "await",
59194
+ "break",
59195
+ "case",
59196
+ "catch",
59197
+ "class",
59198
+ "const",
59199
+ "continue",
59200
+ "debugger",
59201
+ "declare",
59202
+ "default",
59203
+ "delete",
59204
+ "do",
59205
+ "else",
59206
+ "enum",
59207
+ "export",
59208
+ "extends",
59209
+ "finally",
59210
+ "for",
59211
+ "from",
59212
+ "function",
59213
+ "get",
59214
+ "if",
59215
+ "implements",
59216
+ "import",
59217
+ "in",
59218
+ "infer",
59219
+ "instanceof",
59220
+ "interface",
59221
+ "is",
59222
+ "keyof",
59223
+ "let",
59224
+ "module",
59225
+ "namespace",
59226
+ "new",
59227
+ "of",
59228
+ "override",
59229
+ "package",
59230
+ "private",
59231
+ "protected",
59232
+ "public",
59233
+ "readonly",
59234
+ "return",
59235
+ "satisfies",
59236
+ "set",
59237
+ "static",
59238
+ "super",
59239
+ "switch",
59240
+ "throw",
59241
+ "try",
59242
+ "type",
59243
+ "typeof",
59244
+ "using",
59245
+ "var",
59246
+ "void",
59247
+ "while",
59248
+ "with",
59249
+ "yield"
59250
+ ]);
59251
+ const TS_CONSTANTS = /* @__PURE__ */ new Set([
59252
+ "true",
59253
+ "false",
59254
+ "null",
59255
+ "undefined",
59256
+ "NaN",
59257
+ "Infinity",
59258
+ "this",
59259
+ "globalThis",
59260
+ "console",
59261
+ "Promise",
59262
+ "Math",
59263
+ "JSON",
59264
+ "Object",
59265
+ "Array",
59266
+ "Map",
59267
+ "Set",
59268
+ "RegExp",
59269
+ "Error",
59270
+ "String",
59271
+ "Number",
59272
+ "Boolean",
59273
+ "Buffer",
59274
+ "process"
59275
+ ]);
59276
+ const PY_KEYWORDS = /* @__PURE__ */ new Set([
59277
+ "and",
59278
+ "as",
59279
+ "assert",
59280
+ "async",
59281
+ "await",
59282
+ "break",
59283
+ "class",
59284
+ "continue",
59285
+ "def",
59286
+ "del",
59287
+ "elif",
59288
+ "else",
59289
+ "except",
59290
+ "finally",
59291
+ "for",
59292
+ "from",
59293
+ "global",
59294
+ "if",
59295
+ "import",
59296
+ "in",
59297
+ "is",
59298
+ "lambda",
59299
+ "match",
59300
+ "nonlocal",
59301
+ "not",
59302
+ "or",
59303
+ "pass",
59304
+ "raise",
59305
+ "return",
59306
+ "try",
59307
+ "while",
59308
+ "with",
59309
+ "yield"
59310
+ ]);
59311
+ const PY_CONSTANTS = /* @__PURE__ */ new Set([
59312
+ "True",
59313
+ "False",
59314
+ "None",
59315
+ "self",
59316
+ "cls",
59317
+ "Ellipsis",
59318
+ "NotImplemented"
59319
+ ]);
59320
+ /** 允许紧跟正则表达式字面量的前置关键字。 */
59321
+ const REGEX_PRECEDING_KEYWORDS = /* @__PURE__ */ new Set([
59322
+ "return",
59323
+ "throw",
59324
+ "case",
59325
+ "in",
59326
+ "of",
59327
+ "typeof",
59328
+ "instanceof",
59329
+ "void",
59330
+ "delete",
59331
+ "new",
59332
+ "yield",
59333
+ "await"
59334
+ ]);
59335
+ /** 允许紧跟正则表达式字面量的末尾标点字符。 */
59336
+ const REGEX_PRECEDING_PUNCT = /* @__PURE__ */ new Set([
59337
+ "(",
59338
+ "[",
59339
+ "{",
59340
+ ",",
59341
+ ";",
59342
+ ":",
59343
+ "=",
59344
+ "!",
59345
+ "?",
59346
+ "&",
59347
+ "|",
59348
+ "^",
59349
+ "~",
59350
+ "+",
59351
+ "-",
59352
+ "*",
59353
+ "%",
59354
+ "<",
59355
+ ">"
59356
+ ]);
59357
+ /**
59358
+ * 将完整源码切分为带颜色类别的跨行数组(每个子数组代表源码的一行)。
59359
+ */
59360
+ function tokenizeCodeLines(code, language = "typescript") {
59361
+ const normalized = code.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
59362
+ const trimmed = normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
59363
+ if (trimmed.length === 0) return [[{
59364
+ text: "",
59365
+ kind: "plain"
59366
+ }]];
59367
+ if (trimmed.length > MAX_HIGHLIGHT_CHARS) return trimmed.split("\n").map((line) => [{
59368
+ text: line,
59369
+ kind: "plain"
59370
+ }]);
59371
+ return splitTokensIntoLines(language === "python" ? scanPython(trimmed) : scanTypeScript(trimmed));
59372
+ }
59373
+ function pushToken(out, text, kind) {
59374
+ if (text.length === 0) return;
59375
+ const prev = out[out.length - 1];
59376
+ if (prev !== void 0 && prev.kind === kind) {
59377
+ out[out.length - 1] = {
59378
+ text: prev.text + text,
59379
+ kind
59380
+ };
59381
+ return;
59382
+ }
59383
+ out.push({
59384
+ text,
59385
+ kind
59386
+ });
59387
+ }
59388
+ function splitTokensIntoLines(tokens) {
59389
+ const lines = [[]];
59390
+ for (const token of tokens) {
59391
+ const parts = token.text.split("\n");
59392
+ for (let index = 0; index < parts.length; index += 1) {
59393
+ if (index > 0) lines.push([]);
59394
+ const part = parts[index];
59395
+ if (part.length > 0) lines[lines.length - 1].push({
59396
+ text: part,
59397
+ kind: token.kind
59398
+ });
59399
+ }
59400
+ }
59401
+ return lines;
59402
+ }
59403
+ function isIdentStart(ch) {
59404
+ return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch === 95 || ch === 36 || ch > 127;
59405
+ }
59406
+ function isIdentPart(ch) {
59407
+ return isIdentStart(ch) || ch >= 48 && ch <= 57;
59408
+ }
59409
+ function isDigit(ch) {
59410
+ return ch >= 48 && ch <= 57;
59411
+ }
59412
+ function skipWhitespaceLookahead(src, from) {
59413
+ let pos = from;
59414
+ while (pos < src.length) {
59415
+ const ch = src.charCodeAt(pos);
59416
+ if (ch === 32 || ch === 9) pos += 1;
59417
+ else break;
59418
+ }
59419
+ return pos;
59420
+ }
59421
+ function scanNumber(src, start) {
59422
+ let i = start;
59423
+ if (src[i] === "0" && i + 1 < src.length && /[xXbBoO]/.test(src[i + 1])) {
59424
+ i += 2;
59425
+ while (i < src.length && /[0-9a-fA-F_]/.test(src[i])) i += 1;
59426
+ if (src[i] === "n") i += 1;
59427
+ return i;
59428
+ }
59429
+ while (i < src.length && (isDigit(src.charCodeAt(i)) || src[i] === "_")) i += 1;
59430
+ if (src[i] === "." && i + 1 < src.length && isDigit(src.charCodeAt(i + 1))) {
59431
+ i += 1;
59432
+ while (i < src.length && (isDigit(src.charCodeAt(i)) || src[i] === "_")) i += 1;
59433
+ }
59434
+ if (i < src.length && (src[i] === "e" || src[i] === "E")) {
59435
+ let next = i + 1;
59436
+ if (src[next] === "+" || src[next] === "-") next += 1;
59437
+ if (next < src.length && isDigit(src.charCodeAt(next))) {
59438
+ i = next + 1;
59439
+ while (i < src.length && (isDigit(src.charCodeAt(i)) || src[i] === "_")) i += 1;
59440
+ }
59441
+ }
59442
+ if (src[i] === "n") i += 1;
59443
+ return i;
59444
+ }
59445
+ /**
59446
+ * 尝试从 `start`(`src[start] === '/'`)扫描单行正则表达式字面量;不合法时返回 -1。
59447
+ */
59448
+ function tryScanRegexLiteral(src, start) {
59449
+ let i = start + 1;
59450
+ let inCharClass = false;
59451
+ if (i >= src.length || src[i] === "\n") return -1;
59452
+ while (i < src.length) {
59453
+ const ch = src[i];
59454
+ if (ch === "\n") return -1;
59455
+ if (ch === "\\") {
59456
+ if (i + 1 >= src.length || src[i + 1] === "\n") return -1;
59457
+ i += 2;
59458
+ continue;
59459
+ }
59460
+ if (ch === "[") {
59461
+ inCharClass = true;
59462
+ i += 1;
59463
+ continue;
59464
+ }
59465
+ if (ch === "]") {
59466
+ inCharClass = false;
59467
+ i += 1;
59468
+ continue;
59469
+ }
59470
+ if (ch === "/" && !inCharClass) {
59471
+ i += 1;
59472
+ while (i < src.length && /[dgimsuvy]/.test(src[i])) i += 1;
59473
+ return i;
59474
+ }
59475
+ i += 1;
59476
+ }
59477
+ return -1;
59478
+ }
59479
+ function scanTypeScript(src) {
59480
+ const tokens = [];
59481
+ /** 模板字符串 `${ ... }` 嵌套栈:记录每一层尚未闭合的左花括号深度。 */
59482
+ const templateBraceStack = [];
59483
+ let canStartRegex = true;
59484
+ let i = 0;
59485
+ const scanTemplateBody = (from) => {
59486
+ let pos = from;
59487
+ let segStart = pos;
59488
+ while (pos < src.length) {
59489
+ const ch = src[pos];
59490
+ if (ch === "\\") {
59491
+ pos = Math.min(src.length, pos + 2);
59492
+ continue;
59493
+ }
59494
+ if (ch === "`") {
59495
+ pushToken(tokens, src.slice(segStart, pos + 1), "string");
59496
+ canStartRegex = false;
59497
+ return pos + 1;
59498
+ }
59499
+ if (ch === "$" && src[pos + 1] === "{") {
59500
+ if (pos > segStart) pushToken(tokens, src.slice(segStart, pos), "string");
59501
+ pushToken(tokens, "${", "punctuation");
59502
+ templateBraceStack.push(0);
59503
+ canStartRegex = true;
59504
+ return pos + 2;
59505
+ }
59506
+ pos += 1;
59507
+ }
59508
+ pushToken(tokens, src.slice(segStart), "string");
59509
+ canStartRegex = false;
59510
+ return pos;
59511
+ };
59512
+ while (i < src.length) {
59513
+ const ch = src[i];
59514
+ const code = src.charCodeAt(i);
59515
+ if (ch === " " || ch === " " || ch === "\n") {
59516
+ let end = i + 1;
59517
+ while (end < src.length && (src[end] === " " || src[end] === " " || src[end] === "\n")) end += 1;
59518
+ pushToken(tokens, src.slice(i, end), "plain");
59519
+ i = end;
59520
+ continue;
59521
+ }
59522
+ if (ch === "/" && src[i + 1] === "/") {
59523
+ const nl = src.indexOf("\n", i + 2);
59524
+ const end = nl === -1 ? src.length : nl;
59525
+ pushToken(tokens, src.slice(i, end), "comment");
59526
+ i = end;
59527
+ continue;
59528
+ }
59529
+ if (ch === "/" && src[i + 1] === "*") {
59530
+ const close = src.indexOf("*/", i + 2);
59531
+ const end = close === -1 ? src.length : close + 2;
59532
+ pushToken(tokens, src.slice(i, end), "comment");
59533
+ i = end;
59534
+ continue;
59535
+ }
59536
+ if (ch === "/" && canStartRegex) {
59537
+ const regexEnd = tryScanRegexLiteral(src, i);
59538
+ if (regexEnd > i) {
59539
+ pushToken(tokens, src.slice(i, regexEnd), "string-expression");
59540
+ canStartRegex = false;
59541
+ i = regexEnd;
59542
+ continue;
59543
+ }
59544
+ }
59545
+ if (ch === "\"" || ch === "'") {
59546
+ let end = i + 1;
59547
+ while (end < src.length) {
59548
+ const c = src[end];
59549
+ if (c === "\\") {
59550
+ end = Math.min(src.length, end + 2);
59551
+ continue;
59552
+ }
59553
+ end += 1;
59554
+ if (c === ch || c === "\n") break;
59555
+ }
59556
+ pushToken(tokens, src.slice(i, end), "string");
59557
+ canStartRegex = false;
59558
+ i = end;
59559
+ continue;
59560
+ }
59561
+ if (ch === "`") {
59562
+ pushToken(tokens, "`", "string");
59563
+ i = scanTemplateBody(i + 1);
59564
+ continue;
59565
+ }
59566
+ if (ch === "{" && templateBraceStack.length > 0) {
59567
+ templateBraceStack[templateBraceStack.length - 1] += 1;
59568
+ pushToken(tokens, "{", "punctuation");
59569
+ canStartRegex = true;
59570
+ i += 1;
59571
+ continue;
59572
+ }
59573
+ if (ch === "}" && templateBraceStack.length > 0) {
59574
+ const top = templateBraceStack[templateBraceStack.length - 1];
59575
+ if (top === 0) {
59576
+ templateBraceStack.pop();
59577
+ pushToken(tokens, "}", "punctuation");
59578
+ i = scanTemplateBody(i + 1);
59579
+ continue;
59580
+ }
59581
+ templateBraceStack[templateBraceStack.length - 1] = top - 1;
59582
+ pushToken(tokens, "}", "punctuation");
59583
+ canStartRegex = false;
59584
+ i += 1;
59585
+ continue;
59586
+ }
59587
+ if (isDigit(code) || ch === "." && i + 1 < src.length && isDigit(src.charCodeAt(i + 1))) {
59588
+ const end = scanNumber(src, i);
59589
+ pushToken(tokens, src.slice(i, end), "constant");
59590
+ canStartRegex = false;
59591
+ i = end;
59592
+ continue;
59593
+ }
59594
+ if (isIdentStart(code)) {
59595
+ let end = i + 1;
59596
+ while (end < src.length && isIdentPart(src.charCodeAt(end))) end += 1;
59597
+ const word = src.slice(i, end);
59598
+ let prevNonSpace = i - 1;
59599
+ while (prevNonSpace >= 0 && (src[prevNonSpace] === " " || src[prevNonSpace] === " ")) prevNonSpace -= 1;
59600
+ const afterDot = prevNonSpace >= 0 && (src[prevNonSpace] === "." || src[prevNonSpace] === "?");
59601
+ const beforeCall = src[skipWhitespaceLookahead(src, end)] === "(";
59602
+ if (!afterDot && TS_KEYWORDS.has(word)) {
59603
+ pushToken(tokens, word, "keyword");
59604
+ canStartRegex = REGEX_PRECEDING_KEYWORDS.has(word);
59605
+ } else if (!afterDot && TS_CONSTANTS.has(word)) {
59606
+ pushToken(tokens, word, "constant");
59607
+ canStartRegex = false;
59608
+ } else if (beforeCall) {
59609
+ pushToken(tokens, word, "function");
59610
+ canStartRegex = false;
59611
+ } else if (/^[A-Z][A-Z0-9_]{2,}$/.test(word)) {
59612
+ pushToken(tokens, word, "constant");
59613
+ canStartRegex = false;
59614
+ } else {
59615
+ pushToken(tokens, word, "plain");
59616
+ canStartRegex = false;
59617
+ }
59618
+ i = end;
59619
+ continue;
59620
+ }
59621
+ if (ch === "@" && i + 1 < src.length && isIdentStart(src.charCodeAt(i + 1))) {
59622
+ let end = i + 2;
59623
+ while (end < src.length && isIdentPart(src.charCodeAt(end))) end += 1;
59624
+ pushToken(tokens, src.slice(i, end), "function");
59625
+ canStartRegex = false;
59626
+ i = end;
59627
+ continue;
59628
+ }
59629
+ pushToken(tokens, ch, "punctuation");
59630
+ canStartRegex = REGEX_PRECEDING_PUNCT.has(ch);
59631
+ i += 1;
59632
+ }
59633
+ return tokens;
59634
+ }
59635
+ function scanPython(src) {
59636
+ const tokens = [];
59637
+ let i = 0;
59638
+ while (i < src.length) {
59639
+ const ch = src[i];
59640
+ const code = src.charCodeAt(i);
59641
+ if (ch === " " || ch === " " || ch === "\n") {
59642
+ let end = i + 1;
59643
+ while (end < src.length && (src[end] === " " || src[end] === " " || src[end] === "\n")) end += 1;
59644
+ pushToken(tokens, src.slice(i, end), "plain");
59645
+ i = end;
59646
+ continue;
59647
+ }
59648
+ if (ch === "#") {
59649
+ const nl = src.indexOf("\n", i + 1);
59650
+ const end = nl === -1 ? src.length : nl;
59651
+ pushToken(tokens, src.slice(i, end), "comment");
59652
+ i = end;
59653
+ continue;
59654
+ }
59655
+ let strStart = i;
59656
+ if (/[rRfFbBuU]/.test(ch)) {
59657
+ let p = i + 1;
59658
+ if (p < src.length && /[rRfFbBuU]/.test(src[p])) p += 1;
59659
+ if (src[p] === "\"" || src[p] === "'") strStart = p;
59660
+ }
59661
+ if (src[strStart] === "\"" || src[strStart] === "'") {
59662
+ const quote = src[strStart];
59663
+ const triple = src[strStart + 1] === quote && src[strStart + 2] === quote;
59664
+ const delim = triple ? quote.repeat(3) : quote;
59665
+ let end = strStart + delim.length;
59666
+ while (end < src.length) {
59667
+ if (src[end] === "\\") {
59668
+ end = Math.min(src.length, end + 2);
59669
+ continue;
59670
+ }
59671
+ if (triple && src.startsWith(delim, end)) {
59672
+ end += 3;
59673
+ break;
59674
+ }
59675
+ if (!triple && (src[end] === quote || src[end] === "\n")) {
59676
+ if (src[end] === quote) end += 1;
59677
+ break;
59678
+ }
59679
+ end += 1;
59680
+ }
59681
+ pushToken(tokens, src.slice(i, end), "string");
59682
+ i = end;
59683
+ continue;
59684
+ }
59685
+ if (isDigit(code) || ch === "." && i + 1 < src.length && isDigit(src.charCodeAt(i + 1))) {
59686
+ const end = scanNumber(src, i);
59687
+ pushToken(tokens, src.slice(i, end), "constant");
59688
+ i = end;
59689
+ continue;
59690
+ }
59691
+ if (isIdentStart(code)) {
59692
+ let end = i + 1;
59693
+ while (end < src.length && isIdentPart(src.charCodeAt(end))) end += 1;
59694
+ const word = src.slice(i, end);
59695
+ let prevNonSpace = i - 1;
59696
+ while (prevNonSpace >= 0 && (src[prevNonSpace] === " " || src[prevNonSpace] === " ")) prevNonSpace -= 1;
59697
+ const afterDot = prevNonSpace >= 0 && src[prevNonSpace] === ".";
59698
+ const beforeCall = src[skipWhitespaceLookahead(src, end)] === "(";
59699
+ if (!afterDot && PY_KEYWORDS.has(word)) pushToken(tokens, word, "keyword");
59700
+ else if (!afterDot && PY_CONSTANTS.has(word)) pushToken(tokens, word, "constant");
59701
+ else if (beforeCall) pushToken(tokens, word, "function");
59702
+ else pushToken(tokens, word, "plain");
59703
+ i = end;
59704
+ continue;
59705
+ }
59706
+ if (ch === "@" && i + 1 < src.length && isIdentStart(src.charCodeAt(i + 1))) {
59707
+ let end = i + 2;
59708
+ while (end < src.length && isIdentPart(src.charCodeAt(end))) end += 1;
59709
+ pushToken(tokens, src.slice(i, end), "function");
59710
+ i = end;
59711
+ continue;
59712
+ }
59713
+ pushToken(tokens, ch, "punctuation");
59714
+ i += 1;
59715
+ }
59716
+ return tokens;
59717
+ }
59718
+ //#endregion
59719
+ //#region src/client/codemode/CodeRunToolView.tsx
59720
+ /**
59721
+ * `code_run` 在对话流中的语法高亮工具行组件 —— 对齐宿主内置 PTC `run_code` 的呈现体验。
59722
+ *
59723
+ * ## 与宿主 `run_code` 一致的四点设计
59724
+ *
59725
+ * 1. **标题行**:代码图标 `</>` + 本地化标题「代码 / Code」+ `description` 摘要(不再出现
59726
+ * `工具 · code_run · ...`),直接接入框架传入的 `useDisclosure` 控制展开/收起;
59727
+ * 2. **源码区**:提取 `args.code` 纯源码文本(剥离外层 JSON 参数包装),提供语言标识
59728
+ * (`typescript` / `python`)、自动换行切换与一键复制源码按钮,并使用宿主 `--shiki-*`
59729
+ * 主题色进行语法高亮;
59730
+ * 3. **输出区**:已结算结果独立展示在下方 `输出` 卡片中(无结果文本时不画空卡片),子调用由外层
59731
+ * `ToolCallTree` 通过 `tool/ptc-dispatch` 自动挂载在本行下方;
59732
+ * 4. **三阶段支持**:覆盖 `preparing`(流式生成参数)、`start`(执行中)与 `result`(成功/失败/停止)。
59733
+ *
59734
+ * @module @eddyskywalker/dsh-chatgpt-subscription/client/codemode/CodeRunToolView
59735
+ */
59736
+ function fallbackTranslate(key) {
59737
+ return zh$2[key] ?? key;
59738
+ }
59739
+ function firstLine(text) {
59740
+ const nl = text.indexOf("\n");
59741
+ return nl === -1 ? text : text.slice(0, nl);
59742
+ }
59743
+ function rawArgsOf(block) {
59744
+ if (typeof block.argsRaw === "string" && block.argsRaw !== "") return block.argsRaw;
59745
+ if (typeof block.call?.argsRaw === "string" && block.call.argsRaw !== "") return block.call.argsRaw;
59746
+ }
59747
+ function parseArgsObject(raw) {
59748
+ if (raw === void 0 || raw === "") return void 0;
59749
+ try {
59750
+ const parsed = JSON.parse(raw);
59751
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) return parsed;
59752
+ return;
59753
+ } catch {
59754
+ return;
59755
+ }
59756
+ }
59757
+ /** 从流式参数视图或完整 JSON 中读取字段(与 `ProgressRow` / `MinimaxVideoToolView` 一致)。 */
59758
+ function extractCodeRunArgs(block) {
59759
+ let streamCode;
59760
+ let streamDesc;
59761
+ const readText = block.args?.text;
59762
+ if (typeof readText === "function") {
59763
+ try {
59764
+ const c = readText.call(block.args, "code");
59765
+ if (typeof c === "string" && c !== "") streamCode = c;
59766
+ } catch {}
59767
+ try {
59768
+ const d = readText.call(block.args, "description");
59769
+ if (typeof d === "string" && d !== "") streamDesc = d;
59770
+ } catch {}
59771
+ }
59772
+ const raw = rawArgsOf(block);
59773
+ const parsed = parseArgsObject(raw);
59774
+ const jsonCode = typeof parsed?.["code"] === "string" && parsed["code"] !== "" ? parsed["code"] : void 0;
59775
+ const jsonDesc = typeof parsed?.["description"] === "string" && parsed["description"] !== "" ? parsed["description"] : void 0;
59776
+ const code = jsonCode ?? streamCode ?? null;
59777
+ return {
59778
+ code,
59779
+ description: firstLine(jsonDesc ?? streamDesc ?? ""),
59780
+ rawFallback: code === null && raw !== void 0 ? raw : null
59781
+ };
59782
+ }
59783
+ /** 展平已结算结果的内容块(对齐宿主 `resultText`)。 */
59784
+ function flattenCodeRunOutput(block) {
59785
+ if (block.kind === void 0) return null;
59786
+ const parts = [];
59787
+ for (const item of block.content ?? []) if (item.type === "text" && typeof item.text === "string") parts.push(item.text);
59788
+ else try {
59789
+ parts.push(JSON.stringify(item, null, 2));
59790
+ } catch {
59791
+ parts.push(String(item));
59792
+ }
59793
+ if (parts.length === 0 && block.error !== void 0) {
59794
+ const errName = block.error.name ?? "Error";
59795
+ const errCode = block.error.code ?? "UNKNOWN";
59796
+ parts.push(`${errName}: ${errCode}`);
59797
+ }
59798
+ const joined = parts.join("\n");
59799
+ return joined === "" ? null : joined;
59800
+ }
59801
+ function resolveLanguage(meta) {
59802
+ if (typeof meta === "object" && meta !== null && !Array.isArray(meta)) {
59803
+ if (meta["language"] === "python") return "python";
59804
+ }
59805
+ return "typescript";
59806
+ }
59807
+ function resolveState(phase, block) {
59808
+ if (!(block.kind !== void 0 || phase === "result")) return block.phase === "preparing" || phase === "preparing" ? "preparing" : "running";
59809
+ if (block.error?.code === "interrupted") return "stopped";
59810
+ const stopped = typeof block.meta === "object" && block.meta !== null && !Array.isArray(block.meta) && block.meta["stopped"] === true;
59811
+ if (block.isError === true || stopped) return "error";
59812
+ return "ok";
59813
+ }
59814
+ async function copyTextToClipboard(text) {
59815
+ try {
59816
+ if (typeof navigator !== "undefined" && typeof navigator.clipboard?.writeText === "function") {
59817
+ await navigator.clipboard.writeText(text);
59818
+ return true;
59819
+ }
59820
+ } catch {}
59821
+ if (typeof document === "undefined") return false;
59822
+ try {
59823
+ const textarea = document.createElement("textarea");
59824
+ textarea.value = text;
59825
+ textarea.setAttribute("readonly", "true");
59826
+ textarea.style.position = "fixed";
59827
+ textarea.style.opacity = "0";
59828
+ document.body.appendChild(textarea);
59829
+ textarea.select();
59830
+ const ok = document.execCommand("copy");
59831
+ document.body.removeChild(textarea);
59832
+ return ok;
59833
+ } catch {
59834
+ return false;
59835
+ }
59836
+ }
59837
+ function useFallbackDisclosure() {
59838
+ const [expanded, setExpanded] = (0, react.useState)(false);
59839
+ return {
59840
+ expanded,
59841
+ toggle: (0, react.useCallback)(() => {
59842
+ setExpanded((prev) => !prev);
59843
+ }, [])
59844
+ };
59845
+ }
59846
+ function CodeRunToolView(props) {
59847
+ const { block, phase, inspect, useDisclosure } = props;
59848
+ const t = props.t ?? fallbackTranslate;
59849
+ const { expanded, toggle } = (useDisclosure ?? useFallbackDisclosure)();
59850
+ const [wrapped, setWrapped] = (0, react.useState)(true);
59851
+ const [copied, setCopied] = (0, react.useState)(false);
59852
+ const state = resolveState(phase, block);
59853
+ const { code, description, rawFallback } = (0, react.useMemo)(() => extractCodeRunArgs(block), [block]);
59854
+ const outputText = (0, react.useMemo)(() => flattenCodeRunOutput(block), [block]);
59855
+ const language = (0, react.useMemo)(() => resolveLanguage(block.meta), [block.meta]);
59856
+ const sourceText = code ?? rawFallback;
59857
+ const expandable = state !== "preparing" && (sourceText !== null || outputText !== null);
59858
+ const open = expanded && expandable;
59859
+ const running = state === "preparing" || state === "running";
59860
+ const summaryText = (state === "error" && outputText !== null ? firstLine(outputText) : null) ?? (description !== "" ? description : block.callId ?? "");
59861
+ const highlightedLines = (0, react.useMemo)(() => open && sourceText !== null ? tokenizeCodeLines(sourceText, language) : null, [
59862
+ open,
59863
+ sourceText,
59864
+ language
59865
+ ]);
59866
+ const onCopy = (0, react.useCallback)(() => {
59867
+ if (copied || sourceText === null) return;
59868
+ copyTextToClipboard(sourceText.endsWith("\n") ? sourceText.slice(0, -1) : sourceText).then((ok) => {
59869
+ if (!ok) return;
59870
+ setCopied(true);
59871
+ setTimeout(() => {
59872
+ setCopied(false);
59873
+ }, 1e3);
59874
+ });
59875
+ }, [copied, sourceText]);
59876
+ const onRowKeyDown = (0, react.useCallback)((event) => {
59877
+ if (!expandable || event.key !== "Enter" && event.key !== " ") return;
59878
+ event.preventDefault();
59879
+ toggle();
59880
+ }, [expandable, toggle]);
59881
+ const a11yStatus = state === "preparing" ? t("codeRunPreparing") : state === "running" ? t("codeRunRunning") : state === "error" ? t("codeRunFailed") : state === "stopped" ? t("codeRunStopped") : null;
59882
+ const wrapLabel = wrapped ? t("codeRunUnwrap") : t("codeRunWrap");
59883
+ const copyLabel = copied ? t("codeRunCopied") : t("codeRunCopy");
59884
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59885
+ className: "dshc-code-root",
59886
+ "data-variant": "code",
59887
+ "data-tool": props.toolName ?? "code_run",
59888
+ "data-state": state,
59889
+ children: [
59890
+ a11yStatus !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59891
+ className: "dshc-code-visually-hidden",
59892
+ children: a11yStatus
59893
+ }),
59894
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
59895
+ className: "dshc-code-header",
59896
+ "data-disclosure-header": true,
59897
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59898
+ className: "dshc-code-row",
59899
+ "data-disclosure-row": true,
59900
+ "data-expandable": expandable ? "true" : void 0,
59901
+ role: expandable ? "button" : void 0,
59902
+ tabIndex: expandable ? 0 : void 0,
59903
+ "aria-expanded": expandable ? open : void 0,
59904
+ onClick: expandable ? toggle : void 0,
59905
+ onKeyDown: expandable ? onRowKeyDown : void 0,
59906
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59907
+ className: "dshc-code-leading",
59908
+ "aria-hidden": "true",
59909
+ children: open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronUpIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59910
+ className: "dshc-code-icon-idle",
59911
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeGlyphIcon, {})
59912
+ }), expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59913
+ className: "dshc-code-chevron-hover",
59914
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, {})
59915
+ })] })
59916
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
59917
+ className: "dshc-code-text-flow",
59918
+ "data-running": running ? "true" : void 0,
59919
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59920
+ className: "dshc-code-title",
59921
+ children: t("codeRunTitle")
59922
+ }), summaryText !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59923
+ className: "dshc-code-sep",
59924
+ "aria-hidden": "true"
59925
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59926
+ className: "dshc-code-summary",
59927
+ "data-state": state === "error" || state === "stopped" ? state : void 0,
59928
+ children: summaryText
59929
+ })] })]
59930
+ })]
59931
+ })
59932
+ }),
59933
+ open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59934
+ className: "dshc-code-body-wrap",
59935
+ children: [
59936
+ sourceText !== null && highlightedLines !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
59937
+ className: "dshc-code-body-scroll",
59938
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59939
+ className: "dshc-code-card md-code-block",
59940
+ "data-code-wrap": wrapped ? "true" : "false",
59941
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59942
+ className: "dshc-code-toolbar",
59943
+ "data-code-block-banner": true,
59944
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59945
+ className: "dshc-code-lang",
59946
+ children: language
59947
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59948
+ className: "dshc-code-actions",
59949
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
59950
+ type: "button",
59951
+ className: "dshc-code-action",
59952
+ title: wrapLabel,
59953
+ "aria-label": t("codeRunWrap"),
59954
+ "aria-pressed": wrapped,
59955
+ onClick: () => {
59956
+ setWrapped((prev) => !prev);
59957
+ },
59958
+ children: wrapped ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NowrapIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WrapIcon, {})
59959
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
59960
+ type: "button",
59961
+ className: "dshc-code-action",
59962
+ title: copyLabel,
59963
+ "aria-label": copyLabel,
59964
+ onClick: onCopy,
59965
+ children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CheckIcon, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopyIcon, {})
59966
+ })]
59967
+ })]
59968
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
59969
+ className: "shiki css-variables dshc-code-pre",
59970
+ tabIndex: 0,
59971
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: highlightedLines.map((line, lineIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [lineIndex > 0 && "\n", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59972
+ className: "line",
59973
+ children: line.map((span, spanIndex) => {
59974
+ const color = SHIKI_TOKEN_COLORS[span.kind];
59975
+ return color === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.Fragment, { children: span.text }, spanIndex) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59976
+ style: { color },
59977
+ children: span.text
59978
+ }, spanIndex);
59979
+ })
59980
+ })] }, lineIndex)) })
59981
+ })]
59982
+ })
59983
+ }),
59984
+ outputText !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
59985
+ className: "dshc-code-io-card",
59986
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
59987
+ className: "dshc-code-io-section",
59988
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59989
+ className: "dshc-code-io-label",
59990
+ children: t("codeRunOutput")
59991
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
59992
+ className: "dshc-code-io-text",
59993
+ "data-error": state === "error" ? "true" : void 0,
59994
+ children: outputText
59995
+ })]
59996
+ })
59997
+ }),
59998
+ inspect !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
59999
+ type: "button",
60000
+ className: "dshc-code-inspect-btn",
60001
+ onClick: inspect,
60002
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InspectIcon, {}), t("codeRunInspect")]
60003
+ })
60004
+ ]
60005
+ })
60006
+ ]
60007
+ });
60008
+ }
60009
+ function CodeGlyphIcon() {
60010
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
60011
+ viewBox: "0 0 16 16",
60012
+ fill: "none",
60013
+ stroke: "currentColor",
60014
+ strokeWidth: "1.4",
60015
+ strokeLinecap: "round",
60016
+ strokeLinejoin: "round",
60017
+ children: [
60018
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.2 4.5L1.8 8l3.4 3.5" }),
60019
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.8 4.5L14.2 8l-3.4 3.5" }),
60020
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9.2 3L6.8 13" })
60021
+ ]
60022
+ });
60023
+ }
60024
+ function ChevronDownIcon() {
60025
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
60026
+ viewBox: "0 0 16 16",
60027
+ fill: "none",
60028
+ stroke: "currentColor",
60029
+ strokeWidth: "1.5",
60030
+ strokeLinecap: "round",
60031
+ strokeLinejoin: "round",
60032
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 6l4 4 4-4" })
60033
+ });
60034
+ }
60035
+ function ChevronUpIcon() {
60036
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
60037
+ viewBox: "0 0 16 16",
60038
+ fill: "none",
60039
+ stroke: "currentColor",
60040
+ strokeWidth: "1.5",
60041
+ strokeLinecap: "round",
60042
+ strokeLinejoin: "round",
60043
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 10l4-4 4 4" })
60044
+ });
60045
+ }
60046
+ function CopyIcon() {
60047
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
60048
+ width: "14",
60049
+ height: "14",
60050
+ viewBox: "0 0 16 16",
60051
+ fill: "none",
60052
+ stroke: "currentColor",
60053
+ strokeWidth: "1.35",
60054
+ strokeLinecap: "round",
60055
+ strokeLinejoin: "round",
60056
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
60057
+ x: "5.5",
60058
+ y: "5.5",
60059
+ width: "8",
60060
+ height: "8",
60061
+ rx: "1.5"
60062
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.5 5.5V3.8A1.3 1.3 0 0 0 9.2 2.5H3.8A1.3 1.3 0 0 0 2.5 3.8v5.4a1.3 1.3 0 0 0 1.3 1.3h1.7" })]
60063
+ });
60064
+ }
60065
+ function CheckIcon() {
60066
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
60067
+ width: "14",
60068
+ height: "14",
60069
+ viewBox: "0 0 16 16",
60070
+ fill: "none",
60071
+ stroke: "currentColor",
60072
+ strokeWidth: "1.6",
60073
+ strokeLinecap: "round",
60074
+ strokeLinejoin: "round",
60075
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M3.2 8.4l3.1 3.1 6.5-6.5" })
60076
+ });
60077
+ }
60078
+ function WrapIcon() {
60079
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
60080
+ width: "14",
60081
+ height: "14",
60082
+ viewBox: "0 0 16 16",
60083
+ fill: "none",
60084
+ stroke: "currentColor",
60085
+ strokeWidth: "1.35",
60086
+ strokeLinecap: "round",
60087
+ strokeLinejoin: "round",
60088
+ children: [
60089
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 4h11" }),
60090
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 8h8.5a2.2 2.2 0 1 1 0 4.4H8.2" }),
60091
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9.8 10.8L8 12.4l1.8 1.6" }),
60092
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 12.4h3" })
60093
+ ]
60094
+ });
60095
+ }
60096
+ function NowrapIcon() {
60097
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
60098
+ width: "14",
60099
+ height: "14",
60100
+ viewBox: "0 0 16 16",
60101
+ fill: "none",
60102
+ stroke: "currentColor",
60103
+ strokeWidth: "1.35",
60104
+ strokeLinecap: "round",
60105
+ strokeLinejoin: "round",
60106
+ children: [
60107
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 4h11" }),
60108
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 8h11" }),
60109
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M11.5 6.2L13.5 8l-2 1.8" }),
60110
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 12h7" })
60111
+ ]
60112
+ });
60113
+ }
60114
+ function InspectIcon() {
60115
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
60116
+ width: "12",
60117
+ height: "12",
60118
+ viewBox: "0 0 16 16",
60119
+ fill: "none",
60120
+ stroke: "currentColor",
60121
+ strokeWidth: "1.4",
60122
+ strokeLinecap: "round",
60123
+ strokeLinejoin: "round",
60124
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
60125
+ cx: "7.2",
60126
+ cy: "7.2",
60127
+ r: "4.5"
60128
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M10.6 10.6L13.8 13.8" })]
60129
+ });
60130
+ }
60131
+ //#endregion
60132
+ //#region src/client/codemode/styles.ts
60133
+ /**
60134
+ * `code_run` 工具行样式表 —— 对齐宿主内置 `run_code`(`DisclosureRow` + `ToolRow` +
60135
+ * `CodeBlock` + `CodeToolbar`)的视觉令牌与排版节奏。
60136
+ *
60137
+ * 所有颜色、字号与圆角均直接引用宿主 `--dsw-*` / `--dsh-*` / `--shiki-*` CSS 变量。
60138
+ *
60139
+ * @module @eddyskywalker/dsh-chatgpt-subscription/client/codemode/styles
60140
+ */
60141
+ const CODEMODE_CSS = `
60142
+ .dshc-code-root {
60143
+ display: flex;
60144
+ flex-direction: column;
60145
+ width: 100%;
60146
+ min-width: 0;
60147
+ }
60148
+
60149
+ .dshc-code-visually-hidden {
60150
+ position: absolute;
60151
+ width: 1px;
60152
+ height: 1px;
60153
+ overflow: hidden;
60154
+ clip: rect(0 0 0 0);
60155
+ white-space: nowrap;
60156
+ }
60157
+
60158
+ .dshc-code-header {
60159
+ display: flex;
60160
+ align-items: center;
60161
+ min-width: 0;
60162
+ }
60163
+
60164
+ .dshc-code-row {
60165
+ flex: 1 1 auto;
60166
+ position: relative;
60167
+ overflow: hidden;
60168
+ display: flex;
60169
+ align-items: center;
60170
+ height: calc(24px + var(--dsh-content-font-delta, 0px));
60171
+ min-width: 0;
60172
+ color: var(--dsw-alias-label-tertiary, #8a9099);
60173
+ transition: color 100ms ease;
60174
+ user-select: none;
60175
+ }
60176
+
60177
+ .dshc-code-row[data-expandable='true'] {
60178
+ cursor: pointer;
60179
+ }
60180
+
60181
+ @media (hover: hover) {
60182
+ .dshc-code-row:hover {
60183
+ color: var(--dsw-alias-label-secondary, #5b6270);
60184
+ }
60185
+ }
60186
+
60187
+ .dshc-code-row:focus-visible {
60188
+ outline: 1px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #4d6bfe));
60189
+ outline-offset: 2px;
60190
+ border-radius: var(--dsw-radius-sm, 4px);
60191
+ }
60192
+
60193
+ .dshc-code-leading {
60194
+ position: relative;
60195
+ flex: none;
60196
+ width: calc(16px + var(--dsh-content-font-delta, 0px));
60197
+ height: calc(16px + var(--dsh-content-font-delta, 0px));
60198
+ display: inline-flex;
60199
+ align-items: center;
60200
+ justify-content: center;
60201
+ margin-right: 6px;
60202
+ color: inherit;
60203
+ }
60204
+
60205
+ .dshc-code-leading svg {
60206
+ width: calc(14px + var(--dsh-content-font-delta, 0px));
60207
+ height: calc(14px + var(--dsh-content-font-delta, 0px));
60208
+ }
60209
+
60210
+ .dshc-code-icon-idle {
60211
+ display: inline-flex;
60212
+ opacity: 1;
60213
+ transition: opacity 100ms ease;
60214
+ }
60215
+
60216
+ .dshc-code-chevron-hover {
60217
+ position: absolute;
60218
+ inset: 0;
60219
+ margin: auto;
60220
+ opacity: 0;
60221
+ transition: opacity 100ms ease;
60222
+ }
60223
+
60224
+ @media (hover: hover) {
60225
+ .dshc-code-row[data-expandable='true']:hover .dshc-code-icon-idle {
60226
+ opacity: 0;
60227
+ }
60228
+ .dshc-code-row[data-expandable='true']:hover .dshc-code-chevron-hover {
60229
+ opacity: 1;
60230
+ }
60231
+ }
60232
+
60233
+ .dshc-code-text-flow {
60234
+ display: flex;
60235
+ align-items: center;
60236
+ flex: 1 1 auto;
60237
+ min-width: 0;
60238
+ overflow: hidden;
60239
+ }
60240
+
60241
+ @keyframes dshc-shimmer-pulse {
60242
+ 0%, 100% { opacity: 1; }
60243
+ 50% { opacity: 0.55; }
60244
+ }
60245
+
60246
+ .dshc-code-text-flow[data-running='true'] {
60247
+ animation: dshc-shimmer-pulse 1.6s ease-in-out infinite;
60248
+ }
60249
+
60250
+ .dshc-code-title {
60251
+ flex: none;
60252
+ font-weight: 400;
60253
+ font-size: var(--dsh-content-font-size-secondary, 13px);
60254
+ line-height: calc(24px + var(--dsh-content-font-delta, 0px));
60255
+ color: inherit;
60256
+ }
60257
+
60258
+ .dshc-code-sep {
60259
+ flex: none;
60260
+ width: 2px;
60261
+ height: 2px;
60262
+ border-radius: 1px;
60263
+ margin: 0 8px;
60264
+ background: var(--dsw-alias-label-caption, #8a9099);
60265
+ }
60266
+
60267
+ .dshc-code-summary {
60268
+ flex: 1 1 auto;
60269
+ min-width: 0;
60270
+ overflow: hidden;
60271
+ text-overflow: ellipsis;
60272
+ white-space: nowrap;
60273
+ font-size: var(--dsh-content-font-size-secondary, 13px);
60274
+ line-height: calc(24px + var(--dsh-content-font-delta, 0px));
60275
+ }
60276
+
60277
+ .dshc-code-summary[data-state='error'] {
60278
+ color: var(--dsw-alias-state-error-primary, #d54941);
60279
+ }
60280
+
60281
+ .dshc-code-summary[data-state='stopped'] {
60282
+ color: var(--dsw-alias-state-warn-label, #d97706);
60283
+ }
60284
+
60285
+ .dshc-code-body-wrap {
60286
+ display: flex;
60287
+ flex-direction: column;
60288
+ }
60289
+
60290
+ .dshc-code-body-scroll {
60291
+ max-height: 260px;
60292
+ overflow-y: auto;
60293
+ margin: 4px 0 4px 4px;
60294
+ border-radius: var(--dsw-radius-lg, 10px);
60295
+ border: 0.5px solid var(--dsw-alias-border-l1, rgba(128, 128, 128, 0.18));
60296
+ background: var(--dsw-alias-markdown-code-block, rgba(128, 128, 128, 0.08));
60297
+ }
60298
+
60299
+ .dshc-code-card {
60300
+ position: relative;
60301
+ color: var(--dsw-alias-label-primary, inherit);
60302
+ background: transparent;
60303
+ font: var(--dsw-font-markdown-code-block, 13px/20px var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace));
60304
+ }
60305
+
60306
+ .dshc-code-toolbar {
60307
+ position: sticky;
60308
+ top: 0;
60309
+ z-index: 6;
60310
+ display: flex;
60311
+ align-items: center;
60312
+ justify-content: space-between;
60313
+ gap: 12px;
60314
+ padding: 10px 18px 8px 22px;
60315
+ background: var(--dsw-alias-markdown-code-block, #1e222a);
60316
+ color: var(--dsw-alias-label-secondary, #8a9099);
60317
+ font: 11px/18px var(--dsw-font-family, system-ui, sans-serif);
60318
+ }
60319
+
60320
+ .dshc-code-lang {
60321
+ color: var(--dsw-alias-label-tertiary, #8a9099);
60322
+ flex: none;
60323
+ font-family: var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
60324
+ }
60325
+
60326
+ .dshc-code-actions {
60327
+ display: flex;
60328
+ align-items: center;
60329
+ gap: 4px;
60330
+ flex: none;
60331
+ }
60332
+
60333
+ .dshc-code-action {
60334
+ display: inline-flex;
60335
+ align-items: center;
60336
+ justify-content: center;
60337
+ width: 24px;
60338
+ height: 24px;
60339
+ padding: 0;
60340
+ border: 0;
60341
+ border-radius: var(--dsw-radius-sm, 4px);
60342
+ color: var(--dsw-alias-label-secondary, #8a9099);
60343
+ background: transparent;
60344
+ cursor: pointer;
60345
+ }
60346
+
60347
+ @media (hover: hover) {
60348
+ .dshc-code-action:hover {
60349
+ background: var(--dsw-alias-interactive-bg-hover, rgba(128, 128, 128, 0.14));
60350
+ color: var(--dsw-alias-label-primary, inherit);
60351
+ }
60352
+ }
60353
+
60354
+ .dshc-code-action:focus-visible {
60355
+ outline: 1px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #4d6bfe));
60356
+ outline-offset: 2px;
60357
+ }
60358
+
60359
+ .dshc-code-pre {
60360
+ margin: 0 !important;
60361
+ padding: 6px 22px 20px;
60362
+ font: var(--dsw-font-markdown-code-block, 13px/20px var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace));
60363
+ background: transparent !important;
60364
+ color: var(--shiki-foreground, var(--dsw-alias-label-primary, inherit));
60365
+ overflow-x: auto;
60366
+ white-space: pre-wrap;
60367
+ word-break: normal;
60368
+ overflow-wrap: anywhere;
60369
+ }
60370
+
60371
+ .dshc-code-card[data-code-wrap='false'] .dshc-code-pre {
60372
+ white-space: pre;
60373
+ overflow-wrap: normal;
60374
+ }
60375
+
60376
+ .dshc-code-pre code {
60377
+ font: inherit;
60378
+ background: none;
60379
+ padding: 0;
60380
+ }
60381
+
60382
+ .dshc-code-io-card {
60383
+ display: flex;
60384
+ flex-direction: column;
60385
+ margin: 4px 0 4px 4px;
60386
+ border: 0.5px solid var(--dsw-alias-border-l1, rgba(128, 128, 128, 0.18));
60387
+ border-radius: var(--dsw-radius-lg, 10px);
60388
+ background: var(--dsw-alias-markdown-code-block, rgba(128, 128, 128, 0.08));
60389
+ font: var(--dsw-font-markdown-code-block-small, 12px/18px var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace));
60390
+ }
60391
+
60392
+ .dshc-code-io-section {
60393
+ display: grid;
60394
+ grid-template-columns: max-content 1fr;
60395
+ column-gap: 14px;
60396
+ align-items: baseline;
60397
+ padding: 12px 16px;
60398
+ max-height: 150px;
60399
+ overflow-y: auto;
60400
+ }
60401
+
60402
+ .dshc-code-io-label {
60403
+ position: sticky;
60404
+ top: 0;
60405
+ align-self: start;
60406
+ color: var(--dsw-alias-label-caption, #8a9099);
60407
+ }
60408
+
60409
+ .dshc-code-io-text {
60410
+ min-width: 0;
60411
+ white-space: pre-wrap;
60412
+ word-break: break-word;
60413
+ color: var(--dsw-alias-label-secondary, #8a9099);
60414
+ }
60415
+
60416
+ .dshc-code-io-text[data-error='true'] {
60417
+ color: var(--dsw-alias-state-error-primary, #d54941);
60418
+ }
60419
+
60420
+ .dshc-code-inspect-btn {
60421
+ display: inline-flex;
60422
+ align-self: flex-start;
60423
+ align-items: center;
60424
+ gap: 4px;
60425
+ margin: 4px 0 2px 4px;
60426
+ padding: 2px 8px;
60427
+ border: 0.5px solid var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.25));
60428
+ border-radius: 999px;
60429
+ background: var(--dsw-alias-bg-base, transparent);
60430
+ color: var(--dsw-alias-label-secondary, #8a9099);
60431
+ font-size: 11px;
60432
+ line-height: 16px;
60433
+ cursor: pointer;
60434
+ opacity: 0;
60435
+ transition: opacity 100ms ease;
60436
+ }
60437
+
60438
+ .dshc-code-inspect-btn:focus-visible {
60439
+ opacity: 1;
60440
+ }
60441
+
60442
+ @media (hover: hover) {
60443
+ .dshc-code-root:hover .dshc-code-inspect-btn {
60444
+ opacity: 1;
60445
+ }
60446
+ .dshc-code-inspect-btn:hover {
60447
+ background: var(--dsw-alias-interactive-bg-hover-solid, rgba(128, 128, 128, 0.18));
60448
+ color: var(--dsw-alias-label-primary, inherit);
60449
+ }
60450
+ }
60451
+
60452
+ @media (hover: none) {
60453
+ .dshc-code-inspect-btn {
60454
+ opacity: 1;
60455
+ }
60456
+ }
60457
+
60458
+ @media (prefers-reduced-motion: reduce) {
60459
+ .dshc-code-row,
60460
+ .dshc-code-text-flow[data-running='true'] {
60461
+ transition: none;
60462
+ animation: none;
60463
+ }
60464
+ }
60465
+ `;
60466
+ function installCodemodeStyles() {
60467
+ return installPluginStyle("codemode", CODEMODE_CSS);
60468
+ }
60469
+ //#endregion
60470
+ //#region src/client/codemode/tool-name.ts
60471
+ /**
60472
+ * 客户端半边的 `code_run` 工具名常量。
60473
+ *
60474
+ * 独立于 `../../host/codemode/transport.ts`,避免浏览器 bundle 引入 Node 端模块;
60475
+ * 单测会校验两边字面量逐字一致。
60476
+ *
60477
+ * @module @eddyskywalker/dsh-chatgpt-subscription/client/codemode/tool-name
60478
+ */
60479
+ const CODE_RUN_TOOL_NAME = "code_run";
60480
+ //#endregion
59028
60481
  //#region src/client/index.tsx
59029
60482
  const inject = [
59030
60483
  "slots",
@@ -59110,6 +60563,7 @@ window.__ModuleLoader__.load({
59110
60563
  }, "dsh-subagent-settings: styles");
59111
60564
  ctx.effect(() => {
59112
60565
  installPoolStyles();
60566
+ installCodemodeStyles();
59113
60567
  return () => {};
59114
60568
  }, "dsh-chatgpt-subscription: pool styles");
59115
60569
  ctx.effect(() => setupMermaidObserver(), "dsh-mermaid: observer");
@@ -59239,6 +60693,11 @@ window.__ModuleLoader__.load({
59239
60693
  readVideo: videoBytesLoader(ctx)
59240
60694
  })
59241
60695
  }, MinimaxVideoToolView));
60696
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
60697
+ name: "tool.call.toolview",
60698
+ key: CODE_RUN_TOOL_NAME,
60699
+ locale: NS
60700
+ }, CodeRunToolView));
59242
60701
  installVideoDocumentPreview(ctx);
59243
60702
  installSubagentSettingsCard(ctx);
59244
60703
  installProgressUpdatesClient(ctx);