@eddyskywalker/dsh-chatgpt-subscription 0.48.4 → 0.49.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 (43) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/lib/client.js +2381 -179
  3. package/lib/client.js.map +1 -1
  4. package/lib/index.js +829 -29
  5. package/lib/types/client/index.d.ts +2 -0
  6. package/lib/types/client/index.d.ts.map +1 -1
  7. package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -1
  8. package/lib/types/client/kimi-code/locales.d.ts +14 -2
  9. package/lib/types/client/kimi-code/locales.d.ts.map +1 -1
  10. package/lib/types/client/locales-ru/kimi-code.d.ts.map +1 -1
  11. package/lib/types/client/subagent/SubagentCard.d.ts +35 -0
  12. package/lib/types/client/subagent/SubagentCard.d.ts.map +1 -0
  13. package/lib/types/client/subagent/index.d.ts +28 -0
  14. package/lib/types/client/subagent/index.d.ts.map +1 -0
  15. package/lib/types/client/subagent/locales.d.ts +172 -0
  16. package/lib/types/client/subagent/locales.d.ts.map +1 -0
  17. package/lib/types/client/subagent/styles.d.ts +20 -0
  18. package/lib/types/client/subagent/styles.d.ts.map +1 -0
  19. package/lib/types/client/subagent/subagent-card-controller.d.ts +329 -0
  20. package/lib/types/client/subagent/subagent-card-controller.d.ts.map +1 -0
  21. package/lib/types/compat.d.ts +1 -1
  22. package/lib/types/host/common/request-images.d.ts +66 -0
  23. package/lib/types/host/common/request-images.d.ts.map +1 -1
  24. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  25. package/lib/types/host/kimi-code/mapper.d.ts +53 -3
  26. package/lib/types/host/kimi-code/mapper.d.ts.map +1 -1
  27. package/lib/types/host/kimi-code/routes.d.ts.map +1 -1
  28. package/lib/types/host/kimi-code/session-cache-state.d.ts +14 -0
  29. package/lib/types/host/kimi-code/session-cache-state.d.ts.map +1 -1
  30. package/lib/types/host/kimi-code/types.d.ts +29 -4
  31. package/lib/types/host/kimi-code/types.d.ts.map +1 -1
  32. package/lib/types/host/preferences.d.ts.map +1 -1
  33. package/lib/types/host/routes.d.ts.map +1 -1
  34. package/lib/types/host/subagent-model-authorization.d.ts +130 -2
  35. package/lib/types/host/subagent-model-authorization.d.ts.map +1 -1
  36. package/lib/types/index.d.ts.map +1 -1
  37. package/lib/types/shared/contracts.d.ts +28 -0
  38. package/lib/types/shared/contracts.d.ts.map +1 -1
  39. package/lib/types/shared/kimi-code-contracts.d.ts +10 -1
  40. package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -1
  41. package/lib/types/shared/preferences.d.ts +52 -1
  42. package/lib/types/shared/preferences.d.ts.map +1 -1
  43. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -3108,7 +3108,7 @@ window.__ModuleLoader__.load({
3108
3108
  //#endregion
3109
3109
  //#region src/client/antigravity/locales.ts
3110
3110
  const NS_ANTIGRAVITY = "dsh-antigravity";
3111
- const zh$13 = {
3111
+ const zh$14 = {
3112
3112
  ...accountPoolZh,
3113
3113
  title: "Antigravity",
3114
3114
  pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
@@ -3186,7 +3186,7 @@ window.__ModuleLoader__.load({
3186
3186
  loginFailed: "登录失败",
3187
3187
  tokens: "tokens"
3188
3188
  };
3189
- const en$13 = {
3189
+ const en$14 = {
3190
3190
  ...accountPoolEn,
3191
3191
  title: "Antigravity",
3192
3192
  pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
@@ -3264,11 +3264,11 @@ window.__ModuleLoader__.load({
3264
3264
  loginFailed: "Login failed",
3265
3265
  tokens: "tokens"
3266
3266
  };
3267
- const dictionaries$13 = {
3268
- zh: zh$13,
3269
- "zh-CN": zh$13,
3270
- en: en$13,
3271
- "en-US": en$13
3267
+ const dictionaries$14 = {
3268
+ zh: zh$14,
3269
+ "zh-CN": zh$14,
3270
+ en: en$14,
3271
+ "en-US": en$14
3272
3272
  };
3273
3273
  //#endregion
3274
3274
  //#region src/client/common/line-locale.ts
@@ -3380,7 +3380,7 @@ window.__ModuleLoader__.load({
3380
3380
  const [savingModel, setSavingModel] = (0, react.useState)(null);
3381
3381
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
3382
3382
  const quotaFollowUp = (0, react.useRef)(null);
3383
- const t = useLineDict(NS_ANTIGRAVITY, zh$13);
3383
+ const t = useLineDict(NS_ANTIGRAVITY, zh$14);
3384
3384
  const notifyChange = (0, react.useCallback)(() => {
3385
3385
  onModelChange?.();
3386
3386
  loadModelDirectory?.();
@@ -3937,7 +3937,7 @@ window.__ModuleLoader__.load({
3937
3937
  //#endregion
3938
3938
  //#region src/client/command-code/locales.ts
3939
3939
  const NS_COMMAND_CODE = "dsh-command-code";
3940
- const zh$12 = {
3940
+ const zh$13 = {
3941
3941
  ...accountPoolZh,
3942
3942
  title: "Command Code",
3943
3943
  pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
@@ -4005,7 +4005,7 @@ window.__ModuleLoader__.load({
4005
4005
  loginFailed: "登录失败",
4006
4006
  tokens: "tokens"
4007
4007
  };
4008
- const en$12 = {
4008
+ const en$13 = {
4009
4009
  ...accountPoolEn,
4010
4010
  title: "Command Code",
4011
4011
  pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
@@ -4073,11 +4073,11 @@ window.__ModuleLoader__.load({
4073
4073
  loginFailed: "Sign-in failed",
4074
4074
  tokens: "tokens"
4075
4075
  };
4076
- const dictionaries$12 = {
4077
- zh: zh$12,
4078
- "zh-CN": zh$12,
4079
- en: en$12,
4080
- "en-US": en$12
4076
+ const dictionaries$13 = {
4077
+ zh: zh$13,
4078
+ "zh-CN": zh$13,
4079
+ en: en$13,
4080
+ "en-US": en$13
4081
4081
  };
4082
4082
  //#endregion
4083
4083
  //#region src/client/command-code/CommandCodeSection.tsx
@@ -4118,7 +4118,7 @@ window.__ModuleLoader__.load({
4118
4118
  const [apiKey, setApiKey] = (0, react.useState)("");
4119
4119
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
4120
4120
  const quotaFollowUp = (0, react.useRef)(null);
4121
- const t = useLineDict(NS_COMMAND_CODE, zh$12);
4121
+ const t = useLineDict(NS_COMMAND_CODE, zh$13);
4122
4122
  const notifyChange = (0, react.useCallback)(() => {
4123
4123
  onModelChange?.();
4124
4124
  loadModelDirectory?.();
@@ -4879,7 +4879,7 @@ window.__ModuleLoader__.load({
4879
4879
  //#endregion
4880
4880
  //#region src/client/kimi-code/locales.ts
4881
4881
  const NS_KIMI_CODE = "dsh-kimi-code";
4882
- const zh$11 = {
4882
+ const zh$12 = {
4883
4883
  ...accountPoolZh,
4884
4884
  title: "Kimi Code",
4885
4885
  pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -4989,6 +4989,10 @@ window.__ModuleLoader__.load({
4989
4989
  cacheDriftTools: "工具列表已变化(缓存失效)",
4990
4990
  cacheDriftCacheKey: "缓存键已变化(会话切换)",
4991
4991
  cacheDriftColdKey: "未发送缓存键(无法命中)",
4992
+ cacheDriftImageOffload: "旧图片超预算淘汰(缓存重建)",
4993
+ cacheImageBudgetLabel: "请求图片预算",
4994
+ cacheImageBudgetValue: "本轮 {used} / 上限 {budget}(低水位 {low})",
4995
+ cacheImageBudgetDropped: "本轮 {used} / 上限 {budget}(已粘性淘汰 {dropped} 张)",
4992
4996
  preserveThinking: "保留思考 (Preserved Thinking)",
4993
4997
  preserveOn: "已开启(官方默认):跨轮保留 reasoning_content,多轮工具调用更连贯,但思考 token 也计入输出。",
4994
4998
  preserveOff: "已关闭:不要求服务回传推理内容。可设置 DSH_KIMI_CODE_PRESERVE_THINKING=0 关闭。",
@@ -5046,7 +5050,7 @@ window.__ModuleLoader__.load({
5046
5050
  compactionRouteNoImage: "该模型不接受图片:摘要里的截图会被替换为占位文本。",
5047
5051
  compactionRouteEmpty: "没有可用的线路——先登录任意一条线路再回来设置。"
5048
5052
  };
5049
- const en$11 = {
5053
+ const en$12 = {
5050
5054
  ...accountPoolEn,
5051
5055
  title: "Kimi Code",
5052
5056
  pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
@@ -5156,6 +5160,10 @@ window.__ModuleLoader__.load({
5156
5160
  cacheDriftTools: "Tool list changed (cache invalidated)",
5157
5161
  cacheDriftCacheKey: "Cache key changed (session switch)",
5158
5162
  cacheDriftColdKey: "No cache key sent (cannot hit)",
5163
+ cacheDriftImageOffload: "Older images offloaded for budget (cache rebuilt)",
5164
+ cacheImageBudgetLabel: "Request image budget",
5165
+ cacheImageBudgetValue: "{used} this turn / {budget} cap ({low} low-water)",
5166
+ cacheImageBudgetDropped: "{used} this turn / {budget} cap ({dropped} sticky-offloaded)",
5159
5167
  preserveThinking: "Preserved Thinking",
5160
5168
  preserveOn: "On (the official default): reasoning_content is retained across turns, which keeps multi-step tool use coherent — its tokens are billed as output.",
5161
5169
  preserveOff: "Off: the service is not asked to return reasoning. Set DSH_KIMI_CODE_PRESERVE_THINKING=0 to disable.",
@@ -5213,11 +5221,11 @@ window.__ModuleLoader__.load({
5213
5221
  compactionRouteNoImage: "This model takes no images: screenshots become placeholder text in the summary.",
5214
5222
  compactionRouteEmpty: "No route is available — sign in to one first."
5215
5223
  };
5216
- const dictionaries$11 = {
5217
- zh: zh$11,
5218
- "zh-CN": zh$11,
5219
- en: en$11,
5220
- "en-US": en$11
5224
+ const dictionaries$12 = {
5225
+ zh: zh$12,
5226
+ "zh-CN": zh$12,
5227
+ en: en$12,
5228
+ "en-US": en$12
5221
5229
  };
5222
5230
  //#endregion
5223
5231
  //#region src/shared/kimi-code-contracts.ts
@@ -5329,7 +5337,7 @@ window.__ModuleLoader__.load({
5329
5337
  return `${value}x`;
5330
5338
  }
5331
5339
  function KimiModelCapabilities({ models }) {
5332
- const t = useLineDict(NS_KIMI_CODE, zh$11);
5340
+ const t = useLineDict(NS_KIMI_CODE, zh$12);
5333
5341
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5334
5342
  className: "dsha-cap-table",
5335
5343
  children: [
@@ -5742,6 +5750,20 @@ window.__ModuleLoader__.load({
5742
5750
  function tokenCount(value, t) {
5743
5751
  return typeof value === "number" && Number.isFinite(value) ? value.toLocaleString() : t.unknownMetric;
5744
5752
  }
5753
+ /**
5754
+ * One byte count as the card prints it.
5755
+ *
5756
+ * The image budget is a byte budget, so a raw number would be unreadable: the
5757
+ * cap sits in the megabytes while a single image can be in the kilobytes.
5758
+ * A value the card cannot read prints as "0 B" rather than "NaN B" — an
5759
+ * absent measurement is not a measurement of zero bytes.
5760
+ */
5761
+ function formatByteSize(bytes) {
5762
+ if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
5763
+ if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(bytes % (1024 * 1024) === 0 ? 0 : 2)} MB`;
5764
+ if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`;
5765
+ return `${Math.round(bytes)} B`;
5766
+ }
5745
5767
  /** Human label for the last request's prefix-drift cause. */
5746
5768
  function driftLabel(cause, t) {
5747
5769
  switch (cause) {
@@ -5751,6 +5773,7 @@ window.__ModuleLoader__.load({
5751
5773
  case "tools": return t.cacheDriftTools;
5752
5774
  case "cache-key": return t.cacheDriftCacheKey;
5753
5775
  case "cold-key": return t.cacheDriftColdKey;
5776
+ case "image-offload": return t.cacheDriftImageOffload;
5754
5777
  default: return String(cause);
5755
5778
  }
5756
5779
  }
@@ -5768,7 +5791,7 @@ window.__ModuleLoader__.load({
5768
5791
  const [compactionPreferences, setCompactionPreferences] = (0, react.useState)(null);
5769
5792
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
5770
5793
  const quotaFollowUp = (0, react.useRef)(null);
5771
- const t = useLineDict(NS_KIMI_CODE, zh$11);
5794
+ const t = useLineDict(NS_KIMI_CODE, zh$12);
5772
5795
  const notifyChange = (0, react.useCallback)(() => {
5773
5796
  onModelChange?.();
5774
5797
  loadModelDirectory?.();
@@ -6324,6 +6347,16 @@ window.__ModuleLoader__.load({
6324
6347
  className: "dsha-value",
6325
6348
  children: (status.cache.warmup.warmup ? t.cacheWarmupWarming : t.cacheWarmupSettled).replace("{hits}", String(status.cache.warmup.consecutiveHits)).replace("{required}", String(status.cache.warmup.requiredHits)).replace("{chars}", status.cache.warmup.maxChars.toLocaleString())
6326
6349
  })]
6350
+ }),
6351
+ status.cache.imageBudget !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6352
+ className: "dsha-row",
6353
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6354
+ className: "dsha-label",
6355
+ children: t.cacheImageBudgetLabel
6356
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
6357
+ className: "dsha-value",
6358
+ children: (status.cache.imageBudget.droppedImages > 0 ? t.cacheImageBudgetDropped : t.cacheImageBudgetValue).replace("{used}", formatByteSize(status.cache.imageBudget.requestImageBytes)).replace("{budget}", formatByteSize(status.cache.imageBudget.budgetBytes)).replace("{low}", formatByteSize(status.cache.imageBudget.lowBudgetBytes)).replace("{dropped}", String(status.cache.imageBudget.droppedImages))
6359
+ })]
6327
6360
  })
6328
6361
  ]
6329
6362
  })
@@ -6538,7 +6571,7 @@ window.__ModuleLoader__.load({
6538
6571
  //#endregion
6539
6572
  //#region src/client/minimax-code/locales.ts
6540
6573
  const NS_MINIMAX_CODE = "dsh-minimax-code";
6541
- const zh$10 = {
6574
+ const zh$11 = {
6542
6575
  ...accountPoolZh,
6543
6576
  title: "MiniMax Code",
6544
6577
  pageDesc: "登录 MiniMax Code 编程订阅(设备码 OAuth),复用本机 MiniMax Code 的登录态,管理账号、连接与模型。",
@@ -6736,7 +6769,7 @@ window.__ModuleLoader__.load({
6736
6769
  videoHistoryEncrypted: "已由系统凭据后端加密",
6737
6770
  videoHistoryPlain: "本机没有可用的凭据后端,记录为明文"
6738
6771
  };
6739
- const en$10 = {
6772
+ const en$11 = {
6740
6773
  ...accountPoolEn,
6741
6774
  title: "MiniMax Code",
6742
6775
  pageDesc: "Sign in to the MiniMax Code coding subscription (device-code OAuth) and reuse the local MiniMax Code sign-in to manage the account, connection, and models.",
@@ -6934,11 +6967,11 @@ window.__ModuleLoader__.load({
6934
6967
  videoHistoryEncrypted: "Encrypted by the platform credential backend",
6935
6968
  videoHistoryPlain: "No credential backend on this host; stored as plain text"
6936
6969
  };
6937
- const dictionaries$10 = {
6938
- zh: zh$10,
6939
- "zh-CN": zh$10,
6940
- en: en$10,
6941
- "en-US": en$10
6970
+ const dictionaries$11 = {
6971
+ zh: zh$11,
6972
+ "zh-CN": zh$11,
6973
+ en: en$11,
6974
+ "en-US": en$11
6942
6975
  };
6943
6976
  //#endregion
6944
6977
  //#region src/client/minimax-code/useMinimaxCodeSection.ts
@@ -6952,7 +6985,7 @@ window.__ModuleLoader__.load({
6952
6985
  * rather than inferred from the JSX.
6953
6986
  */
6954
6987
  /** The card's own dictionary; stable identity keeps effect dependencies intact. */
6955
- const fallbackTranslate$5 = (key) => zh$10[key];
6988
+ const fallbackTranslate$5 = (key) => zh$11[key];
6956
6989
  /**
6957
6990
  * The shared pool card's labels, resolved through this card's dictionary.
6958
6991
  *
@@ -9010,7 +9043,7 @@ window.__ModuleLoader__.load({
9010
9043
  * 键名重合的会被渲染成 ChatGPT 的措辞,不重合的会把键名本身打印出来)。
9011
9044
  */
9012
9045
  const NS_GLM_CODING_PLAN = "dsh-glm-coding-plan";
9013
- const zh$9 = {
9046
+ const zh$10 = {
9014
9047
  ...accountPoolZh,
9015
9048
  title: "GLM(ZCode 账号)",
9016
9049
  pageDesc: "用 ZCode 账号授权接入 GLM Coding Plan(国区 bigmodel.cn / 国际区 z.ai),管理账号池、套餐额度与模型勾选。两个区域的凭据各自独立,池内可以同时存在两区账号。",
@@ -9104,7 +9137,7 @@ window.__ModuleLoader__.load({
9104
9137
  quotaAllowanceUnknown: "未判定",
9105
9138
  quotaAllowanceHint: "登录时探活认定的额度来源。「免费体验额度」指新用户注册后自动获得、首次使用起 5 天内每天 800 万 token 的体验额度。"
9106
9139
  };
9107
- const en$9 = {
9140
+ const en$10 = {
9108
9141
  ...accountPoolEn,
9109
9142
  title: "GLM (ZCode account)",
9110
9143
  pageDesc: "Sign in with a ZCode account to reach GLM Coding Plan (China bigmodel.cn / International z.ai), and manage the account pool, plan quota and model selection. The two regions hold independent credentials, so a pool can carry accounts from both.",
@@ -9198,11 +9231,11 @@ window.__ModuleLoader__.load({
9198
9231
  quotaAllowanceUnknown: "Undetermined",
9199
9232
  quotaAllowanceHint: "The allowance source established by the sign-in probe. “Free trial allowance” means 8M tokens per day for 5 days from first use, granted automatically to new accounts."
9200
9233
  };
9201
- const dictionaries$9 = {
9202
- zh: zh$9,
9203
- "zh-CN": zh$9,
9204
- en: en$9,
9205
- "en-US": en$9
9234
+ const dictionaries$10 = {
9235
+ zh: zh$10,
9236
+ "zh-CN": zh$10,
9237
+ en: en$10,
9238
+ "en-US": en$10
9206
9239
  };
9207
9240
  /** 一个配额窗口的键到「窗口长度(分钟)」的映射。 */
9208
9241
  const QUOTA_WINDOW_MINUTES$1 = {
@@ -9283,7 +9316,7 @@ window.__ModuleLoader__.load({
9283
9316
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
9284
9317
  const LOGIN_POLL_INTERVAL_MS$2 = 2e3;
9285
9318
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
9286
- const fallbackTranslate$4 = (key) => zh$9[key];
9319
+ const fallbackTranslate$4 = (key) => zh$10[key];
9287
9320
  /**
9288
9321
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
9289
9322
  *
@@ -9709,7 +9742,7 @@ window.__ModuleLoader__.load({
9709
9742
  const { status, loading, busy, error, connection, adoptResult, pasteValue, region, pasteOpen, contextDrafts, savingModel } = state;
9710
9743
  const { accounts, models, contextModels, overrideCount, login, quota, authenticated, poolLabels } = derived;
9711
9744
  const { setRegion, login: startLogin, cancelLogin, submitPaste, setPasteValue, togglePaste, adopt, clearAdoptResult, accountAction, setStrategy, toggleModel, setAllModels, saveContextWindow, resetContextWindow, resetAllContextWindows, updateContextDraft, refreshQuota, refreshCatalog, testConnection } = actions;
9712
- const t = useLineDict(NS_GLM_CODING_PLAN, zh$9);
9745
+ const t = useLineDict(NS_GLM_CODING_PLAN, zh$10);
9713
9746
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9714
9747
  className: "dsha-page",
9715
9748
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -10174,7 +10207,7 @@ window.__ModuleLoader__.load({
10174
10207
  * provider — the same reason every sibling line has one.
10175
10208
  */
10176
10209
  const NS_CLAUDE = "dsh-claude";
10177
- const zh$8 = {
10210
+ const zh$9 = {
10178
10211
  ...accountPoolZh,
10179
10212
  title: "Claude(订阅)",
10180
10213
  pageDesc: "登录 Claude Pro/Max 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -10291,7 +10324,7 @@ window.__ModuleLoader__.load({
10291
10324
  copy: "复制",
10292
10325
  copied: "已复制"
10293
10326
  };
10294
- const en$8 = {
10327
+ const en$9 = {
10295
10328
  ...accountPoolEn,
10296
10329
  title: "Claude (subscription)",
10297
10330
  pageDesc: "Sign in to a Claude Pro/Max subscription and manage models, thinking levels, context windows and quota.",
@@ -10408,11 +10441,11 @@ window.__ModuleLoader__.load({
10408
10441
  copy: "Copy",
10409
10442
  copied: "Copied"
10410
10443
  };
10411
- const dictionaries$8 = {
10412
- zh: zh$8,
10413
- "zh-CN": zh$8,
10414
- en: en$8,
10415
- "en-US": en$8
10444
+ const dictionaries$9 = {
10445
+ zh: zh$9,
10446
+ "zh-CN": zh$9,
10447
+ en: en$9,
10448
+ "en-US": en$9
10416
10449
  };
10417
10450
  //#endregion
10418
10451
  //#region src/client/claude/useClaudeSection.ts
@@ -10446,7 +10479,7 @@ window.__ModuleLoader__.load({
10446
10479
  const [connection, setConnection] = (0, react.useState)(null);
10447
10480
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
10448
10481
  const quotaFollowUp = (0, react.useRef)(null);
10449
- const t = useLineDict(NS_CLAUDE, zh$8);
10482
+ const t = useLineDict(NS_CLAUDE, zh$9);
10450
10483
  const notifyChange = (0, react.useCallback)(() => {
10451
10484
  onModelChange?.();
10452
10485
  loadModelDirectory?.();
@@ -10893,11 +10926,11 @@ window.__ModuleLoader__.load({
10893
10926
  * out here would hide a choice the host would accept and a catalog may expose.
10894
10927
  */
10895
10928
  const EFFORT_LABELS$2 = {
10896
- low: zh$8.effortLow,
10897
- medium: zh$8.effortMedium,
10898
- high: zh$8.effortHigh,
10899
- xhigh: zh$8.effortXHigh,
10900
- max: zh$8.effortMax
10929
+ low: zh$9.effortLow,
10930
+ medium: zh$9.effortMedium,
10931
+ high: zh$9.effortHigh,
10932
+ xhigh: zh$9.effortXHigh,
10933
+ max: zh$9.effortMax
10901
10934
  };
10902
10935
  /** One-line capability summary shown as a model pill's hover title. */
10903
10936
  function modelFacts(model, t) {
@@ -10918,7 +10951,7 @@ window.__ModuleLoader__.load({
10918
10951
  const { status, loading, busy, error, flow, connection, pasteValue, contextDrafts, savingModel } = state;
10919
10952
  const { accounts, hasAdopted, contextModels, overrideCount, quota, windows, poolLabels } = derived;
10920
10953
  const { login, cancelLogin, submitPaste, adopt, stopImporting, accountAction, setStrategy, relogin, refreshQuota, refreshCatalog, testConnection, toggleModel, setAllModels, updateEffort, updateCacheTtl, saveContextWindow, resetContextWindow, resetAllContextWindows, updateContextDraft, setPasteValue } = actions;
10921
- const t = useLineDict(NS_CLAUDE, zh$8);
10954
+ const t = useLineDict(NS_CLAUDE, zh$9);
10922
10955
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10923
10956
  className: "dsha-page",
10924
10957
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -11509,7 +11542,7 @@ window.__ModuleLoader__.load({
11509
11542
  //#endregion
11510
11543
  //#region src/client/ollama/locales.ts
11511
11544
  const NS_OLLAMA = "dsh-ollama";
11512
- const zh$7 = {
11545
+ const zh$8 = {
11513
11546
  ...accountPoolZh,
11514
11547
  relogin: "更换 Key",
11515
11548
  needsRelogin: "Key 已失效",
@@ -11561,7 +11594,7 @@ window.__ModuleLoader__.load({
11561
11594
  usageNone: "尚无请求",
11562
11595
  usageHint: "按 Ollama 每次响应自带的 token 计数本地累加。"
11563
11596
  };
11564
- const en$7 = {
11597
+ const en$8 = {
11565
11598
  ...accountPoolEn,
11566
11599
  relogin: "Replace Key",
11567
11600
  needsRelogin: "Key rejected",
@@ -11613,11 +11646,11 @@ window.__ModuleLoader__.load({
11613
11646
  usageNone: "No requests yet",
11614
11647
  usageHint: "Summed locally from the token counts Ollama returns on each response."
11615
11648
  };
11616
- const dictionaries$7 = {
11617
- zh: zh$7,
11618
- "zh-CN": zh$7,
11619
- en: en$7,
11620
- "en-US": en$7
11649
+ const dictionaries$8 = {
11650
+ zh: zh$8,
11651
+ "zh-CN": zh$8,
11652
+ en: en$8,
11653
+ "en-US": en$8
11621
11654
  };
11622
11655
  //#endregion
11623
11656
  //#region src/client/ollama/OllamaSection.tsx
@@ -11743,7 +11776,7 @@ window.__ModuleLoader__.load({
11743
11776
  const setEffort = (0, react.useCallback)((value) => {
11744
11777
  run("effort", () => API$5.setDefaultReasoningEffort(value === "" ? null : value));
11745
11778
  }, [run]);
11746
- const t = useLineDict(NS_OLLAMA, zh$7);
11779
+ const t = useLineDict(NS_OLLAMA, zh$8);
11747
11780
  const pool = status?.pool;
11748
11781
  const models = status?.models ?? [];
11749
11782
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
@@ -11858,7 +11891,7 @@ window.__ModuleLoader__.load({
11858
11891
  className: "dsha-btn",
11859
11892
  disabled: busy !== null,
11860
11893
  onClick: () => setShowKeyForm(false),
11861
- children: zh$7.deleteAccount
11894
+ children: zh$8.deleteAccount
11862
11895
  })]
11863
11896
  })
11864
11897
  ]
@@ -11978,7 +12011,7 @@ window.__ModuleLoader__.load({
11978
12011
  * 键名重合的会被渲染成 ChatGPT 的措辞,不重合的会把键名本身打印出来)。
11979
12012
  */
11980
12013
  const NS_STEP_CODE = "dsh-step-code";
11981
- const zh$6 = {
12014
+ const zh$7 = {
11982
12015
  ...accountPoolZh,
11983
12016
  title: "Step Code(Step Plan 订阅)",
11984
12017
  pageDesc: "用 StepFun 的 Step Plan 订阅(国区 api.stepfun.com / 国际区 api.stepfun.ai)或开放平台 API Key 接入,管理账号池、套餐额度、缓存用量与模型勾选。区域是凭据的属性,两区凭据互不通用,因此号池里可以同时存在两区账号。",
@@ -12147,7 +12180,7 @@ window.__ModuleLoader__.load({
12147
12180
  cacheEmpty: "本进程还没有任何请求回报过用量,跑一次对话后再看。",
12148
12181
  cacheHitRatioUnavailable: "—"
12149
12182
  };
12150
- const en$6 = {
12183
+ const en$7 = {
12151
12184
  ...accountPoolEn,
12152
12185
  title: "Step Code (Step Plan subscription)",
12153
12186
  pageDesc: "Reach StepFun with a Step Plan subscription (China api.stepfun.com / international api.stepfun.ai) or an open-platform API key, and manage the account pool, plan quota, cache usage and model selection. A region is a property of the credential and the two never share, so a pool can carry accounts from both.",
@@ -12314,11 +12347,11 @@ window.__ModuleLoader__.load({
12314
12347
  cacheEmpty: "No request on this machine has reported usage yet — run a conversation and look again.",
12315
12348
  cacheHitRatioUnavailable: "—"
12316
12349
  };
12317
- const dictionaries$6 = {
12318
- zh: zh$6,
12319
- "zh-CN": zh$6,
12320
- en: en$6,
12321
- "en-US": en$6
12350
+ const dictionaries$7 = {
12351
+ zh: zh$7,
12352
+ "zh-CN": zh$7,
12353
+ en: en$7,
12354
+ "en-US": en$7
12322
12355
  };
12323
12356
  /** 一个额度窗口的键到「窗口长度(分钟)」的映射。窗口名由共享组件按长度本地化。 */
12324
12357
  const QUOTA_WINDOW_MINUTES = {
@@ -12436,7 +12469,7 @@ window.__ModuleLoader__.load({
12436
12469
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
12437
12470
  const LOGIN_POLL_INTERVAL_MS$1 = 2e3;
12438
12471
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
12439
- const fallbackTranslate$3 = (key) => zh$6[key];
12472
+ const fallbackTranslate$3 = (key) => zh$7[key];
12440
12473
  /**
12441
12474
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
12442
12475
  *
@@ -13122,7 +13155,7 @@ window.__ModuleLoader__.load({
13122
13155
  const { status, loading, busy, error, connection, adoptResult, pasteValue, profile, pasteOpen, contextDrafts, savingModel, quotaAccount, quotaPassword, quotaToken } = state;
13123
13156
  const { accounts, models, contextModels, overrideCount, login, quota, authenticated, poolLabels, cache, cacheHitRatio: hitRatio, quotaCredential } = derived;
13124
13157
  const { setProfile, login: startLogin, cancelLogin, submitPaste, setPasteValue, togglePaste, adopt, clearAdoptResult, accountAction, setStrategy, toggleModel, setAllModels, saveContextWindow, resetContextWindow, resetAllContextWindows, updateContextDraft, setDefaultReasoningEffort, setCacheRequestParams, refreshQuota, refreshCatalog, testConnection, setQuotaAccount, setQuotaPassword, setQuotaToken, submitQuotaPassword, submitQuotaToken, clearQuotaCredential } = actions;
13125
- const t = useLineDict(NS_STEP_CODE, zh$6);
13158
+ const t = useLineDict(NS_STEP_CODE, zh$7);
13126
13159
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
13127
13160
  className: "dsha-page",
13128
13161
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -14038,7 +14071,7 @@ window.__ModuleLoader__.load({
14038
14071
  //#endregion
14039
14072
  //#region src/client/cline-pass/locales.ts
14040
14073
  const NS_CLINE_PASS = "dsh-cline-pass";
14041
- const zh$5 = {
14074
+ const zh$6 = {
14042
14075
  ...accountPoolZh,
14043
14076
  relogin: "重新登录",
14044
14077
  needsRelogin: "登录已失效",
@@ -14201,7 +14234,7 @@ window.__ModuleLoader__.load({
14201
14234
  limitRoute: "模型路由按 provider id 抢占:若已有其他插件占用 cline-pass,本卡仍可配置,但请求由对方服务。",
14202
14235
  limitQuota: "额度窗口来自网关的 usage-limits 接口;接口失败时卡片保留上一次读数并显示原因。"
14203
14236
  };
14204
- const en$5 = {
14237
+ const en$6 = {
14205
14238
  ...accountPoolEn,
14206
14239
  relogin: "Sign in again",
14207
14240
  needsRelogin: "Sign-in expired",
@@ -14364,11 +14397,11 @@ window.__ModuleLoader__.load({
14364
14397
  limitRoute: "The route is claimed by provider id: if another plugin already serves cline-pass, this card still configures the line but that provider answers the requests.",
14365
14398
  limitQuota: "Quota windows come from the gateway usage-limits endpoint; when it fails the card keeps the previous reading and says why."
14366
14399
  };
14367
- const dictionaries$5 = {
14368
- zh: zh$5,
14369
- "zh-CN": zh$5,
14370
- en: en$5,
14371
- "en-US": en$5
14400
+ const dictionaries$6 = {
14401
+ zh: zh$6,
14402
+ "zh-CN": zh$6,
14403
+ en: en$6,
14404
+ "en-US": en$6
14372
14405
  };
14373
14406
  //#endregion
14374
14407
  //#region src/client/cline-pass/ClinePassSection.tsx
@@ -14495,10 +14528,10 @@ window.__ModuleLoader__.load({
14495
14528
  API$4.loginStatus(flow.id).then((next) => {
14496
14529
  setLoginFlow(next);
14497
14530
  if (next.status === "complete") {
14498
- setNotice(zh$5.loginComplete.replace("{account}", next.accountAlias === "" ? "Cline Pass" : next.accountAlias));
14531
+ setNotice(zh$6.loginComplete.replace("{account}", next.accountAlias === "" ? "Cline Pass" : next.accountAlias));
14499
14532
  setShowKeyForm(false);
14500
14533
  loadStatus();
14501
- } else if (next.status === "failed") setError(zh$5.loginFailed.replace("{detail}", next.error));
14534
+ } else if (next.status === "failed") setError(zh$6.loginFailed.replace("{detail}", next.error));
14502
14535
  }).catch((cause) => setError(detail$1(cause)));
14503
14536
  }, Math.max(2, flow.intervalSeconds) * 1e3);
14504
14537
  return () => window.clearInterval(timer);
@@ -14572,7 +14605,7 @@ window.__ModuleLoader__.load({
14572
14605
  apiKey: trimmed,
14573
14606
  ...keyBaseURL.trim() === "" ? {} : { baseURL: keyBaseURL.trim() }
14574
14607
  }).then((result) => {
14575
- setNotice(result.authorized ? zh$5.keyTestOk.replace("{ms}", String(Math.round(result.ms))) : zh$5.keyTestFailed.replace("{detail}", result.error));
14608
+ setNotice(result.authorized ? zh$6.keyTestOk.replace("{ms}", String(Math.round(result.ms))) : zh$6.keyTestFailed.replace("{detail}", result.error));
14576
14609
  }).catch((cause) => setError(detail$1(cause))).finally(() => setBusy(null));
14577
14610
  }, [key, keyBaseURL]);
14578
14611
  const testStored = (0, react.useCallback)((accountId) => {
@@ -14580,7 +14613,7 @@ window.__ModuleLoader__.load({
14580
14613
  setError(null);
14581
14614
  setNotice(null);
14582
14615
  API$4.testKey({ accountId }).then((result) => {
14583
- setNotice(result.authorized ? zh$5.keyTestOk.replace("{ms}", String(Math.round(result.ms))) : zh$5.keyTestFailed.replace("{detail}", result.error));
14616
+ setNotice(result.authorized ? zh$6.keyTestOk.replace("{ms}", String(Math.round(result.ms))) : zh$6.keyTestFailed.replace("{detail}", result.error));
14584
14617
  }).catch((cause) => setError(detail$1(cause))).finally(() => setBusy(null));
14585
14618
  }, []);
14586
14619
  const enabledModels = (0, react.useMemo)(() => (status?.models ?? []).filter((model) => model.enabled), [status]);
@@ -14606,7 +14639,7 @@ window.__ModuleLoader__.load({
14606
14639
  if (model === void 0) return;
14607
14640
  const parsed = parsePositiveCapacity$1(drafts[id] ?? formatCapacity$1(model.contextWindow));
14608
14641
  if (parsed === null) {
14609
- setError(zh$5.error.replace("{detail}", zh$5.defaultContextWindow));
14642
+ setError(zh$6.error.replace("{detail}", zh$6.defaultContextWindow));
14610
14643
  return;
14611
14644
  }
14612
14645
  run("ctx:" + id, () => API$4.setContextWindow(id, parsed));
@@ -14628,7 +14661,7 @@ window.__ModuleLoader__.load({
14628
14661
  }, [run, status]);
14629
14662
  const resetAllContext = (0, react.useCallback)(() => {
14630
14663
  if (status === null) return;
14631
- if (typeof window !== "undefined" && !window.confirm(zh$5.contextResetAll)) return;
14664
+ if (typeof window !== "undefined" && !window.confirm(zh$6.contextResetAll)) return;
14632
14665
  const overridden = status.models.filter((model) => model.contextWindowOverride !== void 0);
14633
14666
  run("ctx-all", async () => {
14634
14667
  let next = status;
@@ -14669,7 +14702,7 @@ window.__ModuleLoader__.load({
14669
14702
  const refreshUsage = (0, react.useCallback)(() => {
14670
14703
  run("usage", async () => {
14671
14704
  const outcome = await API$4.readUsage();
14672
- setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$5.usageEmpty);
14705
+ setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$6.usageEmpty);
14673
14706
  return outcome.status;
14674
14707
  });
14675
14708
  }, [run]);
@@ -14689,7 +14722,7 @@ window.__ModuleLoader__.load({
14689
14722
  };
14690
14723
  const invalid = Object.entries(numbers).find(([, value]) => !Number.isSafeInteger(value) || value < 0);
14691
14724
  if (invalid !== void 0) {
14692
- setError(zh$5.error.replace("{detail}", invalid[0]));
14725
+ setError(zh$6.error.replace("{detail}", invalid[0]));
14693
14726
  return;
14694
14727
  }
14695
14728
  setBusy("settings");
@@ -14701,7 +14734,7 @@ window.__ModuleLoader__.load({
14701
14734
  }).then((next) => {
14702
14735
  applyStatus(next);
14703
14736
  setSettingsForm(settingsFormOf$1(next));
14704
- setNotice(zh$5.saved);
14737
+ setNotice(zh$6.saved);
14705
14738
  }).catch((cause) => setError(detail$1(cause))).finally(() => setBusy(null));
14706
14739
  }, [settingsForm, applyStatus]);
14707
14740
  const toggleTools = (0, react.useCallback)(() => {
@@ -14712,10 +14745,10 @@ window.__ModuleLoader__.load({
14712
14745
  API$4.updateSettings({ exposeTools: value }).then((next) => {
14713
14746
  applyStatus(next);
14714
14747
  setSettingsForm(settingsFormOf$1(next));
14715
- setNotice(zh$5.restartRequired);
14748
+ setNotice(zh$6.restartRequired);
14716
14749
  }).catch((cause) => setError(detail$1(cause))).finally(() => setBusy(null));
14717
14750
  }, [status, applyStatus]);
14718
- const t = useLineDict(NS_CLINE_PASS, zh$5);
14751
+ const t = useLineDict(NS_CLINE_PASS, zh$6);
14719
14752
  const errorPrefix = t.error.split("{detail}")[0] ?? "";
14720
14753
  const pool = status?.pool;
14721
14754
  const accounts = (0, react.useMemo)(() => {
@@ -15912,7 +15945,7 @@ window.__ModuleLoader__.load({
15912
15945
  * 'settings.section' 上的那张座位(那张座绑定的是 ChatGPT 的键集)。
15913
15946
  */
15914
15947
  const NS_QODER = "dsh-qoder";
15915
- const zh$4 = {
15948
+ const zh$5 = {
15916
15949
  modelRowEfforts: "档位 {list}",
15917
15950
  modelRowNoEfforts: "无档位",
15918
15951
  modelRowOutput: "输出 {cap}",
@@ -16036,8 +16069,8 @@ window.__ModuleLoader__.load({
16036
16069
  quotaWindow: "额度窗口"
16037
16070
  };
16038
16071
  /** 两套字典。 */
16039
- const dictionaries$4 = {
16040
- zh: zh$4,
16072
+ const dictionaries$5 = {
16073
+ zh: zh$5,
16041
16074
  en: {
16042
16075
  modelRowEfforts: "efforts {list}",
16043
16076
  modelRowNoEfforts: "no efforts",
@@ -16238,7 +16271,7 @@ window.__ModuleLoader__.load({
16238
16271
  /** 登录状态机的轮询节奏。真实超时与间隔由 host 拥有,卡片只是跟随。 */
16239
16272
  const LOGIN_POLL_INTERVAL_MS = 2e3;
16240
16273
  /** 本卡片的字典;身份稳定,依赖它的 effect 才不会每次渲染重建。 */
16241
- const fallbackTranslate$2 = (key) => zh$4[key];
16274
+ const fallbackTranslate$2 = (key) => zh$5[key];
16242
16275
  /**
16243
16276
  * 共享账号池卡片需要的标签集,按本卡片的字典逐键查出来。
16244
16277
  *
@@ -16804,7 +16837,7 @@ window.__ModuleLoader__.load({
16804
16837
  * `defaultMaxTokens`),客户端不按模型名推断任何一项。与 OpenDesign 卡同一写法:
16805
16838
  * 数据一行,散文进折叠区。
16806
16839
  */
16807
- function qoderModelRowHint(model, t = zh$4) {
16840
+ function qoderModelRowHint(model, t = zh$5) {
16808
16841
  return `${formatTokenCount(model.contextWindow)} · ${model.supportsImages ? "text+image" : "text"} · ${model.reasoningEfforts.length === 0 ? t.modelRowNoEfforts : t.modelRowEfforts.replace("{list}", model.reasoningEfforts.join("/"))} · ${t.modelRowOutput.replace("{cap}", formatTokenCount(model.defaultMaxTokens))}`;
16809
16842
  }
16810
16843
  function QoderSection({ onModelChange } = {}) {
@@ -16812,7 +16845,7 @@ window.__ModuleLoader__.load({
16812
16845
  const { status, loading, busy, error, connection, adoptResult, pasteValue, region, pasteOpen, contextDrafts, savingModel } = state;
16813
16846
  const { accounts, models, contextModels, overrideCount, login, quota, authenticated, poolLabels, cache, cacheHitRatio: hitRatio } = derived;
16814
16847
  const { setRegion, login: startLogin, cancelLogin, submitPaste, setPasteValue, togglePaste, adopt, clearAdoptResult, accountAction, setStrategy, toggleModel, setAllModels, saveContextWindow, resetContextWindow, resetAllContextWindows, updateContextDraft, setDefaultReasoningEffort, refreshQuota, refreshCatalog, testConnection } = actions;
16815
- const t = useLineDict(NS_QODER, zh$4);
16848
+ const t = useLineDict(NS_QODER, zh$5);
16816
16849
  if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
16817
16850
  className: "dsha-page",
16818
16851
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -17407,7 +17440,7 @@ window.__ModuleLoader__.load({
17407
17440
  //#endregion
17408
17441
  //#region src/client/opendesign/locales.ts
17409
17442
  const NS_OPENDESIGN = "dsh-opendesign";
17410
- const zh$3 = {
17443
+ const zh$4 = {
17411
17444
  ...accountPoolZh,
17412
17445
  relogin: "重新登录",
17413
17446
  needsRelogin: "登录已失效",
@@ -17515,7 +17548,7 @@ window.__ModuleLoader__.load({
17515
17548
  limitRoute: "模型路由按 provider id 抢占:若已有其他插件占用 opendesign,本卡仍可配置,但请求由对方服务。",
17516
17549
  limitQuota: "套餐与额度读取只覆盖浏览器授权登录的账号;粘贴的 API Key 没有控制 Key,请在 OpenDesign Cloud 控制台查看用量。"
17517
17550
  };
17518
- const en$3 = {
17551
+ const en$4 = {
17519
17552
  ...accountPoolEn,
17520
17553
  relogin: "Add again",
17521
17554
  needsRelogin: "Key invalid",
@@ -17623,11 +17656,11 @@ window.__ModuleLoader__.load({
17623
17656
  limitRoute: "The route is claimed by provider id: if another plugin already serves opendesign, this card still configures the line but that provider answers the requests.",
17624
17657
  limitQuota: "Plan and credit reads cover browser-signed-in accounts only; a pasted API key has no control key, so see usage in the OpenDesign Cloud console."
17625
17658
  };
17626
- const dictionaries$3 = {
17627
- zh: zh$3,
17628
- "zh-CN": zh$3,
17629
- en: en$3,
17630
- "en-US": en$3
17659
+ const dictionaries$4 = {
17660
+ zh: zh$4,
17661
+ "zh-CN": zh$4,
17662
+ en: en$4,
17663
+ "en-US": en$4
17631
17664
  };
17632
17665
  //#endregion
17633
17666
  //#region src/client/opendesign/OpenDesignSection.tsx
@@ -17922,7 +17955,7 @@ window.__ModuleLoader__.load({
17922
17955
  try {
17923
17956
  const outcome = await API$3.readUsage();
17924
17957
  setStatus(outcome.status);
17925
- if (!silent) setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$3.usageEmpty);
17958
+ if (!silent) setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$4.usageEmpty);
17926
17959
  } catch (cause) {
17927
17960
  if (!silent) setError(detail(cause));
17928
17961
  }
@@ -17959,10 +17992,10 @@ window.__ModuleLoader__.load({
17959
17992
  API$3.loginStatus(flow.id).then((next) => {
17960
17993
  setLoginFlow(next);
17961
17994
  if (next.status === "complete") {
17962
- setNotice(zh$3.loginComplete.replace("{account}", next.accountAlias === "" ? "OpenDesign" : next.accountAlias));
17995
+ setNotice(zh$4.loginComplete.replace("{account}", next.accountAlias === "" ? "OpenDesign" : next.accountAlias));
17963
17996
  setShowKeyForm(false);
17964
17997
  reload();
17965
- } else if (next.status === "failed") setError(zh$3.loginFailed.replace("{detail}", next.error));
17998
+ } else if (next.status === "failed") setError(zh$4.loginFailed.replace("{detail}", next.error));
17966
17999
  }).catch((cause) => setError(detail(cause)));
17967
18000
  }, Math.max(2, flow.intervalSeconds) * 1e3);
17968
18001
  return () => window.clearInterval(timer);
@@ -18008,7 +18041,7 @@ window.__ModuleLoader__.load({
18008
18041
  const refreshUsage = (0, react.useCallback)(() => {
18009
18042
  run("usage", async () => {
18010
18043
  const outcome = await API$3.readUsage();
18011
- setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$3.usageEmpty);
18044
+ setNotice(outcome.usage.accounts.some((account) => account.ok) ? "" : zh$4.usageEmpty);
18012
18045
  return outcome.status;
18013
18046
  });
18014
18047
  }, [run]);
@@ -18043,7 +18076,7 @@ window.__ModuleLoader__.load({
18043
18076
  apiKey: trimmed,
18044
18077
  ...keyBaseURL.trim() === "" ? {} : { baseURL: keyBaseURL.trim() }
18045
18078
  }).then((result) => {
18046
- setNotice(result.authorized ? zh$3.keyTestOk.replace("{ms}", String(Math.round(result.ms))).replace("{count}", String(result.modelCount)) : zh$3.keyTestFailed.replace("{detail}", result.error));
18079
+ setNotice(result.authorized ? zh$4.keyTestOk.replace("{ms}", String(Math.round(result.ms))).replace("{count}", String(result.modelCount)) : zh$4.keyTestFailed.replace("{detail}", result.error));
18047
18080
  }).catch((cause) => setError(detail(cause))).finally(() => setBusy(null));
18048
18081
  }, [key, keyBaseURL]);
18049
18082
  const testStored = (0, react.useCallback)((accountId) => {
@@ -18051,7 +18084,7 @@ window.__ModuleLoader__.load({
18051
18084
  setError(null);
18052
18085
  setNotice(null);
18053
18086
  API$3.testKey({ accountId }).then((result) => {
18054
- setNotice(result.authorized ? zh$3.keyTestOk.replace("{ms}", String(Math.round(result.ms))).replace("{count}", String(result.modelCount)) : zh$3.keyTestFailed.replace("{detail}", result.error));
18087
+ setNotice(result.authorized ? zh$4.keyTestOk.replace("{ms}", String(Math.round(result.ms))).replace("{count}", String(result.modelCount)) : zh$4.keyTestFailed.replace("{detail}", result.error));
18055
18088
  }).catch((cause) => setError(detail(cause))).finally(() => setBusy(null));
18056
18089
  }, []);
18057
18090
  const enabledModels = (0, react.useMemo)(() => (status?.models ?? []).filter((model) => model.enabled), [status]);
@@ -18077,7 +18110,7 @@ window.__ModuleLoader__.load({
18077
18110
  if (model === void 0) return;
18078
18111
  const parsed = parsePositiveCapacity$1(drafts[id] ?? formatCapacity$1(model.contextWindow));
18079
18112
  if (parsed === null) {
18080
- setError(zh$3.error.replace("{detail}", zh$3.defaultContextWindow));
18113
+ setError(zh$4.error.replace("{detail}", zh$4.defaultContextWindow));
18081
18114
  return;
18082
18115
  }
18083
18116
  run("ctx:" + id, () => API$3.setContextWindow(id, parsed));
@@ -18099,7 +18132,7 @@ window.__ModuleLoader__.load({
18099
18132
  }, [run, status]);
18100
18133
  const resetAllContext = (0, react.useCallback)(() => {
18101
18134
  if (status === null) return;
18102
- if (typeof window !== "undefined" && !window.confirm(zh$3.contextResetAll)) return;
18135
+ if (typeof window !== "undefined" && !window.confirm(zh$4.contextResetAll)) return;
18103
18136
  const overridden = status.models.filter((model) => model.contextWindowOverride !== void 0);
18104
18137
  run("ctx-all", async () => {
18105
18138
  let next = status;
@@ -18115,7 +18148,7 @@ window.__ModuleLoader__.load({
18115
18148
  const refreshCatalog = (0, react.useCallback)(() => {
18116
18149
  run("catalog", async () => {
18117
18150
  const outcome = await API$3.refreshCatalog();
18118
- setNotice(zh$3.catalogSyncedNote.replace("{count}", String(outcome.status.catalogCount)));
18151
+ setNotice(zh$4.catalogSyncedNote.replace("{count}", String(outcome.status.catalogCount)));
18119
18152
  return outcome.status;
18120
18153
  });
18121
18154
  }, [run]);
@@ -18129,7 +18162,7 @@ window.__ModuleLoader__.load({
18129
18162
  };
18130
18163
  const invalid = Object.entries(numbers).find(([, value]) => !Number.isSafeInteger(value) || value < 0);
18131
18164
  if (invalid !== void 0) {
18132
- setError(zh$3.error.replace("{detail}", invalid[0]));
18165
+ setError(zh$4.error.replace("{detail}", invalid[0]));
18133
18166
  return;
18134
18167
  }
18135
18168
  setBusy("settings");
@@ -18140,10 +18173,10 @@ window.__ModuleLoader__.load({
18140
18173
  }).then((next) => {
18141
18174
  applyStatus(next);
18142
18175
  setSettingsForm(settingsFormOf(next));
18143
- setNotice(zh$3.saved);
18176
+ setNotice(zh$4.saved);
18144
18177
  }).catch((cause) => setError(detail(cause))).finally(() => setBusy(null));
18145
18178
  }, [settingsForm, applyStatus]);
18146
- const t = useLineDict(NS_OPENDESIGN, zh$3);
18179
+ const t = useLineDict(NS_OPENDESIGN, zh$4);
18147
18180
  const errorPrefix = t.error.split("{detail}")[0] ?? "";
18148
18181
  const pool = status?.pool;
18149
18182
  const accounts = pool?.accounts ?? [];
@@ -18660,7 +18693,7 @@ window.__ModuleLoader__.load({
18660
18693
  * control that renders it instead.
18661
18694
  */
18662
18695
  const NS_WORKBUDDY = "dsh-workbuddy";
18663
- const zh$2 = {
18696
+ const zh$3 = {
18664
18697
  title: "WorkBuddy",
18665
18698
  pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
18666
18699
  account: "账号",
@@ -18786,7 +18819,7 @@ window.__ModuleLoader__.load({
18786
18819
  modelCooldownActive: "模型限流中",
18787
18820
  notRoutable: "当前不可路由"
18788
18821
  };
18789
- const en$2 = {
18822
+ const en$3 = {
18790
18823
  title: "WorkBuddy",
18791
18824
  pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
18792
18825
  account: "Account",
@@ -18912,11 +18945,11 @@ window.__ModuleLoader__.load({
18912
18945
  modelCooldownActive: "Model parked",
18913
18946
  notRoutable: "Not routable right now"
18914
18947
  };
18915
- const dictionaries$2 = {
18916
- zh: zh$2,
18917
- "zh-CN": zh$2,
18918
- en: en$2,
18919
- "en-US": en$2
18948
+ const dictionaries$3 = {
18949
+ zh: zh$3,
18950
+ "zh-CN": zh$3,
18951
+ en: en$3,
18952
+ "en-US": en$3
18920
18953
  };
18921
18954
  //#endregion
18922
18955
  //#region src/client/workbuddy/useWorkBuddySection.ts
@@ -19014,7 +19047,7 @@ window.__ModuleLoader__.load({
19014
19047
  const quotaFollowUp = (0, react.useRef)(null);
19015
19048
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
19016
19049
  const [savingModel, setSavingModel] = (0, react.useState)(null);
19017
- const t = useLineDict(NS_WORKBUDDY, zh$2);
19050
+ const t = useLineDict(NS_WORKBUDDY, zh$3);
19018
19051
  const notifyChange = (0, react.useCallback)(() => {
19019
19052
  onModelChange?.();
19020
19053
  loadModelDirectory?.();
@@ -19648,7 +19681,7 @@ window.__ModuleLoader__.load({
19648
19681
  const timer = window.setInterval(() => setNow(Date.now()), 1e3);
19649
19682
  return () => window.clearInterval(timer);
19650
19683
  }, [pausedUntil]);
19651
- const t = useLineDict(NS_WORKBUDDY, zh$2);
19684
+ const t = useLineDict(NS_WORKBUDDY, zh$3);
19652
19685
  const poolState = poolStateLines(pool, t, now);
19653
19686
  const storageLine = poolStorageLine(pool?.storage, t);
19654
19687
  const storageUnavailable = pool?.storage === void 0 ? null : poolStorageUnavailableLabel(pool.storage, t);
@@ -20864,7 +20897,7 @@ window.__ModuleLoader__.load({
20864
20897
  //#endregion
20865
20898
  //#region src/client/locales.ts
20866
20899
  const NS = "dsh-chatgpt-subscription";
20867
- const dictionaries$1 = {
20900
+ const dictionaries$2 = {
20868
20901
  zh: {
20869
20902
  ...accountPoolZh,
20870
20903
  title: "ChatGPT",
@@ -21277,7 +21310,7 @@ window.__ModuleLoader__.load({
21277
21310
  * 不另起一套点号命名——同一份 index.tsx 里两种命名风格会让「这条键属于哪张表」
21278
21311
  * 变成要靠记忆的事。
21279
21312
  */
21280
- const zh = {
21313
+ const zh$1 = {
21281
21314
  /** 设置页导航里的那一格,也是侧栏页签的标题。 */
21282
21315
  navTitle: "进展更新",
21283
21316
  progressTitle: "进展更新",
@@ -21321,7 +21354,7 @@ window.__ModuleLoader__.load({
21321
21354
  settingsSaveFailed: "保存失败,请稍后再试"
21322
21355
  };
21323
21356
  /** 英文对照,键集与 zh 完全一致。 */
21324
- const en = {
21357
+ const en$1 = {
21325
21358
  navTitle: "Progress updates",
21326
21359
  progressTitle: "Progress updates",
21327
21360
  progressGuideNote: "Every step the agent reports, collected here",
@@ -21363,11 +21396,11 @@ window.__ModuleLoader__.load({
21363
21396
  settingsSaveFailed: "Could not save. Try again in a moment."
21364
21397
  };
21365
21398
  /** 与其余线路同形的字典包(四个内置语言 id 都指向那两份)。 */
21366
- const dictionaries = {
21367
- zh,
21368
- "zh-CN": zh,
21369
- en,
21370
- "en-US": en
21399
+ const dictionaries$1 = {
21400
+ zh: zh$1,
21401
+ "zh-CN": zh$1,
21402
+ en: en$1,
21403
+ "en-US": en$1
21371
21404
  };
21372
21405
  //#endregion
21373
21406
  //#region src/client/locales-ru/account-pool.ts
@@ -22260,6 +22293,10 @@ window.__ModuleLoader__.load({
22260
22293
  cacheDriftTools: "Список инструментов изменился (кеш сброшен)",
22261
22294
  cacheDriftCacheKey: "Ключ кеша изменился (переключение сессии)",
22262
22295
  cacheDriftColdKey: "Ключ кеша не отправлен (попадание невозможно)",
22296
+ cacheDriftImageOffload: "Старые изображения выгружены по бюджету (кеш пересобран)",
22297
+ cacheImageBudgetLabel: "Бюджет изображений запроса",
22298
+ cacheImageBudgetValue: "{used} за ход / лимит {budget} (нижний порог {low})",
22299
+ cacheImageBudgetDropped: "{used} за ход / лимит {budget} (выгружено: {dropped})",
22263
22300
  preserveThinking: "Сохранение рассуждений (Preserved Thinking)",
22264
22301
  preserveOn: "Включено (официальное значение по умолчанию): reasoning_content сохраняется между ходами, многошаговые вызовы инструментов идут связнее, но токены рассуждений входят в вывод.",
22265
22302
  preserveOff: "Выключено: сервис не просят возвращать рассуждения. Отключается через DSH_KIMI_CODE_PRESERVE_THINKING=0.",
@@ -24249,7 +24286,7 @@ window.__ModuleLoader__.load({
24249
24286
  //#region src/client/minimax-code/MinimaxVideoDocumentBody.tsx
24250
24287
  /** 兜底翻译:只在没有 locale 座位时用到。 */
24251
24288
  function translate$1(key) {
24252
- return zh$10[key] ?? key;
24289
+ return zh$11[key] ?? key;
24253
24290
  }
24254
24291
  /**
24255
24292
  * 一个文件地址里的会话与路径。
@@ -24385,7 +24422,7 @@ window.__ModuleLoader__.load({
24385
24422
  */
24386
24423
  /** 兜底翻译:只在没有 locale 座位时用到,走同一份 zh 字典。 */
24387
24424
  function translate(key) {
24388
- return zh$10[key] ?? key;
24425
+ return zh$11[key] ?? key;
24389
24426
  }
24390
24427
  /**
24391
24428
  * 一张视频工具卡片。
@@ -24841,7 +24878,7 @@ window.__ModuleLoader__.load({
24841
24878
  * 没有快照、没有窗口、或全部窗口都没有百分比时返回 null,即**不渲染胶囊**:
24842
24879
  * 契约允许 quota 为 null,装一个占位数字比不显示更像坏了。
24843
24880
  */
24844
- function selectBadgeFacts$3(status, lookup = (key) => zh$9[key]) {
24881
+ function selectBadgeFacts$3(status, lookup = (key) => zh$10[key]) {
24845
24882
  const measured = (status?.quota?.windows ?? []).filter((window) => typeof window.usedPercent === "number" && Number.isFinite(window.usedPercent));
24846
24883
  if (measured.length === 0) return null;
24847
24884
  const tightest = measured.reduce((best, window) => {
@@ -24933,7 +24970,7 @@ window.__ModuleLoader__.load({
24933
24970
  *
24934
24971
  * 没有快照、没有窗口、或全部窗口都没有百分比时返回 null(见文件头)。
24935
24972
  */
24936
- function selectBadgeFacts$2(status, lookup = (key) => zh$6[key]) {
24973
+ function selectBadgeFacts$2(status, lookup = (key) => zh$7[key]) {
24937
24974
  const quota = status?.quota;
24938
24975
  if (quota === null || quota === void 0) return null;
24939
24976
  if (quota.kind !== "windowed") return null;
@@ -25082,7 +25119,7 @@ window.__ModuleLoader__.load({
25082
25119
  directory: props.directory,
25083
25120
  loadModelDirectory: props.loadModelDirectory,
25084
25121
  providerId: "cline-pass",
25085
- label: zh$5.composerLabel,
25122
+ label: zh$6.composerLabel,
25086
25123
  readStatus: (refresh) => API$1.status(refresh),
25087
25124
  selectFacts: selectClinePassFacts
25088
25125
  });
@@ -25178,7 +25215,7 @@ window.__ModuleLoader__.load({
25178
25215
  * 另外那只可能还剩一大半。所以这里不平均、不取最小剩余,而是取最大已用比例。
25179
25216
  * 没有快照、没有桶、或全部桶都没有总额时返回 null(见文件头)。
25180
25217
  */
25181
- function selectBadgeFacts$1(status, lookup = (key) => zh$4[key]) {
25218
+ function selectBadgeFacts$1(status, lookup = (key) => zh$5[key]) {
25182
25219
  const quota = status?.quota;
25183
25220
  if (quota === null || quota === void 0) return null;
25184
25221
  const measurable = quota.buckets.filter((bucket) => bucket.total !== null && bucket.total > 0 && bucket.used !== null);
@@ -25188,7 +25225,7 @@ window.__ModuleLoader__.load({
25188
25225
  const remaining = Math.round((1 - used) * 100);
25189
25226
  const unit = tightest.unit !== null && tightest.unit !== "" ? " " + tightest.unit : "";
25190
25227
  const bucketLabel = quotaBucketText(tightest.kind, {
25191
- ...zh$4,
25228
+ ...zh$5,
25192
25229
  quotaBucketPersonal: lookup("quotaBucketPersonal"),
25193
25230
  quotaBucketAddOn: lookup("quotaBucketAddOn"),
25194
25231
  quotaBucketOrg: lookup("quotaBucketOrg")
@@ -25299,7 +25336,7 @@ window.__ModuleLoader__.load({
25299
25336
  directory: props.directory,
25300
25337
  loadModelDirectory: props.loadModelDirectory,
25301
25338
  providerId: "opendesign",
25302
- label: zh$3.composerLabel,
25339
+ label: zh$4.composerLabel,
25303
25340
  readStatus: () => API.status(),
25304
25341
  selectFacts: selectOpenDesignFacts
25305
25342
  });
@@ -25320,9 +25357,9 @@ window.__ModuleLoader__.load({
25320
25357
  * is not), and one decimal is what keeps "1.5 小时" from reading as "2 小时".
25321
25358
  */
25322
25359
  function planWindowName(seconds) {
25323
- if (seconds >= 86400 && seconds % 86400 === 0) return zh$3.usageWindowDays.replace("{count}", String(seconds / 86400));
25324
- if (seconds >= 3600) return zh$3.usageWindowHours.replace("{count}", formatDecimal(seconds / 3600));
25325
- return zh$3.usageWindowMinutes.replace("{count}", formatDecimal(seconds / 60));
25360
+ if (seconds >= 86400 && seconds % 86400 === 0) return zh$4.usageWindowDays.replace("{count}", String(seconds / 86400));
25361
+ if (seconds >= 3600) return zh$4.usageWindowHours.replace("{count}", formatDecimal(seconds / 3600));
25362
+ return zh$4.usageWindowMinutes.replace("{count}", formatDecimal(seconds / 60));
25326
25363
  }
25327
25364
  /** What a window still has, from the grant and the remainder it states. */
25328
25365
  function windowRemaining(limitCredits, remainingCredits) {
@@ -25355,7 +25392,7 @@ window.__ModuleLoader__.load({
25355
25392
  const primaryId = status.pool.activeAccountId ?? status.pool.accounts.find((account) => account.isPrimary)?.id;
25356
25393
  const reading = readings.find((account) => account.accountId === primaryId) ?? readings[0];
25357
25394
  const amount = reading.balanceUsd;
25358
- const readAt = zh$3.usageReadAt.replace("{time}", new Date(reading.fetchedAt).toLocaleTimeString());
25395
+ const readAt = zh$4.usageReadAt.replace("{time}", new Date(reading.fetchedAt).toLocaleTimeString());
25359
25396
  const windows = planWindows(reading.codingPlan);
25360
25397
  if (windows.length === 0) return {
25361
25398
  text: `$${amount}`,
@@ -25364,8 +25401,8 @@ window.__ModuleLoader__.load({
25364
25401
  };
25365
25402
  const narrowest = windows[0];
25366
25403
  return {
25367
- text: zh$3.usageWindowRemaining.replace("{remaining}", formatDecimal(narrowest.remaining)),
25368
- tooltip: `${reading.alias} · ${windows.map((window) => `${window.name} ${zh$3.usageWindowRemaining.replace("{remaining}", formatDecimal(window.remaining))}`).join(" · ")} · ${readAt}`,
25404
+ text: zh$4.usageWindowRemaining.replace("{remaining}", formatDecimal(narrowest.remaining)),
25405
+ tooltip: `${reading.alias} · ${windows.map((window) => `${window.name} ${zh$4.usageWindowRemaining.replace("{remaining}", formatDecimal(window.remaining))}`).join(" · ")} · ${readAt}`,
25369
25406
  level: quotaLevel(narrowest.remaining),
25370
25407
  percent: narrowest.remaining
25371
25408
  };
@@ -27194,7 +27231,7 @@ window.__ModuleLoader__.load({
27194
27231
  }
27195
27232
  /** 兜底翻译:只在没有 locale 服务时用到(测试、以及菜单渲染早于字典注册)。 */
27196
27233
  function fallbackTranslate$1(key, params) {
27197
- const template = zh$10[key] ?? key;
27234
+ const template = zh$11[key] ?? key;
27198
27235
  if (params === void 0) return template;
27199
27236
  return template.replace(/\{(\w+)\}/g, (_match, name) => String(params[name] ?? ""));
27200
27237
  }
@@ -54405,7 +54442,7 @@ window.__ModuleLoader__.load({
54405
54442
  * @returns 该键的文案;缺键时回退为键本身。
54406
54443
  */
54407
54444
  function fallbackTranslate(key, params) {
54408
- return interpolate(zh[key] ?? key, params);
54445
+ return interpolate(zh$1[key] ?? key, params);
54409
54446
  }
54410
54447
  /**
54411
54448
  * 把 `{name}` 占位符换成实参。
@@ -54566,7 +54603,7 @@ window.__ModuleLoader__.load({
54566
54603
  * 先按当前语言的字典取值(没有 `t` 时才用兜底字典),再统一做一次替换。
54567
54604
  */
54568
54605
  const translate = (key, params) => {
54569
- return interpolate(t === void 0 ? zh[key] ?? key : t(key), params);
54606
+ return interpolate(t === void 0 ? zh$1[key] ?? key : t(key), params);
54570
54607
  };
54571
54608
  const latestId = updates.length > 0 ? updates[updates.length - 1].id : void 0;
54572
54609
  /**
@@ -55672,7 +55709,7 @@ window.__ModuleLoader__.load({
55672
55709
  * @param name - 服务名。
55673
55710
  * @returns 服务实例或 undefined。
55674
55711
  */
55675
- function serviceOf$1(ctx, name) {
55712
+ function serviceOf$2(ctx, name) {
55676
55713
  try {
55677
55714
  return ctx.get(name);
55678
55715
  } catch {
@@ -55684,7 +55721,7 @@ window.__ModuleLoader__.load({
55684
55721
  * @param value - 任意服务值。
55685
55722
  * @returns 是否具备 get / describe 两个成员。
55686
55723
  */
55687
- function isConfigForms(value) {
55724
+ function isConfigForms$1(value) {
55688
55725
  if (typeof value !== "object" || value === null) return false;
55689
55726
  const face = value;
55690
55727
  return typeof face.get === "function" && typeof face.describe === "function";
@@ -55711,8 +55748,8 @@ window.__ModuleLoader__.load({
55711
55748
  * @returns 表单通道,或 undefined(这个部署没有设置服务)。
55712
55749
  */
55713
55750
  function createProgressSettingsForm(ctx) {
55714
- const forms = serviceOf$1(ctx, "configForms");
55715
- if (!isConfigForms(forms)) return void 0;
55751
+ const forms = serviceOf$2(ctx, "configForms");
55752
+ if (!isConfigForms$1(forms)) return void 0;
55716
55753
  const listeners = /* @__PURE__ */ new Set();
55717
55754
  let boundId;
55718
55755
  let bound;
@@ -55824,7 +55861,7 @@ window.__ModuleLoader__.load({
55824
55861
  * @param name - 服务名。
55825
55862
  * @returns 服务实例或 undefined。
55826
55863
  */
55827
- function serviceOf(ctx, name) {
55864
+ function serviceOf$1(ctx, name) {
55828
55865
  try {
55829
55866
  return ctx.get(name);
55830
55867
  } catch {
@@ -55849,7 +55886,7 @@ window.__ModuleLoader__.load({
55849
55886
  explicit(PANEL_TAB_KIND);
55850
55887
  return;
55851
55888
  }
55852
- const sidebarRight = serviceOf(ctx, "sidebarRight");
55889
+ const sidebarRight = serviceOf$1(ctx, "sidebarRight");
55853
55890
  if (typeof sidebarRight?.openTab !== "function") return;
55854
55891
  sidebarRight.openTab(PANEL_TAB_KIND);
55855
55892
  };
@@ -55953,7 +55990,7 @@ window.__ModuleLoader__.load({
55953
55990
  const direct = scope.sidebarRightTabs;
55954
55991
  if (direct !== void 0) return direct;
55955
55992
  } catch {}
55956
- return serviceOf(scope, "sidebarRightTabs");
55993
+ return serviceOf$1(scope, "sidebarRightTabs");
55957
55994
  };
55958
55995
  /**
55959
55996
  * 阶段一:声明页签**类型**。
@@ -55974,7 +56011,7 @@ window.__ModuleLoader__.load({
55974
56011
  try {
55975
56012
  return ctx.locale.bind(NS_PROGRESS_UPDATES)("progressTitle");
55976
56013
  } catch {
55977
- return zh.progressTitle;
56014
+ return zh$1.progressTitle;
55978
56015
  }
55979
56016
  },
55980
56017
  guide: [{
@@ -55984,14 +56021,14 @@ window.__ModuleLoader__.load({
55984
56021
  try {
55985
56022
  return ctx.locale.bind(NS_PROGRESS_UPDATES)("progressTitle");
55986
56023
  } catch {
55987
- return zh.progressTitle;
56024
+ return zh$1.progressTitle;
55988
56025
  }
55989
56026
  },
55990
56027
  description: () => {
55991
56028
  try {
55992
56029
  return ctx.locale.bind(NS_PROGRESS_UPDATES)("progressGuideNote");
55993
56030
  } catch {
55994
- return zh.progressGuideNote;
56031
+ return zh$1.progressGuideNote;
55995
56032
  }
55996
56033
  },
55997
56034
  icon: ProgressUpdatesArtwork
@@ -56069,7 +56106,7 @@ window.__ModuleLoader__.load({
56069
56106
  try {
56070
56107
  return ctx.locale.bind(NS_PROGRESS_UPDATES)("navTitle");
56071
56108
  } catch {
56072
- return zh.navTitle;
56109
+ return zh$1.navTitle;
56073
56110
  }
56074
56111
  },
56075
56112
  locale: NS_PROGRESS_UPDATES,
@@ -56115,7 +56152,7 @@ window.__ModuleLoader__.load({
56115
56152
  * 单独一支分支。写死的只有开关滑块投影与品牌方块淡染这类"结构色"。
56116
56153
  */
56117
56154
  /** 这张表的 `data-plugin-css` 子名。 */
56118
- const STYLE_NAME = "progress-updates";
56155
+ const STYLE_NAME$1 = "progress-updates";
56119
56156
  /** 设置卡片与面板的样式全文。 */
56120
56157
  const CSS = `
56121
56158
  .dsh-progress-overview{display:flex;flex-direction:column;min-width:0}
@@ -56152,7 +56189,7 @@ window.__ModuleLoader__.load({
56152
56189
  * @returns 空操作释放函数(与邻居同形)。
56153
56190
  */
56154
56191
  function installProgressUpdatesStyles() {
56155
- return installPluginStyle(STYLE_NAME, CSS);
56192
+ return installPluginStyle(STYLE_NAME$1, CSS);
56156
56193
  }
56157
56194
  //#endregion
56158
56195
  //#region src/client/workbuddy/WorkBuddyComposerQuota.tsx
@@ -56218,7 +56255,7 @@ window.__ModuleLoader__.load({
56218
56255
  providerId: "workbuddy-subscription",
56219
56256
  readStatus: (refresh) => refresh ? api.post("/quota") : api.get("/status"),
56220
56257
  selectFacts: selectBadgeFacts,
56221
- label: useLineDict(NS_WORKBUDDY, zh$2).composerLabel
56258
+ label: useLineDict(NS_WORKBUDDY, zh$3).composerLabel
56222
56259
  });
56223
56260
  }
56224
56261
  //#endregion
@@ -56282,6 +56319,2165 @@ window.__ModuleLoader__.load({
56282
56319
  `, STYLE_ID);
56283
56320
  }
56284
56321
  //#endregion
56322
+ //#region src/client/subagent/subagent-card-controller.ts
56323
+ /**
56324
+ * 「子智能体」设置卡片的**状态与动作**。
56325
+ *
56326
+ * ## 这张卡替换了宿主的同名卡
56327
+ *
56328
+ * 宿主自带 `@deepseek-ai/dsh-client-ui-settings-subagent` 在 `plugins.item` 上以
56329
+ * `id: 'subagent'`、默认 priority 注册。本插件以同一个 id、`priority: -10` 再注册
56330
+ * 一次——槽位的遮蔽规则是「同一个 cell 上 priority 最低的那一条渲染」,于是打开
56331
+ * 「插件 → 子智能体」看到的是这张卡,而不是两张并排。
56332
+ *
56333
+ * ## 三份存储,一次保存
56334
+ *
56335
+ * | 来源 | 内容 | 通道 |
56336
+ * | --- | --- | --- |
56337
+ * | `subagent` 命名空间 | `maxDepth` / `maxActiveSubagents` | `ctx.configForms` |
56338
+ * | `subagent-model-selection-settings` 命名空间 | `enabled` / `allowedModels` | `ctx.configForms` |
56339
+ * | 本插件偏好文档 | 全局默认列表 + 每个主代理模型的专属列表 | `POST /preferences/update` |
56340
+ *
56341
+ * @module @eddyskywalker/dsh-chatgpt-subscription/client/subagent/subagent-card-controller
56342
+ */
56343
+ /** 宿主侧「运行限制」的命名空间。 */
56344
+ const SUBAGENT_LIMITS_NS = "subagent";
56345
+ /** 宿主侧「模型选择」的命名空间。 */
56346
+ const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection-settings";
56347
+ /** 主代理模型下拉里代表「全局默认」的取值。 */
56348
+ const GLOBAL_TARGET = "default";
56349
+ /** 浏览器侧本地备份键(当宿主进程尚未重启加载新版 /preferences/update 时兜底)。 */
56350
+ const LOCAL_STORAGE_KEY = "dsh-chatgpt-subscription:subagent-model-preferences";
56351
+ /** 一条路由的不透明键。 */
56352
+ function routeKey(route) {
56353
+ return `${route.provider}/${route.model}`;
56354
+ }
56355
+ /** 过滤并克隆非空合法路由。 */
56356
+ function cloneRoutes(routes) {
56357
+ const out = [];
56358
+ const seen = /* @__PURE__ */ new Set();
56359
+ for (const route of routes) {
56360
+ if (typeof route?.provider !== "string" || typeof route?.model !== "string") continue;
56361
+ const provider = route.provider.trim();
56362
+ const model = route.model.trim();
56363
+ if (provider.length === 0 || model.length === 0) continue;
56364
+ if (provider === "undefined" || model === "undefined") continue;
56365
+ const key = `${provider}/${model}`;
56366
+ if (seen.has(key)) continue;
56367
+ seen.add(key);
56368
+ out.push({
56369
+ provider,
56370
+ model
56371
+ });
56372
+ }
56373
+ return out;
56374
+ }
56375
+ function sameRouteSet(left, right) {
56376
+ if (left.length !== right.length) return false;
56377
+ const keys = new Set(right.map(routeKey));
56378
+ return left.every((route) => keys.has(routeKey(route)));
56379
+ }
56380
+ function sameOverrides(left, right) {
56381
+ const leftKeys = Object.keys(left).sort();
56382
+ const rightKeys = Object.keys(right).sort();
56383
+ if (leftKeys.length !== rightKeys.length) return false;
56384
+ return leftKeys.every((key, index) => key === rightKeys[index] && sameRouteSet(left[key] ?? [], right[key] ?? []));
56385
+ }
56386
+ /** 最小快照 store:`useSyncExternalStore` 要求引用在两次变更之间稳定。 */
56387
+ function createStore(initial) {
56388
+ let snapshot = initial;
56389
+ const listeners = /* @__PURE__ */ new Set();
56390
+ return {
56391
+ getSnapshot: () => snapshot,
56392
+ subscribe: (listener) => {
56393
+ listeners.add(listener);
56394
+ return () => {
56395
+ listeners.delete(listener);
56396
+ };
56397
+ },
56398
+ setState: (next) => {
56399
+ snapshot = next;
56400
+ for (const listener of [...listeners]) listener();
56401
+ }
56402
+ };
56403
+ }
56404
+ /** 未绑定表单时的空快照。 */
56405
+ const EMPTY_SNAPSHOT = Object.freeze({
56406
+ status: "unavailable",
56407
+ value: void 0,
56408
+ base: void 0,
56409
+ user: void 0,
56410
+ revision: void 0,
56411
+ writable: false
56412
+ });
56413
+ /** 空表单(服务缺席时用它顶替,让所有读取都成立)。 */
56414
+ const NO_SCOPE = {
56415
+ getSnapshot: () => EMPTY_SNAPSHOT,
56416
+ subscribe: () => () => {}
56417
+ };
56418
+ /**
56419
+ * 归一化模型目录分组:兼容宿主的 `{ id, name, models }` 与测试替身的 `{ provider, providerName, models }`。
56420
+ */
56421
+ function normalizeCatalogGroups(rawGroups) {
56422
+ const groups = [];
56423
+ for (const entry of rawGroups) {
56424
+ if (typeof entry !== "object" || entry === null) continue;
56425
+ const rec = entry;
56426
+ const provider = typeof rec["provider"] === "string" && rec["provider"].trim().length > 0 ? rec["provider"].trim() : typeof rec["id"] === "string" && rec["id"].trim().length > 0 ? rec["id"].trim() : "";
56427
+ if (provider.length === 0) continue;
56428
+ const providerName = typeof rec["providerName"] === "string" && rec["providerName"].trim().length > 0 ? rec["providerName"].trim() : typeof rec["name"] === "string" && rec["name"].trim().length > 0 ? rec["name"].trim() : provider;
56429
+ const rawModels = Array.isArray(rec["models"]) ? rec["models"] : [];
56430
+ const models = [];
56431
+ for (const rawModel of rawModels) {
56432
+ if (typeof rawModel !== "object" || rawModel === null) continue;
56433
+ const mRec = rawModel;
56434
+ const id = typeof mRec["id"] === "string" && mRec["id"].trim().length > 0 ? mRec["id"].trim() : typeof mRec["model"] === "string" && mRec["model"].trim().length > 0 ? mRec["model"].trim() : "";
56435
+ if (id.length === 0) continue;
56436
+ const name = typeof mRec["name"] === "string" && mRec["name"].trim().length > 0 ? mRec["name"].trim() : typeof mRec["modelName"] === "string" && mRec["modelName"].trim().length > 0 ? mRec["modelName"].trim() : id;
56437
+ models.push({
56438
+ id,
56439
+ name
56440
+ });
56441
+ }
56442
+ groups.push({
56443
+ provider,
56444
+ providerName,
56445
+ models
56446
+ });
56447
+ }
56448
+ return groups;
56449
+ }
56450
+ function readLocalBackup() {
56451
+ try {
56452
+ if (typeof localStorage === "undefined") return void 0;
56453
+ const raw = localStorage.getItem(LOCAL_STORAGE_KEY);
56454
+ if (!raw) return void 0;
56455
+ const parsed = JSON.parse(raw);
56456
+ if (typeof parsed !== "object" || parsed === null) return void 0;
56457
+ return {
56458
+ subagentDefaultModels: Array.isArray(parsed.subagentDefaultModels) ? cloneRoutes(parsed.subagentDefaultModels) : [],
56459
+ subagentModelsByMainModel: parsed.subagentModelsByMainModel ?? {}
56460
+ };
56461
+ } catch {
56462
+ return;
56463
+ }
56464
+ }
56465
+ function writeLocalBackup(patch) {
56466
+ try {
56467
+ if (typeof localStorage === "undefined") return;
56468
+ const prev = readLocalBackup();
56469
+ const mergedOverrides = { ...prev?.subagentModelsByMainModel ?? {} };
56470
+ for (const [k, v] of Object.entries(patch.subagentModelsByMainModel ?? {})) if (v === null || !Array.isArray(v) || v.length === 0) delete mergedOverrides[k];
56471
+ else mergedOverrides[k] = cloneRoutes(v);
56472
+ localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({
56473
+ subagentDefaultModels: Array.isArray(patch.subagentDefaultModels) ? cloneRoutes(patch.subagentDefaultModels) : prev?.subagentDefaultModels ?? [],
56474
+ subagentModelsByMainModel: mergedOverrides
56475
+ }));
56476
+ } catch {}
56477
+ }
56478
+ /**
56479
+ * 读本插件偏好里的子代理模型两项。
56480
+ * @returns 偏好切片;读取失败时 undefined(卡片照常可用,只是从空列表起步)。
56481
+ */
56482
+ async function readSubagentPreferences() {
56483
+ const local = readLocalBackup();
56484
+ try {
56485
+ const response = await fetch(`${ROUTE_PREFIX}/status`, { credentials: "same-origin" });
56486
+ if (!response.ok) return local;
56487
+ const preferences = (await response.json())?.value?.preferences;
56488
+ if (preferences === void 0 || preferences === null) return local;
56489
+ const serverDefaults = Array.isArray(preferences.subagentDefaultModels) ? cloneRoutes(preferences.subagentDefaultModels) : [];
56490
+ const serverByMain = preferences.subagentModelsByMainModel ?? {};
56491
+ if (serverDefaults.length === 0 && Object.keys(serverByMain).length === 0 && local !== void 0) return local;
56492
+ return {
56493
+ subagentDefaultModels: serverDefaults,
56494
+ subagentModelsByMainModel: serverByMain
56495
+ };
56496
+ } catch {
56497
+ return local;
56498
+ }
56499
+ }
56500
+ /**
56501
+ * 写本插件偏好里的子代理模型两项。
56502
+ * @param patch - 要写入的两项。
56503
+ */
56504
+ async function writeSubagentPreferences(patch) {
56505
+ writeLocalBackup(patch);
56506
+ const response = await fetch(`${ROUTE_PREFIX}/preferences/update`, {
56507
+ method: "POST",
56508
+ credentials: "same-origin",
56509
+ headers: { "content-type": "application/json" },
56510
+ body: JSON.stringify(patch)
56511
+ });
56512
+ const envelope = await response.json().catch(() => void 0);
56513
+ if (!response.ok || envelope?.ok === false) throw new Error(envelope?.error?.message ?? "The deployment rejected the subagent model preferences.");
56514
+ }
56515
+ /**
56516
+ * 读宿主模型目录。
56517
+ *
56518
+ * `remote.session.modelCatalog()` 返回 `{ ok: true, value: { groups: ModelProviderGroup[], failures } }`,
56519
+ * 其中每个 `group` 是 `{ id: string, name: string, models: Array<{ id: string, name: string }> }`。
56520
+ * @param ctx - 浏览器根上下文(只用 `get`)。
56521
+ * @returns 分组,或失败。
56522
+ */
56523
+ async function readSubagentCatalog(ctx) {
56524
+ try {
56525
+ const session = (ctx?.get?.("remote"))?.session;
56526
+ const call = session?.modelCatalog;
56527
+ if (typeof call === "function" && session !== void 0) {
56528
+ const answer = await call.call(session);
56529
+ if (answer?.ok === true && Array.isArray(answer.value?.groups)) return {
56530
+ ok: true,
56531
+ groups: normalizeCatalogGroups(answer.value.groups),
56532
+ partial: (answer.value.failures?.length ?? 0) > 0
56533
+ };
56534
+ return {
56535
+ ok: false,
56536
+ groups: []
56537
+ };
56538
+ }
56539
+ } catch {
56540
+ return {
56541
+ ok: false,
56542
+ groups: []
56543
+ };
56544
+ }
56545
+ return {
56546
+ ok: false,
56547
+ groups: []
56548
+ };
56549
+ }
56550
+ /** 数字限制字段的解析规则。 */
56551
+ function parseLimit(text, minimum) {
56552
+ const trimmed = text.trim();
56553
+ if (!/^[0-9]+$/.test(trimmed)) return void 0;
56554
+ const value = Number(trimmed);
56555
+ return Number.isSafeInteger(value) && value >= minimum && !Object.is(value, -0) ? value : void 0;
56556
+ }
56557
+ /** 取表单快照里的一个数字字段(缺失时用兜底值)。 */
56558
+ function readNumber(value, field, fallback) {
56559
+ if (typeof value !== "object" || value === null) return fallback;
56560
+ const raw = value[field];
56561
+ return typeof raw === "number" && Number.isSafeInteger(raw) ? raw : fallback;
56562
+ }
56563
+ /** 用户层是否已经覆盖了某个字段(存在性即覆盖,与值无关)。 */
56564
+ function userHas(user, field) {
56565
+ return typeof user === "object" && user !== null && field in user;
56566
+ }
56567
+ /**
56568
+ * 子智能体设置卡片的状态机。
56569
+ */
56570
+ var SubagentSettingsController = class {
56571
+ limits;
56572
+ modelSelection;
56573
+ loadCatalog;
56574
+ loadPreferences;
56575
+ savePreferences;
56576
+ store = createStore(void 0);
56577
+ unsubscribes = [];
56578
+ preferences;
56579
+ preferencesStatus = "idle";
56580
+ catalogGroups = [];
56581
+ catalogPartial = false;
56582
+ catalogStatus = "idle";
56583
+ draftDepth;
56584
+ draftDepthCleared = false;
56585
+ draftActive;
56586
+ draftActiveCleared = false;
56587
+ draftEnabled;
56588
+ draftDefault;
56589
+ draftOverrides;
56590
+ draftRevision;
56591
+ activeTarget = GLOBAL_TARGET;
56592
+ saving = false;
56593
+ failed = false;
56594
+ disposed = false;
56595
+ catalogGeneration = 0;
56596
+ saveGeneration = 0;
56597
+ /**
56598
+ * @param options - 表单通道与三条外部依赖;全部可省,省略时卡片是只读的。
56599
+ */
56600
+ constructor(options = {}) {
56601
+ this.limits = options.limits ?? NO_SCOPE;
56602
+ this.modelSelection = options.modelSelection ?? NO_SCOPE;
56603
+ this.loadCatalog = options.loadCatalog ?? (() => Promise.resolve({
56604
+ ok: false,
56605
+ groups: []
56606
+ }));
56607
+ this.loadPreferences = options.loadPreferences ?? (() => Promise.resolve(void 0));
56608
+ this.savePreferences = options.savePreferences ?? (() => Promise.resolve());
56609
+ this.unsubscribes.push(this.limits.subscribe(() => {
56610
+ this.publish();
56611
+ }));
56612
+ this.unsubscribes.push(this.modelSelection.subscribe(() => {
56613
+ this.publish();
56614
+ }));
56615
+ this.publish();
56616
+ this.hydrate();
56617
+ }
56618
+ /** 停掉订阅与迟到的保存/目录答复。 */
56619
+ dispose() {
56620
+ this.disposed = true;
56621
+ this.saveGeneration += 1;
56622
+ this.catalogGeneration += 1;
56623
+ for (const off of this.unsubscribes.splice(0)) try {
56624
+ off();
56625
+ } catch {}
56626
+ }
56627
+ /** 刷新模型目录(当适配器或设置文档在其他位置变更时调用)。 */
56628
+ refreshCatalog() {
56629
+ if (this.disposed) return;
56630
+ this.loadCatalogOnce();
56631
+ }
56632
+ /** 重连后重置连接态与目录。 */
56633
+ resetConnection() {
56634
+ if (this.disposed) return;
56635
+ this.saveGeneration += 1;
56636
+ this.saving = false;
56637
+ this.clearDraft();
56638
+ this.catalogGroups = [];
56639
+ this.hydrate();
56640
+ }
56641
+ /**
56642
+ * 组装注入给渲染器的座位。
56643
+ * @returns 快照与全部动作。
56644
+ */
56645
+ inject() {
56646
+ return {
56647
+ store: this.store,
56648
+ editLimit: (field, text) => {
56649
+ this.editLimit(field, text);
56650
+ },
56651
+ resetLimit: (field) => {
56652
+ this.resetLimit(field);
56653
+ },
56654
+ toggleEnabled: () => {
56655
+ this.toggleEnabled();
56656
+ },
56657
+ toggleModel: (key) => {
56658
+ this.toggleModel(key);
56659
+ },
56660
+ setActiveTarget: (target) => {
56661
+ this.setActiveTarget(target);
56662
+ },
56663
+ resetActiveTarget: () => {
56664
+ this.resetActiveTarget();
56665
+ },
56666
+ retryCatalog: () => {
56667
+ this.loadCatalogOnce();
56668
+ },
56669
+ save: () => {
56670
+ this.save();
56671
+ },
56672
+ discard: () => {
56673
+ this.discard();
56674
+ }
56675
+ };
56676
+ }
56677
+ /** 首屏:并行读偏好与目录。 */
56678
+ async hydrate() {
56679
+ this.preferencesStatus = "loading";
56680
+ this.publish();
56681
+ const [preferences] = await Promise.all([this.loadPreferences(), this.loadCatalogOnce()]);
56682
+ if (this.disposed) return;
56683
+ if (preferences === void 0) this.preferencesStatus = "error";
56684
+ else {
56685
+ this.preferences = preferences;
56686
+ this.preferencesStatus = "ready";
56687
+ }
56688
+ this.publish();
56689
+ }
56690
+ /** 拉一次目录(`refreshCatalog` 与「重试」共用)。 */
56691
+ async loadCatalogOnce() {
56692
+ if (this.disposed) return;
56693
+ this.catalogGeneration += 1;
56694
+ const generation = this.catalogGeneration;
56695
+ this.catalogStatus = "loading";
56696
+ this.catalogPartial = false;
56697
+ this.publish();
56698
+ const answer = await this.loadCatalog();
56699
+ if (this.disposed || generation !== this.catalogGeneration) return;
56700
+ if (answer.ok) {
56701
+ this.catalogGroups = normalizeCatalogGroups(answer.groups);
56702
+ this.catalogPartial = answer.partial === true;
56703
+ this.catalogStatus = "ready";
56704
+ } else {
56705
+ this.catalogGroups = [];
56706
+ this.catalogStatus = "error";
56707
+ }
56708
+ this.publish();
56709
+ }
56710
+ currentEnabled() {
56711
+ return this.modelSelection.getSnapshot().value?.enabled === true;
56712
+ }
56713
+ /**
56714
+ * 全局默认列表。
56715
+ *
56716
+ * 向后兼容种子:偏好文档里还没有这份列表(老版本、或从未保存过)时,把宿主
56717
+ * `allowedModels` 当作初始默认。
56718
+ */
56719
+ currentDefault() {
56720
+ const stored = this.preferences?.subagentDefaultModels;
56721
+ if (Array.isArray(stored) && stored.length > 0) return cloneRoutes(stored);
56722
+ const allowed = this.modelSelection.getSnapshot().value?.allowedModels;
56723
+ if (Array.isArray(allowed) && allowed.length > 0) return cloneRoutes(allowed);
56724
+ return [];
56725
+ }
56726
+ /** 每个主代理模型的专属列表(丢弃空数组与非法项)。 */
56727
+ currentOverrides() {
56728
+ const raw = this.preferences?.subagentModelsByMainModel;
56729
+ const out = {};
56730
+ if (raw === void 0 || raw === null) return out;
56731
+ for (const [key, value] of Object.entries(raw)) {
56732
+ if (!Array.isArray(value)) continue;
56733
+ const cloned = cloneRoutes(value);
56734
+ if (cloned.length === 0) continue;
56735
+ out[key] = cloned;
56736
+ }
56737
+ return out;
56738
+ }
56739
+ enabled() {
56740
+ return this.draftEnabled ?? this.currentEnabled();
56741
+ }
56742
+ defaultRoutes() {
56743
+ return cloneRoutes(this.draftDefault ?? this.currentDefault());
56744
+ }
56745
+ overrides() {
56746
+ const source = this.draftOverrides ?? this.currentOverrides();
56747
+ const out = {};
56748
+ for (const [key, value] of Object.entries(source)) out[key] = cloneRoutes(value);
56749
+ return out;
56750
+ }
56751
+ /** 当前目标生效的列表(专属列表优先,否则回落到全局默认)。 */
56752
+ activeRoutes() {
56753
+ if (this.activeTarget === "default") return this.defaultRoutes();
56754
+ const own = this.overrides()[this.activeTarget];
56755
+ return own === void 0 ? this.defaultRoutes() : cloneRoutes(own);
56756
+ }
56757
+ ensureDraft() {
56758
+ if (this.draftDefault !== void 0) return;
56759
+ this.draftEnabled = this.currentEnabled();
56760
+ this.draftDefault = this.currentDefault();
56761
+ this.draftOverrides = this.currentOverrides();
56762
+ this.draftRevision = this.modelSelection.getSnapshot().revision;
56763
+ }
56764
+ clearDraft() {
56765
+ this.draftDepth = void 0;
56766
+ this.draftDepthCleared = false;
56767
+ this.draftActive = void 0;
56768
+ this.draftActiveCleared = false;
56769
+ this.draftEnabled = void 0;
56770
+ this.draftDefault = void 0;
56771
+ this.draftOverrides = void 0;
56772
+ this.draftRevision = void 0;
56773
+ this.failed = false;
56774
+ }
56775
+ editLimit(field, text) {
56776
+ if (this.saving) return;
56777
+ if (field === "maxDepth") {
56778
+ this.draftDepth = text;
56779
+ this.draftDepthCleared = text.trim() === "";
56780
+ } else {
56781
+ this.draftActive = text;
56782
+ this.draftActiveCleared = text.trim() === "";
56783
+ }
56784
+ this.failed = false;
56785
+ this.publish();
56786
+ }
56787
+ resetLimit(field) {
56788
+ if (this.saving) return;
56789
+ const base = this.limits.getSnapshot().base;
56790
+ const fallback = field === "maxDepth" ? readNumber(base, "maxDepth", 1) : readNumber(base, "maxActiveSubagents", 8);
56791
+ if (field === "maxDepth") {
56792
+ this.draftDepth = String(fallback);
56793
+ this.draftDepthCleared = true;
56794
+ } else {
56795
+ this.draftActive = String(fallback);
56796
+ this.draftActiveCleared = true;
56797
+ }
56798
+ this.failed = false;
56799
+ this.publish();
56800
+ }
56801
+ toggleEnabled() {
56802
+ const snapshot = this.modelSelection.getSnapshot();
56803
+ if (this.saving || snapshot.status !== "ready" || !snapshot.writable) return;
56804
+ this.ensureDraft();
56805
+ this.draftEnabled = !this.enabled();
56806
+ this.failed = false;
56807
+ if (this.draftEnabled && this.catalogStatus === "idle") this.loadCatalogOnce();
56808
+ this.publish();
56809
+ }
56810
+ /**
56811
+ * 切换一条路由在当前目标下的勾选态。
56812
+ */
56813
+ toggleModel(key) {
56814
+ if (this.saving || !this.enabled()) return;
56815
+ if (this.modelSelection.getSnapshot().status !== "ready") return;
56816
+ const route = this.candidates().find((candidate) => candidate.key === key);
56817
+ if (route === void 0) return;
56818
+ if (!route.provider || !route.model || route.provider === "undefined" || route.model === "undefined") return;
56819
+ this.ensureDraft();
56820
+ const overrides = this.draftOverrides ?? this.currentOverrides();
56821
+ if (this.activeTarget === "default") {
56822
+ const next = new Map((this.draftDefault ?? this.currentDefault()).map((item) => [routeKey(item), item]));
56823
+ if (next.has(key)) next.delete(key);
56824
+ else next.set(key, {
56825
+ provider: route.provider,
56826
+ model: route.model
56827
+ });
56828
+ this.draftDefault = [...next.values()];
56829
+ } else {
56830
+ const base = overrides[this.activeTarget] ?? this.defaultRoutes();
56831
+ const next = new Map(base.map((item) => [routeKey(item), item]));
56832
+ if (next.has(key)) next.delete(key);
56833
+ else next.set(key, {
56834
+ provider: route.provider,
56835
+ model: route.model
56836
+ });
56837
+ overrides[this.activeTarget] = [...next.values()];
56838
+ this.draftOverrides = overrides;
56839
+ }
56840
+ this.failed = false;
56841
+ this.publish();
56842
+ }
56843
+ setActiveTarget(target) {
56844
+ if (this.saving) return;
56845
+ this.activeTarget = target === "" ? GLOBAL_TARGET : target;
56846
+ this.publish();
56847
+ }
56848
+ /** 让当前目标恢复「跟随全局默认」:删掉它的专属列表。 */
56849
+ resetActiveTarget() {
56850
+ if (this.saving || this.activeTarget === "default") return;
56851
+ this.ensureDraft();
56852
+ const overrides = this.draftOverrides ?? this.currentOverrides();
56853
+ delete overrides[this.activeTarget];
56854
+ this.draftOverrides = overrides;
56855
+ this.failed = false;
56856
+ this.publish();
56857
+ }
56858
+ discard() {
56859
+ if (this.saving) return;
56860
+ this.clearDraft();
56861
+ this.publish();
56862
+ }
56863
+ /** 当前目标的候选行:目录 ∪ 已保存 ∪ 草稿里出现的每一条。 */
56864
+ candidates() {
56865
+ const selected = new Set(this.activeRoutes().map(routeKey));
56866
+ const retained = /* @__PURE__ */ new Map();
56867
+ for (const route of this.activeRoutes()) retained.set(routeKey(route), route);
56868
+ for (const route of this.currentDefault()) retained.set(routeKey(route), route);
56869
+ for (const list of Object.values(this.overrides())) for (const route of list) retained.set(routeKey(route), route);
56870
+ const rows = [];
56871
+ for (const group of this.catalogGroups) {
56872
+ if (!group.provider || group.provider === "undefined") continue;
56873
+ for (const model of group.models) {
56874
+ if (!model.id || model.id === "undefined") continue;
56875
+ const key = `${group.provider}/${model.id}`;
56876
+ retained.delete(key);
56877
+ rows.push({
56878
+ provider: group.provider,
56879
+ model: model.id,
56880
+ key,
56881
+ providerName: group.providerName,
56882
+ modelName: model.name,
56883
+ available: true,
56884
+ selected: selected.has(key)
56885
+ });
56886
+ }
56887
+ }
56888
+ for (const [key, route] of retained) {
56889
+ if (!route.provider || !route.model || route.provider === "undefined" || route.model === "undefined") continue;
56890
+ rows.push({
56891
+ provider: route.provider,
56892
+ model: route.model,
56893
+ key,
56894
+ providerName: route.provider,
56895
+ modelName: route.model,
56896
+ available: false,
56897
+ selected: selected.has(key)
56898
+ });
56899
+ }
56900
+ return rows;
56901
+ }
56902
+ /** 主代理模型下拉的分组(目录分组 + 已保存但不可用的孤儿)。 */
56903
+ mainModelGroups() {
56904
+ const overrides = this.overrides();
56905
+ const groups = [];
56906
+ for (const group of this.catalogGroups) {
56907
+ if (!group.provider || group.provider === "undefined") continue;
56908
+ const models = group.models.filter((model) => Boolean(model.id) && model.id !== "undefined").map((model) => {
56909
+ const key = `${group.provider}/${model.id}`;
56910
+ return {
56911
+ key,
56912
+ model: model.id,
56913
+ modelName: model.name,
56914
+ overridden: overrides[key] !== void 0
56915
+ };
56916
+ });
56917
+ if (models.length > 0) groups.push({
56918
+ provider: group.provider,
56919
+ providerName: group.providerName,
56920
+ models
56921
+ });
56922
+ }
56923
+ return groups;
56924
+ }
56925
+ /** 已保存但目录不公布的主代理模型键(下拉里单列一组)。 */
56926
+ orphanMainModels() {
56927
+ const known = /* @__PURE__ */ new Set();
56928
+ for (const group of this.catalogGroups) for (const model of group.models) known.add(`${group.provider}/${model.id}`);
56929
+ return Object.keys(this.overrides()).filter((key) => !known.has(key));
56930
+ }
56931
+ /**
56932
+ * 一次保存三份存储。
56933
+ */
56934
+ async save() {
56935
+ const state = this.store.getSnapshot();
56936
+ if (this.disposed || this.saving || !state.available || !state.writable || !state.dirty || state.invalid) return;
56937
+ const desiredEnabled = this.enabled();
56938
+ const desiredDefault = this.defaultRoutes();
56939
+ const desiredOverrides = this.overrides();
56940
+ const generation = this.saveGeneration;
56941
+ this.saving = true;
56942
+ this.failed = false;
56943
+ this.publish();
56944
+ try {
56945
+ const initial = this.currentOverrides();
56946
+ const patch = {};
56947
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(initial), ...Object.keys(desiredOverrides)])) {
56948
+ const list = desiredOverrides[key];
56949
+ patch[key] = list !== void 0 && list.length > 0 ? cloneRoutes(list) : null;
56950
+ }
56951
+ await this.savePreferences({
56952
+ subagentDefaultModels: cloneRoutes(desiredDefault),
56953
+ subagentModelsByMainModel: patch
56954
+ });
56955
+ if (this.disposed || generation !== this.saveGeneration) return;
56956
+ const nextOverrides = {};
56957
+ for (const [k, v] of Object.entries(desiredOverrides)) if (v.length > 0) nextOverrides[k] = cloneRoutes(v);
56958
+ this.preferences = {
56959
+ subagentDefaultModels: cloneRoutes(desiredDefault),
56960
+ subagentModelsByMainModel: nextOverrides
56961
+ };
56962
+ this.preferencesStatus = "ready";
56963
+ const union = /* @__PURE__ */ new Map();
56964
+ for (const route of desiredDefault) union.set(routeKey(route), {
56965
+ provider: route.provider,
56966
+ model: route.model
56967
+ });
56968
+ for (const list of Object.values(desiredOverrides)) for (const route of list) union.set(routeKey(route), {
56969
+ provider: route.provider,
56970
+ model: route.model
56971
+ });
56972
+ const unionRoutes = [...union.values()];
56973
+ const scope = this.modelSelection;
56974
+ const modelSnapshot = scope.getSnapshot();
56975
+ if ((this.currentEnabled() !== desiredEnabled || !sameRouteSet(modelSnapshot.value?.allowedModels ?? [], unionRoutes)) && modelSnapshot.status === "ready") {
56976
+ const ops = [{
56977
+ op: "set",
56978
+ path: ["enabled"],
56979
+ value: desiredEnabled
56980
+ }, {
56981
+ op: "set",
56982
+ path: ["allowedModels"],
56983
+ value: unionRoutes
56984
+ }];
56985
+ if (typeof scope.mutate === "function") {
56986
+ if (await scope.mutate(ops, modelSnapshot.revision ?? this.draftRevision) === false) throw new Error("The deployment rejected the subagent model selection settings.");
56987
+ } else if (typeof scope.set === "function") {
56988
+ const ok1 = await scope.set("enabled", desiredEnabled);
56989
+ const ok2 = await scope.set("allowedModels", unionRoutes);
56990
+ if (ok1 === false || ok2 === false) throw new Error("The deployment rejected the subagent model selection settings.");
56991
+ }
56992
+ }
56993
+ if (state.maxDepth.invalid || state.maxActiveSubagents.invalid) throw new Error("invalid limits");
56994
+ const limitsSnapshot = this.limits.getSnapshot();
56995
+ const limitsOps = [];
56996
+ if (this.draftDepthCleared) {
56997
+ if (userHas(limitsSnapshot.user, "maxDepth")) limitsOps.push({
56998
+ op: "unset",
56999
+ path: ["maxDepth"]
57000
+ });
57001
+ } else if (this.draftDepth !== void 0) {
57002
+ const nextDepth = parseLimit(this.draftDepth, 0);
57003
+ if (nextDepth !== void 0 && nextDepth !== readNumber(limitsSnapshot.value, "maxDepth", nextDepth)) limitsOps.push({
57004
+ op: "set",
57005
+ path: ["maxDepth"],
57006
+ value: nextDepth
57007
+ });
57008
+ }
57009
+ if (this.draftActiveCleared) {
57010
+ if (userHas(limitsSnapshot.user, "maxActiveSubagents")) limitsOps.push({
57011
+ op: "unset",
57012
+ path: ["maxActiveSubagents"]
57013
+ });
57014
+ } else if (this.draftActive !== void 0) {
57015
+ const nextActive = parseLimit(this.draftActive, 1);
57016
+ if (nextActive !== void 0 && nextActive !== readNumber(limitsSnapshot.value, "maxActiveSubagents", nextActive)) limitsOps.push({
57017
+ op: "set",
57018
+ path: ["maxActiveSubagents"],
57019
+ value: nextActive
57020
+ });
57021
+ }
57022
+ if (limitsOps.length > 0 && limitsSnapshot.status === "ready") {
57023
+ if (typeof this.limits.mutate === "function") {
57024
+ if (await this.limits.mutate(limitsOps, limitsSnapshot.revision) === false) throw new Error("The deployment rejected the subagent limits.");
57025
+ } else if (typeof this.limits.set === "function") {
57026
+ for (const op of limitsOps) if (op.op === "set") await this.limits.set(op.path[0], op.value);
57027
+ }
57028
+ }
57029
+ if (this.disposed || generation !== this.saveGeneration) return;
57030
+ this.saving = false;
57031
+ this.clearDraft();
57032
+ this.publish();
57033
+ } catch {
57034
+ if (this.disposed || generation !== this.saveGeneration) return;
57035
+ this.saving = false;
57036
+ this.failed = true;
57037
+ this.publish();
57038
+ }
57039
+ }
57040
+ limitField(field, minimum, fallback) {
57041
+ const snapshot = this.limits.getSnapshot();
57042
+ const base = readNumber(snapshot.base, field, readNumber(snapshot.value, field, fallback));
57043
+ const current = readNumber(snapshot.value, field, fallback);
57044
+ const draft = field === "maxDepth" ? this.draftDepth : this.draftActive;
57045
+ const cleared = field === "maxDepth" ? this.draftDepthCleared : this.draftActiveCleared;
57046
+ const text = cleared ? String(base) : draft ?? String(current);
57047
+ const persistedOverridden = userHas(snapshot.user, field) || base !== current;
57048
+ const overridden = cleared ? false : draft !== void 0 ? text.trim() !== "" && text.trim() !== String(base) : persistedOverridden;
57049
+ const invalid = cleared ? false : parseLimit(text, minimum) === void 0;
57050
+ return {
57051
+ value: text,
57052
+ base: String(base),
57053
+ overridden,
57054
+ invalid
57055
+ };
57056
+ }
57057
+ projection() {
57058
+ const limitsSnapshot = this.limits.getSnapshot();
57059
+ const modelSnapshot = this.modelSelection.getSnapshot();
57060
+ const limitsAvailable = limitsSnapshot.status === "ready";
57061
+ const modelsAvailable = modelSnapshot.status === "ready";
57062
+ const maxDepth = this.limitField("maxDepth", 0, 1);
57063
+ const maxActive = this.limitField("maxActiveSubagents", 1, 8);
57064
+ const enabled = this.enabled();
57065
+ const desiredDefault = this.defaultRoutes();
57066
+ const desiredOverrides = this.overrides();
57067
+ const currentOverrides = this.currentOverrides();
57068
+ const currentDefault = this.currentDefault();
57069
+ const union = /* @__PURE__ */ new Map();
57070
+ for (const route of desiredDefault) union.set(routeKey(route), route);
57071
+ for (const list of Object.values(desiredOverrides)) for (const route of list) union.set(routeKey(route), route);
57072
+ const hostAllowed = cloneRoutes(modelSnapshot.value?.allowedModels ?? []);
57073
+ const modelsDirty = this.currentEnabled() !== enabled || !sameRouteSet(currentDefault, desiredDefault) || !sameOverrides(currentOverrides, desiredOverrides) || this.draftDefault !== void 0 && !sameRouteSet(hostAllowed, [...union.values()]);
57074
+ const depthPersistedOverridden = userHas(limitsSnapshot.user, "maxDepth");
57075
+ const activePersistedOverridden = userHas(limitsSnapshot.user, "maxActiveSubagents");
57076
+ const depthDirty = this.draftDepthCleared ? depthPersistedOverridden : this.draftDepth !== void 0 && maxDepth.value !== String(readNumber(limitsSnapshot.value, "maxDepth", 1));
57077
+ const activeDirty = this.draftActiveCleared ? activePersistedOverridden : this.draftActive !== void 0 && maxActive.value !== String(readNumber(limitsSnapshot.value, "maxActiveSubagents", 8));
57078
+ const limitsDirty = depthDirty || activeDirty;
57079
+ const emptyOverride = Object.values(desiredOverrides).some((list) => list.length === 0);
57080
+ const invalid = maxDepth.invalid || maxActive.invalid || enabled && (desiredDefault.length === 0 || emptyOverride);
57081
+ const activeOverridden = this.activeTarget !== "default" && desiredOverrides[this.activeTarget] !== void 0;
57082
+ return {
57083
+ available: limitsAvailable || modelsAvailable,
57084
+ writable: (limitsAvailable ? limitsSnapshot.writable : true) && (modelsAvailable ? modelSnapshot.writable : true),
57085
+ dirty: limitsDirty || modelsDirty,
57086
+ invalid,
57087
+ saving: this.saving,
57088
+ failed: this.failed,
57089
+ maxDepth,
57090
+ maxActiveSubagents: maxActive,
57091
+ enabled,
57092
+ activeTarget: this.activeTarget,
57093
+ defaultCount: desiredDefault.length,
57094
+ overridesByMainModel: desiredOverrides,
57095
+ mainModelGroups: this.mainModelGroups(),
57096
+ orphanMainModels: this.orphanMainModels(),
57097
+ catalogStatus: this.catalogStatus,
57098
+ catalogPartial: this.catalogPartial,
57099
+ candidates: this.candidates(),
57100
+ activeTargetOverridden: activeOverridden,
57101
+ activeTargetCount: this.activeRoutes().length,
57102
+ preferencesStatus: this.preferencesStatus
57103
+ };
57104
+ }
57105
+ publish() {
57106
+ if (this.disposed) return;
57107
+ this.store.setState(this.projection());
57108
+ }
57109
+ };
57110
+ //#endregion
57111
+ //#region src/client/subagent/SubagentCard.tsx
57112
+ /**
57113
+ * 「子智能体」设置卡片:运行限制 + 模型选择(全局默认 + 按主代理模型覆盖)。
57114
+ *
57115
+ * 1:1 还原 DSH 官方 `@deepseek-ai/dsh-client-ui-settings-subagent` 的 DOM 层次与样式:
57116
+ * - 运行限制:双列响应式网格,标题旁带 `?` 帮助按钮(展开显示深度说明表格),全宽数字输入框;
57117
+ * - 模型选择:官方胶囊开关、主代理模型切换栏、以及带滚动条(max-height: 280px)和提供方分隔线的子智能体模型勾选框;
57118
+ * - 保存栏:左对齐保存按钮,卸载页面时自动丢弃未保存草稿。
57119
+ *
57120
+ * @module @eddyskywalker/dsh-chatgpt-subscription/client/subagent/SubagentCard
57121
+ */
57122
+ /** 把 {count} 占位符换成一个数。 */
57123
+ function withCount(template, count) {
57124
+ return template.replace("{count}", String(count));
57125
+ }
57126
+ /** 与官方 IconInfoOutlineRegular 一致的 12px 信息圆圈图标。 */
57127
+ function InfoIcon() {
57128
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
57129
+ width: "12",
57130
+ height: "12",
57131
+ viewBox: "0 0 16 16",
57132
+ fill: "none",
57133
+ "aria-hidden": "true",
57134
+ children: [
57135
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
57136
+ cx: "8",
57137
+ cy: "8",
57138
+ r: "6.25",
57139
+ stroke: "currentColor",
57140
+ strokeWidth: "1.3"
57141
+ }),
57142
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
57143
+ d: "M8 7.2V11",
57144
+ stroke: "currentColor",
57145
+ strokeWidth: "1.3",
57146
+ strokeLinecap: "round"
57147
+ }),
57148
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
57149
+ cx: "8",
57150
+ cy: "4.9",
57151
+ r: "0.75",
57152
+ fill: "currentColor"
57153
+ })
57154
+ ]
57155
+ });
57156
+ }
57157
+ /** 一行模型勾选项(1:1 复刻官方 SubagentModelSelectionFields 的 renderCandidate)。 */
57158
+ function ModelRow(props) {
57159
+ const { candidate } = props;
57160
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
57161
+ className: "dsh-subagent-model",
57162
+ "data-dsh-part": "subagent-model",
57163
+ children: [
57164
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
57165
+ type: "checkbox",
57166
+ checked: candidate.selected,
57167
+ disabled: props.disabled,
57168
+ "aria-label": candidate.providerName + " " + candidate.modelName,
57169
+ onChange: () => {
57170
+ props.onToggle(candidate.key);
57171
+ }
57172
+ }),
57173
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
57174
+ className: "dsh-subagent-model-name",
57175
+ children: candidate.modelName
57176
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
57177
+ className: "dsh-subagent-model-route",
57178
+ children: candidate.providerName + " · " + candidate.provider + "/" + candidate.model
57179
+ })] }),
57180
+ candidate.available ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
57181
+ className: "dsh-subagent-model-unavailable",
57182
+ children: props.unavailableLabel
57183
+ })
57184
+ ]
57185
+ });
57186
+ }
57187
+ /** 1:1 复刻官方 SettingsValueField:标签 + 帮助按钮 + 已覆盖徽标/恢复默认 + 全宽输入框。 */
57188
+ function LimitField(props) {
57189
+ const [helpOpen, setHelpOpen] = (0, react.useState)(false);
57190
+ const helpId = props.id + "-help";
57191
+ const messageId = props.id + "-message";
57192
+ const description = [props.invalid ? messageId : "", helpOpen ? helpId : ""].filter(Boolean).join(" ");
57193
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57194
+ className: "dsh-subagent-field",
57195
+ "data-dsh-part": props.id,
57196
+ children: [
57197
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57198
+ className: "dsh-subagent-field-head",
57199
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57200
+ className: "dsh-subagent-label-group",
57201
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
57202
+ className: "dsh-subagent-label",
57203
+ htmlFor: props.id,
57204
+ children: props.label
57205
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57206
+ type: "button",
57207
+ className: "dsh-subagent-help-btn",
57208
+ "aria-label": props.helpLabel,
57209
+ "aria-expanded": helpOpen,
57210
+ "aria-controls": helpId,
57211
+ onClick: () => {
57212
+ setHelpOpen(!helpOpen);
57213
+ },
57214
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoIcon, {})
57215
+ })]
57216
+ }), props.overridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
57217
+ className: "dsh-subagent-badges",
57218
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
57219
+ className: "dsh-subagent-override-tag",
57220
+ children: props.overriddenLabel
57221
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57222
+ type: "button",
57223
+ className: "dsh-subagent-reset-link",
57224
+ "data-dsh-part": props.id + "-reset",
57225
+ disabled: props.disabled,
57226
+ onClick: props.onReset,
57227
+ children: props.resetLabel
57228
+ })]
57229
+ }) : null]
57230
+ }),
57231
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
57232
+ id: props.id,
57233
+ type: "text",
57234
+ inputMode: "numeric",
57235
+ className: "dsh-subagent-input",
57236
+ "aria-label": props.label,
57237
+ "aria-describedby": description || void 0,
57238
+ ...props.invalid ? { "aria-invalid": true } : {},
57239
+ value: props.value,
57240
+ disabled: props.disabled,
57241
+ onChange: (event) => {
57242
+ props.onEdit(event.target.value);
57243
+ }
57244
+ }),
57245
+ props.invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57246
+ id: messageId,
57247
+ className: "dsh-subagent-invalid",
57248
+ role: "alert",
57249
+ children: props.invalidLabel
57250
+ }) : null,
57251
+ helpOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57252
+ id: helpId,
57253
+ className: "dsh-subagent-help-box",
57254
+ role: "region",
57255
+ "aria-label": props.helpLabel,
57256
+ children: props.helpContent
57257
+ }) : null
57258
+ ]
57259
+ });
57260
+ }
57261
+ /**
57262
+ * 渲染子智能体设置。
57263
+ * @param props - 框架座位、t,以及注入的快照与动作。
57264
+ * @returns summary 时是一句简介,page 时是整张表单。
57265
+ */
57266
+ function SubagentCard(props) {
57267
+ const { t } = props;
57268
+ const state = (0, react.useSyncExternalStore)(props.store.subscribe, props.store.getSnapshot, props.store.getSnapshot);
57269
+ const headingId = (0, react.useId)();
57270
+ const discardRef = (0, react.useRef)(props.discard);
57271
+ discardRef.current = props.discard;
57272
+ (0, react.useEffect)(() => () => {
57273
+ if (props.view === "page") discardRef.current();
57274
+ }, [props.view]);
57275
+ if (props.view === "summary") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: t("subagentDescription") });
57276
+ if (!state.available) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57277
+ className: "dsh-subagent-unavailable-notice",
57278
+ role: "status",
57279
+ children: t("unavailable")
57280
+ });
57281
+ const disabled = !state.writable || state.saving;
57282
+ const groups = /* @__PURE__ */ new Map();
57283
+ const unavailable = [];
57284
+ for (const candidate of state.candidates) {
57285
+ if (!candidate.available) {
57286
+ unavailable.push(candidate);
57287
+ continue;
57288
+ }
57289
+ const group = groups.get(candidate.provider);
57290
+ if (group === void 0) groups.set(candidate.provider, {
57291
+ providerName: candidate.providerName,
57292
+ rows: [candidate]
57293
+ });
57294
+ else group.rows.push(candidate);
57295
+ }
57296
+ /** 主代理模型的显示名:目录里有就用目录的,没有就用键本身。 */
57297
+ const mainModelName = (key) => {
57298
+ for (const group of state.mainModelGroups) for (const model of group.models) if (model.key === key) return model.modelName;
57299
+ return key;
57300
+ };
57301
+ const activeModelKey = state.activeTarget;
57302
+ const overrideKeys = Object.keys(state.overridesByMainModel);
57303
+ const limitsHeadingId = headingId + "-limits";
57304
+ const modelsHeadingId = headingId + "-models";
57305
+ const mainModelId = headingId + "-main-model";
57306
+ const blocked = !state.dirty || state.invalid || state.saving || !state.writable;
57307
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57308
+ className: "dsh-subagent-form",
57309
+ "data-dsh-plugin": "subagent",
57310
+ "data-dsh-part": "subagent-form",
57311
+ children: [
57312
+ !state.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57313
+ className: "dsh-subagent-readonly-notice",
57314
+ role: "status",
57315
+ children: t("readOnly")
57316
+ }) : null,
57317
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
57318
+ className: "dsh-subagent-section",
57319
+ "aria-labelledby": limitsHeadingId,
57320
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
57321
+ className: "dsh-subagent-heading",
57322
+ id: limitsHeadingId,
57323
+ children: t("subagentLimitsTitle")
57324
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57325
+ className: "dsh-subagent-limits-grid",
57326
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57327
+ className: "dsh-subagent-limit-cell",
57328
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimitField, {
57329
+ id: "plugin-config-subagent-depth",
57330
+ label: t("subagentMaxDepth"),
57331
+ helpLabel: t("subagentDepthHelpLabel"),
57332
+ helpContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
57333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthHelp") }),
57334
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("table", {
57335
+ className: "dsh-subagent-depth-table",
57336
+ "aria-label": t("subagentDepthHelpLabel"),
57337
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tbody", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
57338
+ scope: "row",
57339
+ children: 0
57340
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthZero") })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", {
57341
+ scope: "row",
57342
+ children: 1
57343
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthOne") })] })] })
57344
+ }),
57345
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthOverride") })
57346
+ ] }),
57347
+ value: state.maxDepth.value,
57348
+ overridden: state.maxDepth.overridden,
57349
+ overriddenLabel: t("overridden"),
57350
+ resetLabel: t("reset"),
57351
+ invalidLabel: t("subagentDepthInvalid"),
57352
+ invalid: state.maxDepth.invalid,
57353
+ disabled,
57354
+ onEdit: (text) => {
57355
+ props.editLimit("maxDepth", text);
57356
+ },
57357
+ onReset: () => {
57358
+ props.resetLimit("maxDepth");
57359
+ }
57360
+ })
57361
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57362
+ className: "dsh-subagent-limit-cell",
57363
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LimitField, {
57364
+ id: "plugin-config-subagent-capacity",
57365
+ label: t("subagentMaxActive"),
57366
+ helpLabel: t("subagentCapacityHelpLabel"),
57367
+ helpContent: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("subagentCapacityHelp") }),
57368
+ value: state.maxActiveSubagents.value,
57369
+ overridden: state.maxActiveSubagents.overridden,
57370
+ overriddenLabel: t("overridden"),
57371
+ resetLabel: t("reset"),
57372
+ invalidLabel: t("subagentCapacityInvalid"),
57373
+ invalid: state.maxActiveSubagents.invalid,
57374
+ disabled,
57375
+ onEdit: (text) => {
57376
+ props.editLimit("maxActiveSubagents", text);
57377
+ },
57378
+ onReset: () => {
57379
+ props.resetLimit("maxActiveSubagents");
57380
+ }
57381
+ })
57382
+ })]
57383
+ })]
57384
+ }),
57385
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
57386
+ className: "dsh-subagent-section",
57387
+ "aria-labelledby": modelsHeadingId,
57388
+ children: [
57389
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
57390
+ className: "dsh-subagent-heading",
57391
+ id: modelsHeadingId,
57392
+ children: t("subagentModelSelectionTitle")
57393
+ }),
57394
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57395
+ className: "dsh-subagent-permission",
57396
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57397
+ className: "dsh-subagent-toggle-row",
57398
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
57399
+ className: "dsh-subagent-toggle-label",
57400
+ children: t("subagentModelSelectionToggle")
57401
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57402
+ type: "button",
57403
+ role: "switch",
57404
+ "aria-checked": state.enabled,
57405
+ "aria-label": t("subagentModelSelectionToggle"),
57406
+ className: "dsh-subagent-switch",
57407
+ "data-dsh-part": "subagent-enabled-switch",
57408
+ disabled,
57409
+ onClick: () => {
57410
+ props.toggleEnabled();
57411
+ },
57412
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsh-subagent-switch-thumb" })
57413
+ })]
57414
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57415
+ className: "dsh-subagent-hint",
57416
+ children: t(state.enabled ? "subagentModelSelectionChoose" : "subagentModelSelectionOff")
57417
+ })]
57418
+ }),
57419
+ state.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57420
+ className: "dsh-subagent-selection",
57421
+ "data-dsh-part": "subagent-target",
57422
+ children: [
57423
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57424
+ className: "dsh-subagent-target-bar",
57425
+ children: [
57426
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57427
+ className: "dsh-subagent-target-header",
57428
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
57429
+ className: "dsh-subagent-target-label",
57430
+ htmlFor: mainModelId,
57431
+ children: t("subagentMainModelLabel")
57432
+ }), activeModelKey !== "default" && state.activeTargetOverridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57433
+ type: "button",
57434
+ className: "dsh-subagent-reset",
57435
+ "data-dsh-part": "subagent-reset-to-global",
57436
+ disabled,
57437
+ onClick: () => {
57438
+ props.resetActiveTarget();
57439
+ },
57440
+ children: t("subagentResetToGlobal")
57441
+ }) : null]
57442
+ }),
57443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
57444
+ id: mainModelId,
57445
+ className: "dsh-subagent-select",
57446
+ "data-dsh-part": "subagent-main-model",
57447
+ "aria-label": t("subagentMainModelLabel"),
57448
+ value: activeModelKey,
57449
+ disabled,
57450
+ onChange: (event) => {
57451
+ props.setActiveTarget(event.target.value);
57452
+ },
57453
+ children: [
57454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
57455
+ value: GLOBAL_TARGET,
57456
+ children: t("subagentMainModelGlobalOption")
57457
+ }),
57458
+ state.mainModelGroups.map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("optgroup", {
57459
+ label: group.providerName,
57460
+ children: group.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
57461
+ value: model.key,
57462
+ children: model.modelName + " · " + model.key + (model.overridden ? t("subagentOverrideBadge") : "")
57463
+ }, model.key))
57464
+ }, group.provider)),
57465
+ state.orphanMainModels.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("optgroup", {
57466
+ label: t("subagentModelSelectionUnavailableGroup"),
57467
+ children: state.orphanMainModels.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
57468
+ value: key,
57469
+ children: mainModelName(key) + " · " + key + t("subagentOverrideBadge")
57470
+ }, key))
57471
+ }) : null
57472
+ ]
57473
+ }),
57474
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57475
+ className: "dsh-subagent-chips",
57476
+ "data-dsh-part": "subagent-chips",
57477
+ "aria-label": t("subagentMainModelQuickSwitch"),
57478
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57479
+ type: "button",
57480
+ className: "dsh-subagent-chip",
57481
+ "data-dsh-part": "subagent-chip-global",
57482
+ "aria-pressed": activeModelKey === GLOBAL_TARGET,
57483
+ disabled,
57484
+ onClick: () => {
57485
+ props.setActiveTarget(GLOBAL_TARGET);
57486
+ },
57487
+ children: withCount(t("subagentChipGlobal"), state.defaultCount)
57488
+ }), overrideKeys.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57489
+ type: "button",
57490
+ className: "dsh-subagent-chip",
57491
+ "data-dsh-part": "subagent-chip-override",
57492
+ "aria-pressed": activeModelKey === key,
57493
+ disabled,
57494
+ onClick: () => {
57495
+ props.setActiveTarget(key);
57496
+ },
57497
+ children: mainModelName(key) + " (" + String(state.overridesByMainModel[key]?.length ?? 0) + ")"
57498
+ }, key))]
57499
+ }),
57500
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57501
+ className: "dsh-subagent-status",
57502
+ "data-dsh-part": "subagent-target-status",
57503
+ children: activeModelKey === "default" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57504
+ className: "dsh-subagent-hint",
57505
+ children: t("subagentTargetGlobalHint")
57506
+ }) : state.activeTargetOverridden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57507
+ className: "dsh-subagent-hint",
57508
+ children: withCount(t("subagentTargetOverrideStatus"), state.activeTargetCount)
57509
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57510
+ className: "dsh-subagent-hint",
57511
+ children: t("subagentTargetFollowGlobalStatus")
57512
+ })
57513
+ })
57514
+ ]
57515
+ }),
57516
+ state.catalogStatus === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57517
+ className: "dsh-subagent-notice",
57518
+ role: "status",
57519
+ children: t("subagentModelSelectionLoading")
57520
+ }) : null,
57521
+ state.catalogStatus === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57522
+ className: "dsh-subagent-catalog-error",
57523
+ role: "alert",
57524
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("subagentModelSelectionLoadFailed") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57525
+ type: "button",
57526
+ "data-dsh-part": "subagent-retry-catalog",
57527
+ disabled: state.saving,
57528
+ onClick: () => {
57529
+ props.retryCatalog();
57530
+ },
57531
+ children: t("subagentModelSelectionRetry")
57532
+ })]
57533
+ }) : null,
57534
+ state.catalogPartial ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57535
+ className: "dsh-subagent-notice",
57536
+ children: t("subagentModelSelectionPartial")
57537
+ }) : null,
57538
+ state.candidates.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
57539
+ className: "dsh-subagent-models",
57540
+ children: [
57541
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", { children: t("subagentModelSelectionAllowed") }),
57542
+ [...groups].map(([provider, group]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57543
+ className: "dsh-subagent-group",
57544
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57545
+ className: "dsh-subagent-group-name",
57546
+ children: group.providerName
57547
+ }), group.rows.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
57548
+ candidate,
57549
+ disabled,
57550
+ unavailableLabel: t("subagentModelSelectionUnavailable"),
57551
+ onToggle: (key) => {
57552
+ props.toggleModel(key);
57553
+ }
57554
+ }, candidate.key))]
57555
+ }, provider)),
57556
+ unavailable.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57557
+ className: "dsh-subagent-group",
57558
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
57559
+ className: "dsh-subagent-group-name",
57560
+ children: t("subagentModelSelectionUnavailableGroup")
57561
+ }), unavailable.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
57562
+ candidate,
57563
+ disabled,
57564
+ unavailableLabel: t("subagentModelSelectionUnavailable"),
57565
+ onToggle: (key) => {
57566
+ props.toggleModel(key);
57567
+ }
57568
+ }, candidate.key))]
57569
+ }) : null
57570
+ ]
57571
+ }) : state.catalogStatus === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57572
+ className: "dsh-subagent-notice",
57573
+ children: t("subagentModelSelectionEmpty")
57574
+ }) : null,
57575
+ state.invalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57576
+ className: "dsh-subagent-invalid",
57577
+ role: "alert",
57578
+ children: t("subagentModelPerTargetRequired")
57579
+ }) : null
57580
+ ]
57581
+ }) : null
57582
+ ]
57583
+ }),
57584
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
57585
+ className: "dsh-subagent-footer",
57586
+ "data-dsh-part": "subagent-footer",
57587
+ children: [
57588
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57589
+ type: "button",
57590
+ className: "dsh-subagent-save",
57591
+ "data-dsh-part": "subagent-save",
57592
+ disabled: blocked,
57593
+ onClick: () => {
57594
+ props.save();
57595
+ },
57596
+ children: state.saving ? t("saving") : t("save")
57597
+ }),
57598
+ state.dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
57599
+ type: "button",
57600
+ className: "dsh-subagent-discard",
57601
+ "data-dsh-part": "subagent-discard",
57602
+ disabled: state.saving,
57603
+ onClick: () => {
57604
+ props.discard();
57605
+ },
57606
+ children: t("discard")
57607
+ }) : null,
57608
+ state.failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
57609
+ className: "dsh-subagent-failed",
57610
+ role: "alert",
57611
+ children: t("saveFailed")
57612
+ }) : null
57613
+ ]
57614
+ })
57615
+ ]
57616
+ });
57617
+ }
57618
+ //#endregion
57619
+ //#region src/client/subagent/locales.ts
57620
+ /**
57621
+ * 「子智能体」设置卡片的文案与命名空间。
57622
+ *
57623
+ * ## 为什么这里另起一个命名空间
57624
+ *
57625
+ * 宿主自带的子智能体设置页有自己的 `settings.subagent` 命名空间,而本卡是
57626
+ * **替换**它(同 id、更低 priority 遮蔽),不是与它并存。文案表因此归本插件所有:
57627
+ * 键名沿用本插件其余线路的扁平驼峰(`hubTitle`、`settingsEnabledName` 那一套),
57628
+ * 不引入宿主的点号风格。
57629
+ *
57630
+ * ## 键集是契约
57631
+ *
57632
+ * `SubagentLocaleKey` 由中文表反推,英文表用 `Record<SubagentLocaleKey, string>`
57633
+ * 钉死——少一条键编译期就报,而不是等到界面上渲染出键名本身。
57634
+ */
57635
+ /** 本卡片在 locale 服务里的命名空间。 */
57636
+ const NS_SUBAGENT = "dsh-subagent-settings";
57637
+ /** 中文文案(键集的唯一定义处)。 */
57638
+ const zh = {
57639
+ overridden: "已覆盖",
57640
+ reset: "恢复默认",
57641
+ readOnly: "本部署的设置为只读。",
57642
+ unavailable: "该插件当前未加载,暂时无法配置。",
57643
+ save: "保存",
57644
+ saving: "保存中…",
57645
+ saveFailed: "本部署没有接受这些值,已保留供你修改。",
57646
+ discard: "放弃修改",
57647
+ subagentTitle: "子智能体",
57648
+ subagentDescription: "设置子智能体的递归层级、数量和模型。",
57649
+ subagentLimitsTitle: "运行限制",
57650
+ subagentMaxDepth: "最大递归深度",
57651
+ subagentDepthHelpLabel: "最大递归深度说明",
57652
+ subagentDepthHelp: "限制 Agent 创建子智能体的递归层级。",
57653
+ subagentDepthZero: "禁用子智能体",
57654
+ subagentDepthOne: "仅允许主 Agent 创建子智能体",
57655
+ subagentDepthOverride: "如果某个工具单独设置了最大递归深度,以该工具的设置为准。",
57656
+ subagentMaxActive: "子智能体并行数量上限",
57657
+ subagentCapacityHelpLabel: "子智能体并行数量上限说明",
57658
+ subagentCapacityHelp: "同一主 Agent 下,所有递归层级同时存活的子智能体总数,主 Agent 不计入。达到上限时,新的启动请求会被拒绝。",
57659
+ subagentDepthInvalid: "请输入不小于 0 的整数。",
57660
+ subagentCapacityInvalid: "请输入不小于 1 的整数。",
57661
+ subagentModelSelectionTitle: "模型选择",
57662
+ subagentModelSelectionToggle: "允许 Agent 为子智能体选择模型",
57663
+ subagentModelSelectionChoose: "开启后,Agent 可以从下方授权模型中,为每个子智能体选择提供方、模型和推理强度。仅影响新会话。",
57664
+ subagentModelSelectionAllowed: "Agent 可选择的模型",
57665
+ subagentModelSelectionLoading: "正在加载模型…",
57666
+ subagentModelSelectionLoadFailed: "无法加载模型。",
57667
+ subagentModelSelectionRetry: "重试",
57668
+ subagentModelSelectionPartial: "部分模型提供方暂时无法加载;已保存的选择仍可移除。",
57669
+ subagentModelSelectionUnavailable: "当前不可用",
57670
+ subagentModelSelectionUnavailableGroup: "已保存但当前不可用",
57671
+ subagentModelSelectionEmpty: "当前没有模型提供方公布模型。",
57672
+ subagentModelSelectionRequired: "保存前请至少选择一个模型。",
57673
+ subagentModelSelectionOff: "关闭后,子智能体使用配置的默认模型或继承父 Agent 的模型;已选模型会保留。",
57674
+ subagentMainModelLabel: "主代理模型配置栏",
57675
+ subagentMainModelGlobalOption: "全局默认(未单独配置的主代理使用)",
57676
+ subagentMainModelQuickSwitch: "快捷切换",
57677
+ subagentChipGlobal: "全局默认 ({count})",
57678
+ subagentTargetGlobalHint: "正在编辑全局默认子代理模型列表;未单独配置专属列表的主代理将使用此列表。",
57679
+ subagentTargetOverrideStatus: "已为该主代理单独配置 {count} 个子代理模型",
57680
+ subagentTargetFollowGlobalStatus: "当前跟随全局默认列表(勾选或取消下方模型即可为该主代理创建专属列表)",
57681
+ subagentResetToGlobal: "恢复跟随全局默认",
57682
+ subagentOverrideBadge: "(已覆盖)",
57683
+ subagentPreferencesLoadFailed: "无法读取已保存的子代理模型偏好;保存时将以当前界面为准。",
57684
+ subagentModelPerTargetRequired: "保存前请至少选择一个模型(或点击「恢复跟随全局默认」)。"
57685
+ };
57686
+ /** 英文对照,键集与中文完全一致。 */
57687
+ const en = {
57688
+ overridden: "Overridden",
57689
+ reset: "Reset to default",
57690
+ readOnly: "This deployment stores settings read-only.",
57691
+ unavailable: "This plugin is not loaded, so it cannot be configured right now.",
57692
+ save: "Save",
57693
+ saving: "Saving…",
57694
+ saveFailed: "The deployment did not accept these values; they were left for you to correct.",
57695
+ discard: "Discard changes",
57696
+ subagentTitle: "Subagent",
57697
+ subagentDescription: "Set Subagent recursion depth, count, and models.",
57698
+ subagentLimitsTitle: "Limits",
57699
+ subagentMaxDepth: "Maximum recursion depth",
57700
+ subagentDepthHelpLabel: "About maximum recursion depth",
57701
+ subagentDepthHelp: "Limits how many levels of Subagents an Agent can create.",
57702
+ subagentDepthZero: "Disable Subagents",
57703
+ subagentDepthOne: "Only the main Agent can create Subagents",
57704
+ subagentDepthOverride: "If a tool defines its own maximum recursion depth, that setting takes precedence.",
57705
+ subagentMaxActive: "Subagent parallelism limit",
57706
+ subagentCapacityHelpLabel: "About the Subagent parallelism limit",
57707
+ subagentCapacityHelp: "Total live Subagents under the same main Agent, across all recursion levels. The main Agent is excluded. New start requests are rejected when the limit is reached.",
57708
+ subagentDepthInvalid: "Enter a whole number of 0 or more.",
57709
+ subagentCapacityInvalid: "Enter a whole number of 1 or more.",
57710
+ subagentModelSelectionTitle: "Model selection",
57711
+ subagentModelSelectionToggle: "Allow agents to choose models for Subagents",
57712
+ subagentModelSelectionChoose: "When enabled, agents can choose a provider, model, and reasoning effort for each Subagent from the authorized models below. Applies only to new sessions.",
57713
+ subagentModelSelectionAllowed: "Models agents may choose",
57714
+ subagentModelSelectionLoading: "Loading models…",
57715
+ subagentModelSelectionLoadFailed: "Models could not be loaded.",
57716
+ subagentModelSelectionRetry: "Retry",
57717
+ subagentModelSelectionPartial: "Some model providers could not be loaded; saved choices remain removable.",
57718
+ subagentModelSelectionUnavailable: "Currently unavailable",
57719
+ subagentModelSelectionUnavailableGroup: "Saved but currently unavailable",
57720
+ subagentModelSelectionEmpty: "No model provider currently advertises a model.",
57721
+ subagentModelSelectionRequired: "Select at least one model before saving.",
57722
+ subagentModelSelectionOff: "Subagents use configured defaults or inherit the parent agent's model. Saved model choices are retained.",
57723
+ subagentMainModelLabel: "Main agent model",
57724
+ subagentMainModelGlobalOption: "Global default (used by main agents without their own list)",
57725
+ subagentMainModelQuickSwitch: "Quick switch",
57726
+ subagentChipGlobal: "Global default ({count})",
57727
+ subagentTargetGlobalHint: "Editing the global default subagent model list; main agents without their own list use it.",
57728
+ subagentTargetOverrideStatus: "This main agent has {count} dedicated subagent models",
57729
+ subagentTargetFollowGlobalStatus: "Currently following the global default list (tick or untick a model below to create a dedicated list for this main agent)",
57730
+ subagentResetToGlobal: "Follow the global default again",
57731
+ subagentOverrideBadge: " (overridden)",
57732
+ subagentPreferencesLoadFailed: "Saved subagent model preferences could not be read; saving will use what this page shows.",
57733
+ subagentModelPerTargetRequired: "Select at least one model before saving (or choose \"Follow the global default again\")."
57734
+ };
57735
+ /** 与其余线路同形的字典包(四个内置语言 id 都指向那两份)。 */
57736
+ const dictionaries = {
57737
+ zh,
57738
+ "zh-CN": zh,
57739
+ en,
57740
+ "en-US": en
57741
+ };
57742
+ //#endregion
57743
+ //#region src/client/subagent/index.ts
57744
+ /** 本卡在插件页里的槽位 id;与宿主同名,这是遮蔽的前提。 */
57745
+ const SUBAGENT_SLOT_ID = "subagent";
57746
+ function serviceOf(ctx, name) {
57747
+ try {
57748
+ return ctx.get?.(name);
57749
+ } catch {
57750
+ return;
57751
+ }
57752
+ }
57753
+ function isConfigForms(value) {
57754
+ if (typeof value !== "object" || value === null) return false;
57755
+ return typeof value.get === "function";
57756
+ }
57757
+ /**
57758
+ * 为 `ctx.slots.entries('plugins.item')` 安装按 `id` 的 cell 去重视图,
57759
+ * 避免 `configLedgerSource` 读原始账本时把被遮蔽的同 id 卡片也列出来。
57760
+ */
57761
+ function installPluginsItemLedgerDedup(slots) {
57762
+ if (typeof slots !== "object" || slots === null) return () => {};
57763
+ const target = slots;
57764
+ if (typeof target.entries !== "function") return () => {};
57765
+ const originalEntries = target.entries;
57766
+ let holder = target;
57767
+ let descriptor = Object.getOwnPropertyDescriptor(holder, "entries");
57768
+ while (descriptor === void 0) {
57769
+ const proto = Object.getPrototypeOf(holder);
57770
+ if (proto === null) break;
57771
+ holder = proto;
57772
+ descriptor = Object.getOwnPropertyDescriptor(holder, "entries");
57773
+ }
57774
+ if (descriptor !== void 0 && !descriptor.configurable && !descriptor.writable) return () => {};
57775
+ let cachedRaw;
57776
+ let cachedDeduped = [];
57777
+ const wrapped = function(key) {
57778
+ const raw = originalEntries.call(this ?? slots, key);
57779
+ if (key !== "plugins.item" || !Array.isArray(raw) || raw.length <= 1) return raw;
57780
+ if (raw === cachedRaw) return cachedDeduped;
57781
+ const seenIds = /* @__PURE__ */ new Set();
57782
+ const deduped = [];
57783
+ for (const entry of raw) {
57784
+ const id = entry?.options?.id;
57785
+ if (typeof id === "string" && id.length > 0) {
57786
+ if (seenIds.has(id)) continue;
57787
+ seenIds.add(id);
57788
+ }
57789
+ deduped.push(entry);
57790
+ }
57791
+ deduped.sort((a, b) => (a.options?.order ?? 0) - (b.options?.order ?? 0));
57792
+ cachedRaw = raw;
57793
+ cachedDeduped = deduped;
57794
+ return cachedDeduped;
57795
+ };
57796
+ try {
57797
+ Object.defineProperty(target, "entries", {
57798
+ value: wrapped,
57799
+ configurable: true,
57800
+ writable: true
57801
+ });
57802
+ } catch {
57803
+ return () => {};
57804
+ }
57805
+ return () => {
57806
+ try {
57807
+ if (target.entries === wrapped) {
57808
+ delete target.entries;
57809
+ if (target.entries !== originalEntries) Object.defineProperty(target, "entries", {
57810
+ value: originalEntries,
57811
+ configurable: true,
57812
+ writable: true
57813
+ });
57814
+ }
57815
+ } catch {}
57816
+ };
57817
+ }
57818
+ /**
57819
+ * 把本卡注册进插件页。
57820
+ */
57821
+ function installSubagentSettingsCard(ctx) {
57822
+ const forms = serviceOf(ctx, "configForms");
57823
+ if (!isConfigForms(forms)) return () => {};
57824
+ const controller = new SubagentSettingsController({
57825
+ limits: forms.get(SUBAGENT_LIMITS_NS),
57826
+ modelSelection: forms.get(SUBAGENT_MODEL_SELECTION_NS),
57827
+ loadCatalog: () => readSubagentCatalog(ctx),
57828
+ loadPreferences: readSubagentPreferences,
57829
+ savePreferences: writeSubagentPreferences
57830
+ });
57831
+ ctx.effect(() => () => {
57832
+ controller.dispose();
57833
+ }, "dsh-subagent-settings: form subscriptions");
57834
+ const remote = serviceOf(ctx, "remote");
57835
+ if (typeof remote?.$on === "function") {
57836
+ const $on = remote.$on.bind(remote);
57837
+ ctx.effect(() => $on("llm/adapters-updated", () => {
57838
+ controller.refreshCatalog();
57839
+ }), "dsh-subagent-settings: adapter invalidations");
57840
+ ctx.effect(() => $on("settings/document-updated", () => {
57841
+ controller.refreshCatalog();
57842
+ }), "dsh-subagent-settings: settings invalidations");
57843
+ }
57844
+ const on = ctx.on;
57845
+ if (typeof on === "function") ctx.effect(() => on.call(ctx, "connection/reset", () => {
57846
+ controller.resetConnection();
57847
+ }), "dsh-subagent-settings: connection reset");
57848
+ const face = controller.inject();
57849
+ const register = () => {
57850
+ try {
57851
+ const restoreEntries = installPluginsItemLedgerDedup(ctx.slots);
57852
+ const disposeInject = ctx.slots.inject("plugins.item", () => {
57853
+ try {
57854
+ return ctx.slots.register({
57855
+ name: "plugins.item",
57856
+ id: SUBAGENT_SLOT_ID,
57857
+ order: 10,
57858
+ priority: -10,
57859
+ label: () => {
57860
+ try {
57861
+ return ctx.locale.bind(NS_SUBAGENT)("subagentTitle");
57862
+ } catch {
57863
+ return "子智能体";
57864
+ }
57865
+ },
57866
+ locale: NS_SUBAGENT,
57867
+ inject: () => face
57868
+ }, SubagentCard);
57869
+ } catch {
57870
+ return () => {};
57871
+ }
57872
+ });
57873
+ return () => {
57874
+ disposeInject();
57875
+ restoreEntries();
57876
+ };
57877
+ } catch {
57878
+ return () => {};
57879
+ }
57880
+ };
57881
+ if (typeof forms.whileServed === "function") try {
57882
+ return forms.whileServed([SUBAGENT_LIMITS_NS, SUBAGENT_MODEL_SELECTION_NS], () => register());
57883
+ } catch {}
57884
+ return register();
57885
+ }
57886
+ //#endregion
57887
+ //#region src/client/subagent/styles.ts
57888
+ /**
57889
+ * 「子智能体」设置卡片的样式表。
57890
+ *
57891
+ * 1:1 对齐 DSH 官方 `ui-settings-subagent` 与 `ui-primitives` 的 CSS 规则与变量:
57892
+ * - `.dsh-subagent-section` / `.dsh-subagent-heading` 对应 `SubagentCard.module.css`
57893
+ * - `.dsh-subagent-limits-grid` / `.dsh-subagent-field` / `.dsh-subagent-input` 对应 `SubagentLimitsFields.module.css` + `fields.module.css`
57894
+ * - `.dsh-subagent-switch` 对应 `Switch.module.css`
57895
+ * - `.dsh-subagent-models` / `.dsh-subagent-group` / `.dsh-subagent-model` 对应 `SubagentModelSelectionFields.module.css`
57896
+ * - `.dsh-subagent-footer` / `.dsh-subagent-save` 对应 `SettingsForm.module.css`
57897
+ */
57898
+ /** 这张表的 `data-plugin-css` 子名。 */
57899
+ const STYLE_NAME = "subagent";
57900
+ /** 卡片与表单的样式全文。 */
57901
+ const SUBAGENT_CSS = `
57902
+ .dsh-subagent-form {
57903
+ display: flex;
57904
+ flex-direction: column;
57905
+ min-width: 0;
57906
+ }
57907
+
57908
+ .dsh-subagent-readonly-notice,
57909
+ .dsh-subagent-unavailable-notice {
57910
+ margin: 0 0 12px;
57911
+ font-size: 12px;
57912
+ line-height: 1.5;
57913
+ color: var(--dsw-alias-label-tertiary);
57914
+ }
57915
+
57916
+ .dsh-subagent-section {
57917
+ min-width: 0;
57918
+ padding: 16px 0;
57919
+ }
57920
+
57921
+ .dsh-subagent-heading {
57922
+ margin: 0;
57923
+ font-size: 13px;
57924
+ font-weight: 600;
57925
+ line-height: 1.5;
57926
+ color: var(--dsw-alias-label-primary);
57927
+ }
57928
+
57929
+ .dsh-subagent-limits-grid {
57930
+ display: grid;
57931
+ grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
57932
+ gap: 16px;
57933
+ }
57934
+
57935
+ .dsh-subagent-limit-cell {
57936
+ min-width: 0;
57937
+ }
57938
+
57939
+ .dsh-subagent-field {
57940
+ display: flex;
57941
+ flex-direction: column;
57942
+ gap: 6px;
57943
+ padding: 12px 0;
57944
+ min-width: 0;
57945
+ }
57946
+
57947
+ .dsh-subagent-field-head {
57948
+ display: flex;
57949
+ align-items: center;
57950
+ gap: 8px;
57951
+ }
57952
+
57953
+ .dsh-subagent-label-group {
57954
+ display: flex;
57955
+ align-items: center;
57956
+ gap: 4px;
57957
+ flex: 1;
57958
+ min-width: 0;
57959
+ }
57960
+
57961
+ .dsh-subagent-label {
57962
+ flex: 0 1 auto;
57963
+ min-width: 0;
57964
+ font-size: 13px;
57965
+ font-weight: 500;
57966
+ line-height: 1.5;
57967
+ color: var(--dsw-alias-label-primary);
57968
+ }
57969
+
57970
+ .dsh-subagent-help-btn {
57971
+ display: inline-flex;
57972
+ align-items: center;
57973
+ justify-content: center;
57974
+ flex: none;
57975
+ width: 24px;
57976
+ height: 24px;
57977
+ padding: 0;
57978
+ border: 0;
57979
+ border-radius: var(--dsw-radius-sm, 6px);
57980
+ background: none;
57981
+ color: var(--dsw-alias-label-tertiary);
57982
+ cursor: pointer;
57983
+ }
57984
+
57985
+ .dsh-subagent-help-btn[aria-expanded='true'] {
57986
+ background: var(--dsw-alias-bg-layer-4);
57987
+ color: var(--dsw-alias-label-secondary);
57988
+ }
57989
+
57990
+ @media (hover: hover) {
57991
+ .dsh-subagent-help-btn:hover {
57992
+ background: var(--dsw-alias-bg-layer-4);
57993
+ color: var(--dsw-alias-label-secondary);
57994
+ }
57995
+ }
57996
+
57997
+ .dsh-subagent-help-box {
57998
+ padding: 10px 0 0;
57999
+ font-size: 12px;
58000
+ line-height: 1.6;
58001
+ color: var(--dsw-alias-label-secondary);
58002
+ }
58003
+
58004
+ .dsh-subagent-help-box > p {
58005
+ margin: 0;
58006
+ }
58007
+
58008
+ .dsh-subagent-help-box > p + p {
58009
+ margin-top: 8px;
58010
+ }
58011
+
58012
+ .dsh-subagent-depth-table {
58013
+ width: 100%;
58014
+ margin: 8px 0;
58015
+ border-collapse: collapse;
58016
+ border-block: 0.5px solid var(--dsw-alias-border-l2);
58017
+ font: inherit;
58018
+ text-align: left;
58019
+ }
58020
+
58021
+ .dsh-subagent-depth-table th,
58022
+ .dsh-subagent-depth-table td {
58023
+ padding: 6px 0;
58024
+ vertical-align: top;
58025
+ }
58026
+
58027
+ .dsh-subagent-depth-table th {
58028
+ width: 24px;
58029
+ padding-right: 8px;
58030
+ font-weight: 500;
58031
+ font-variant-numeric: tabular-nums;
58032
+ color: var(--dsw-alias-label-primary);
58033
+ }
58034
+
58035
+ .dsh-subagent-depth-table tr + tr {
58036
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
58037
+ }
58038
+
58039
+ .dsh-subagent-badges {
58040
+ display: inline-flex;
58041
+ align-items: center;
58042
+ gap: 8px;
58043
+ }
58044
+
58045
+ .dsh-subagent-override-tag {
58046
+ display: inline-flex;
58047
+ align-items: center;
58048
+ padding: 1px 6px;
58049
+ border-radius: var(--dsw-radius-sm, 6px);
58050
+ background: var(--dsw-alias-bg-layer-4);
58051
+ font-size: 11px;
58052
+ line-height: 1.4;
58053
+ color: var(--dsw-alias-label-secondary);
58054
+ }
58055
+
58056
+ .dsh-subagent-reset-link {
58057
+ border: none;
58058
+ background: none;
58059
+ padding: 0;
58060
+ font: inherit;
58061
+ font-size: 12px;
58062
+ line-height: 1.5;
58063
+ color: var(--dsw-alias-label-secondary);
58064
+ cursor: pointer;
58065
+ }
58066
+
58067
+ @media (hover: hover) {
58068
+ .dsh-subagent-reset-link:hover:not(:disabled) {
58069
+ color: var(--dsw-alias-label-primary);
58070
+ }
58071
+ }
58072
+
58073
+ .dsh-subagent-reset-link:disabled {
58074
+ cursor: default;
58075
+ opacity: 0.5;
58076
+ }
58077
+
58078
+ .dsh-subagent-input {
58079
+ height: 34px;
58080
+ padding: 0 12px;
58081
+ border: 0.5px solid var(--dsw-alias-border-l4);
58082
+ border-radius: var(--dsw-radius-md, 8px);
58083
+ background: var(--dsw-alias-bg-layer-3);
58084
+ font: inherit;
58085
+ font-size: 13px;
58086
+ line-height: 1.5;
58087
+ font-variant-numeric: tabular-nums;
58088
+ color: var(--dsw-alias-label-primary);
58089
+ min-width: 0;
58090
+ box-sizing: border-box;
58091
+ }
58092
+
58093
+ .dsh-subagent-input:focus-visible {
58094
+ outline: none;
58095
+ border-color: var(--dsw-alias-state-business-primary);
58096
+ }
58097
+
58098
+ .dsh-subagent-input:disabled {
58099
+ color: var(--dsw-alias-label-tertiary);
58100
+ cursor: default;
58101
+ }
58102
+
58103
+ .dsh-subagent-input[aria-invalid='true'] {
58104
+ border-color: var(--dsw-alias-state-error-primary);
58105
+ }
58106
+
58107
+ .dsh-subagent-permission {
58108
+ display: grid;
58109
+ gap: 6px;
58110
+ padding: 12px 0;
58111
+ }
58112
+
58113
+ .dsh-subagent-toggle-row {
58114
+ display: flex;
58115
+ align-items: flex-start;
58116
+ justify-content: space-between;
58117
+ gap: 16px;
58118
+ font-size: 13px;
58119
+ line-height: 1.5;
58120
+ color: var(--dsw-alias-label-primary);
58121
+ }
58122
+
58123
+ .dsh-subagent-toggle-label {
58124
+ flex: 1;
58125
+ min-width: 0;
58126
+ }
58127
+
58128
+ .dsh-subagent-switch {
58129
+ box-sizing: border-box;
58130
+ position: relative;
58131
+ flex: 0 0 auto;
58132
+ width: 36px;
58133
+ height: 20px;
58134
+ padding: 2px;
58135
+ border: 0;
58136
+ border-radius: 999px;
58137
+ background: var(--dsw-alias-border-l3);
58138
+ cursor: pointer;
58139
+ }
58140
+
58141
+ .dsh-subagent-switch[aria-checked='true'] {
58142
+ background: var(--dsw-alias-brand-primary, #e06c3b);
58143
+ }
58144
+
58145
+ .dsh-subagent-switch:disabled {
58146
+ cursor: default;
58147
+ opacity: 0.5;
58148
+ }
58149
+
58150
+ .dsh-subagent-switch:focus-visible {
58151
+ outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
58152
+ outline-offset: 2px;
58153
+ }
58154
+
58155
+ .dsh-subagent-switch-thumb {
58156
+ display: block;
58157
+ width: 16px;
58158
+ height: 16px;
58159
+ border-radius: 50%;
58160
+ background: var(--dsw-alias-label-primary-foreground, #fff);
58161
+ transition: transform 120ms ease;
58162
+ }
58163
+
58164
+ .dsh-subagent-switch[aria-checked='false'] .dsh-subagent-switch-thumb {
58165
+ background: var(--dsw-alias-switch-thumb, #fff);
58166
+ }
58167
+
58168
+ .dsh-subagent-switch[aria-checked='true'] .dsh-subagent-switch-thumb {
58169
+ transform: translateX(16px);
58170
+ }
58171
+
58172
+ .dsh-subagent-selection {
58173
+ display: grid;
58174
+ gap: 12px;
58175
+ min-width: 0;
58176
+ }
58177
+
58178
+ .dsh-subagent-target-bar {
58179
+ display: grid;
58180
+ gap: 8px;
58181
+ padding: 12px;
58182
+ border: 0.5px solid var(--dsw-alias-border-l4);
58183
+ border-radius: var(--dsw-radius-lg, 10px);
58184
+ background: var(--dsw-alias-bg-layer-2, transparent);
58185
+ min-width: 0;
58186
+ }
58187
+
58188
+ .dsh-subagent-target-header {
58189
+ display: flex;
58190
+ align-items: center;
58191
+ justify-content: space-between;
58192
+ gap: 8px;
58193
+ min-width: 0;
58194
+ }
58195
+
58196
+ .dsh-subagent-target-label {
58197
+ font-size: 12px;
58198
+ font-weight: 500;
58199
+ line-height: 1.5;
58200
+ color: var(--dsw-alias-label-secondary);
58201
+ }
58202
+
58203
+ .dsh-subagent-select {
58204
+ height: 34px;
58205
+ width: 100%;
58206
+ padding: 0 10px;
58207
+ border: 0.5px solid var(--dsw-alias-border-l4);
58208
+ border-radius: var(--dsw-radius-md, 8px);
58209
+ background: var(--dsw-alias-bg-layer-3);
58210
+ color: var(--dsw-alias-label-primary);
58211
+ font: inherit;
58212
+ font-size: 13px;
58213
+ line-height: 1.5;
58214
+ box-sizing: border-box;
58215
+ cursor: pointer;
58216
+ }
58217
+
58218
+ .dsh-subagent-select option,
58219
+ .dsh-subagent-select optgroup {
58220
+ background: var(--dsw-alias-bg-layer-3, #1e1e1e);
58221
+ color: var(--dsw-alias-label-primary, #e5e5e5);
58222
+ }
58223
+
58224
+ .dsh-subagent-select:focus-visible {
58225
+ outline: none;
58226
+ border-color: var(--dsw-alias-state-business-primary);
58227
+ }
58228
+
58229
+ .dsh-subagent-select:disabled {
58230
+ color: var(--dsw-alias-label-tertiary);
58231
+ cursor: default;
58232
+ }
58233
+
58234
+ .dsh-subagent-chips {
58235
+ display: flex;
58236
+ flex-wrap: wrap;
58237
+ align-items: center;
58238
+ gap: 6px;
58239
+ min-width: 0;
58240
+ }
58241
+
58242
+ .dsh-subagent-chip {
58243
+ padding: 3px 10px;
58244
+ border: 0.5px solid var(--dsw-alias-border-l3);
58245
+ border-radius: 999px;
58246
+ background: var(--dsw-alias-bg-layer-3);
58247
+ color: var(--dsw-alias-label-secondary);
58248
+ font: inherit;
58249
+ font-size: 12px;
58250
+ line-height: 1.4;
58251
+ cursor: pointer;
58252
+ }
58253
+
58254
+ .dsh-subagent-chip[aria-pressed='true'] {
58255
+ border-color: var(--dsw-alias-brand-primary, #e06c3b);
58256
+ background: color-mix(in srgb, var(--dsw-alias-brand-primary, #e06c3b) 15%, transparent);
58257
+ color: var(--dsw-alias-label-primary);
58258
+ font-weight: 500;
58259
+ }
58260
+
58261
+ .dsh-subagent-chip:disabled {
58262
+ cursor: default;
58263
+ opacity: 0.5;
58264
+ }
58265
+
58266
+ .dsh-subagent-status {
58267
+ display: flex;
58268
+ flex-wrap: wrap;
58269
+ align-items: center;
58270
+ justify-content: space-between;
58271
+ gap: 8px;
58272
+ min-width: 0;
58273
+ }
58274
+
58275
+ .dsh-subagent-reset {
58276
+ padding: 3px 10px;
58277
+ border: 0.5px solid var(--dsw-alias-border-l4);
58278
+ border-radius: var(--dsw-radius-md, 8px);
58279
+ background: var(--dsw-alias-bg-layer-3);
58280
+ color: var(--dsw-alias-label-secondary);
58281
+ font: inherit;
58282
+ font-size: 12px;
58283
+ line-height: 1.4;
58284
+ cursor: pointer;
58285
+ }
58286
+
58287
+ @media (hover: hover) {
58288
+ .dsh-subagent-reset:hover:not(:disabled) {
58289
+ background: var(--dsw-alias-bg-layer-4);
58290
+ color: var(--dsw-alias-label-primary);
58291
+ }
58292
+ }
58293
+
58294
+ .dsh-subagent-reset:disabled {
58295
+ cursor: default;
58296
+ opacity: 0.5;
58297
+ }
58298
+
58299
+ .dsh-subagent-hint,
58300
+ .dsh-subagent-notice,
58301
+ .dsh-subagent-invalid {
58302
+ margin: 0;
58303
+ font-size: 12px;
58304
+ line-height: 1.5;
58305
+ }
58306
+
58307
+ .dsh-subagent-hint,
58308
+ .dsh-subagent-notice {
58309
+ color: var(--dsw-alias-label-tertiary);
58310
+ }
58311
+
58312
+ .dsh-subagent-invalid {
58313
+ color: var(--dsw-alias-state-error-primary, #e5534b);
58314
+ }
58315
+
58316
+ .dsh-subagent-catalog-error {
58317
+ display: flex;
58318
+ align-items: center;
58319
+ justify-content: space-between;
58320
+ gap: 12px;
58321
+ font-size: 12px;
58322
+ color: var(--dsw-alias-state-error-primary, #e5534b);
58323
+ }
58324
+
58325
+ .dsh-subagent-catalog-error button {
58326
+ border: 0;
58327
+ padding: 0;
58328
+ background: transparent;
58329
+ color: var(--dsw-alias-brand-primary, #e06c3b);
58330
+ font: inherit;
58331
+ cursor: pointer;
58332
+ }
58333
+
58334
+ .dsh-subagent-models {
58335
+ display: grid;
58336
+ align-content: start;
58337
+ gap: 6px;
58338
+ min-width: 0;
58339
+ min-height: 180px;
58340
+ max-height: clamp(220px, calc(100dvh - 620px), 440px);
58341
+ resize: vertical;
58342
+ margin: 0;
58343
+ padding: 10px;
58344
+ overflow: auto;
58345
+ border: 0.5px solid var(--dsw-alias-border-l4);
58346
+ border-radius: var(--dsw-radius-lg, 10px);
58347
+ }
58348
+
58349
+ .dsh-subagent-models > legend {
58350
+ padding: 0 4px;
58351
+ font-size: 12px;
58352
+ color: var(--dsw-alias-label-secondary);
58353
+ }
58354
+
58355
+ .dsh-subagent-group {
58356
+ display: grid;
58357
+ gap: 6px;
58358
+ min-width: 0;
58359
+ }
58360
+
58361
+ .dsh-subagent-group + .dsh-subagent-group {
58362
+ margin-top: 4px;
58363
+ padding-top: 10px;
58364
+ border-top: 0.5px solid var(--dsw-alias-border-l3);
58365
+ }
58366
+
58367
+ .dsh-subagent-group-name {
58368
+ padding: 0 6px;
58369
+ font-size: 11px;
58370
+ font-weight: 500;
58371
+ color: var(--dsw-alias-label-tertiary);
58372
+ }
58373
+
58374
+ .dsh-subagent-model {
58375
+ display: grid;
58376
+ grid-template-columns: auto minmax(0, 1fr) auto;
58377
+ align-items: center;
58378
+ gap: 8px;
58379
+ min-width: 0;
58380
+ padding: 6px;
58381
+ border-radius: var(--dsw-radius-md, 8px);
58382
+ cursor: pointer;
58383
+ }
58384
+
58385
+ @media (hover: hover) {
58386
+ .dsh-subagent-model:hover {
58387
+ background: var(--dsw-alias-bg-layer-4);
58388
+ }
58389
+ }
58390
+
58391
+ .dsh-subagent-model-name,
58392
+ .dsh-subagent-model-route {
58393
+ display: block;
58394
+ overflow: hidden;
58395
+ text-overflow: ellipsis;
58396
+ white-space: nowrap;
58397
+ }
58398
+
58399
+ .dsh-subagent-model-name {
58400
+ font-size: 13px;
58401
+ color: var(--dsw-alias-label-primary);
58402
+ }
58403
+
58404
+ .dsh-subagent-model-route {
58405
+ margin-top: 2px;
58406
+ font-size: 11px;
58407
+ color: var(--dsw-alias-label-tertiary);
58408
+ }
58409
+
58410
+ .dsh-subagent-model-unavailable {
58411
+ font-size: 11px;
58412
+ color: var(--dsw-alias-label-tertiary);
58413
+ white-space: nowrap;
58414
+ }
58415
+
58416
+ .dsh-subagent-footer {
58417
+ display: flex;
58418
+ align-items: center;
58419
+ gap: 8px;
58420
+ padding-top: 16px;
58421
+ }
58422
+
58423
+ .dsh-subagent-save {
58424
+ appearance: none;
58425
+ border: 1px solid transparent;
58426
+ border-radius: var(--dsw-radius-md, 8px);
58427
+ padding: 5px 14px;
58428
+ font: inherit;
58429
+ font-size: 13px;
58430
+ line-height: 1.5;
58431
+ cursor: pointer;
58432
+ background: var(--dsw-alias-label-primary);
58433
+ color: var(--dsw-alias-bg-layer-3);
58434
+ }
58435
+
58436
+ .dsh-subagent-save:disabled {
58437
+ opacity: 0.4;
58438
+ cursor: default;
58439
+ }
58440
+
58441
+ .dsh-subagent-save:focus-visible {
58442
+ outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
58443
+ outline-offset: 1px;
58444
+ }
58445
+
58446
+ .dsh-subagent-discard {
58447
+ appearance: none;
58448
+ border: 0.5px solid var(--dsw-alias-border-l4);
58449
+ border-radius: var(--dsw-radius-md, 8px);
58450
+ padding: 5px 12px;
58451
+ font: inherit;
58452
+ font-size: 13px;
58453
+ line-height: 1.5;
58454
+ cursor: pointer;
58455
+ background: transparent;
58456
+ color: var(--dsw-alias-label-secondary);
58457
+ }
58458
+
58459
+ .dsh-subagent-discard:disabled {
58460
+ opacity: 0.4;
58461
+ cursor: default;
58462
+ }
58463
+
58464
+ .dsh-subagent-failed {
58465
+ flex: 1;
58466
+ min-width: 0;
58467
+ margin: 0;
58468
+ font-size: 12px;
58469
+ line-height: 1.5;
58470
+ color: var(--dsw-alias-label-error, var(--dsw-alias-state-error-primary, #e5534b));
58471
+ }
58472
+ `;
58473
+ /**
58474
+ * 安装本卡片的样式表。
58475
+ * @returns 卸载函数(样式表由文档持有,这里不做删除)。
58476
+ */
58477
+ function installSubagentStyles() {
58478
+ return installPluginStyle(STYLE_NAME, SUBAGENT_CSS);
58479
+ }
58480
+ //#endregion
56285
58481
  //#region src/client/index.tsx
56286
58482
  const inject = [
56287
58483
  "slots",
@@ -56295,70 +58491,75 @@ window.__ModuleLoader__.load({
56295
58491
  function apply(ctx) {
56296
58492
  installLineLocale(ctx.locale);
56297
58493
  installRussianLocale(ctx);
56298
- ctx.effect(() => ctx.locale.register(NS, dictionaries$1), "dsh-chatgpt-subscription: dictionaries");
58494
+ ctx.effect(() => ctx.locale.register(NS, dictionaries$2), "dsh-chatgpt-subscription: dictionaries");
56299
58495
  ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
56300
58496
  ctx.effect(() => {
56301
58497
  installHubStyles();
56302
58498
  installModelChecklistStyles();
56303
58499
  return () => {};
56304
58500
  }, "dsh-chatgpt-subscription: hub styles");
56305
- ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$13), "dsh-antigravity: dictionaries");
58501
+ ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$14), "dsh-antigravity: dictionaries");
56306
58502
  ctx.effect(() => {
56307
58503
  installAntigravityStyles();
56308
58504
  return () => {};
56309
58505
  }, "dsh-antigravity: styles");
56310
- ctx.effect(() => ctx.locale.register(NS_CLAUDE, dictionaries$8), "dsh-claude: dictionaries");
58506
+ ctx.effect(() => ctx.locale.register(NS_CLAUDE, dictionaries$9), "dsh-claude: dictionaries");
56311
58507
  ctx.effect(() => {
56312
58508
  installClaudeStyles();
56313
58509
  return () => {};
56314
58510
  }, "dsh-claude: styles");
56315
- ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$12), "dsh-command-code: dictionaries");
56316
- ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$11), "dsh-kimi-code: dictionaries");
58511
+ ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$13), "dsh-command-code: dictionaries");
58512
+ ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$12), "dsh-kimi-code: dictionaries");
56317
58513
  ctx.effect(() => {
56318
58514
  installKimiCodeStyles();
56319
58515
  return () => {};
56320
58516
  }, "dsh-kimi-code: styles");
56321
- ctx.effect(() => ctx.locale.register(NS_MINIMAX_CODE, dictionaries$10), "dsh-minimax-code: dictionaries");
58517
+ ctx.effect(() => ctx.locale.register(NS_MINIMAX_CODE, dictionaries$11), "dsh-minimax-code: dictionaries");
56322
58518
  ctx.effect(() => {
56323
58519
  installMinimaxCodeStyles();
56324
58520
  return () => {};
56325
58521
  }, "dsh-minimax-code: styles");
56326
- ctx.effect(() => ctx.locale.register(NS_GLM_CODING_PLAN, dictionaries$9), "dsh-glm-coding-plan: dictionaries");
58522
+ ctx.effect(() => ctx.locale.register(NS_GLM_CODING_PLAN, dictionaries$10), "dsh-glm-coding-plan: dictionaries");
56327
58523
  ctx.effect(() => {
56328
58524
  installGlmCodingPlanStyles();
56329
58525
  return () => {};
56330
58526
  }, "dsh-glm-coding-plan: styles");
56331
- ctx.effect(() => ctx.locale.register(NS_OLLAMA, dictionaries$7), "dsh-ollama: dictionaries");
56332
- ctx.effect(() => ctx.locale.register(NS_PROGRESS_UPDATES, dictionaries), "dsh-progress-updates: dictionaries");
58527
+ ctx.effect(() => ctx.locale.register(NS_OLLAMA, dictionaries$8), "dsh-ollama: dictionaries");
58528
+ ctx.effect(() => ctx.locale.register(NS_PROGRESS_UPDATES, dictionaries$1), "dsh-progress-updates: dictionaries");
56333
58529
  ctx.effect(() => {
56334
58530
  installProgressUpdatesStyles();
56335
58531
  return () => {};
56336
58532
  }, "dsh-progress-updates: styles");
56337
- ctx.effect(() => ctx.locale.register(NS_STEP_CODE, dictionaries$6), "dsh-step-code: dictionaries");
58533
+ ctx.effect(() => ctx.locale.register(NS_STEP_CODE, dictionaries$7), "dsh-step-code: dictionaries");
56338
58534
  ctx.effect(() => {
56339
58535
  installStepCodeStyles();
56340
58536
  return () => {};
56341
58537
  }, "dsh-step-code: styles");
56342
- ctx.effect(() => ctx.locale.register(NS_CLINE_PASS, dictionaries$5), "dsh-cline-pass: dictionaries");
58538
+ ctx.effect(() => ctx.locale.register(NS_CLINE_PASS, dictionaries$6), "dsh-cline-pass: dictionaries");
56343
58539
  ctx.effect(() => {
56344
58540
  installClinePassStyles();
56345
58541
  return () => {};
56346
58542
  }, "dsh-cline-pass: styles");
56347
- ctx.effect(() => ctx.locale.register(NS_QODER, dictionaries$4), "dsh-qoder: dictionaries");
58543
+ ctx.effect(() => ctx.locale.register(NS_QODER, dictionaries$5), "dsh-qoder: dictionaries");
56348
58544
  ctx.effect(() => {
56349
58545
  installQoderStyles();
56350
58546
  return () => {};
56351
58547
  }, "dsh-qoder: styles");
56352
- ctx.effect(() => ctx.locale.register(NS_OPENDESIGN, dictionaries$3), "dsh-opendesign: dictionaries");
58548
+ ctx.effect(() => ctx.locale.register(NS_OPENDESIGN, dictionaries$4), "dsh-opendesign: dictionaries");
56353
58549
  ctx.effect(() => {
56354
58550
  installOpenDesignStyles();
56355
58551
  return () => {};
56356
58552
  }, "dsh-opendesign: styles");
56357
- ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$2), "dsh-workbuddy: dictionaries");
58553
+ ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$3), "dsh-workbuddy: dictionaries");
56358
58554
  ctx.effect(() => {
56359
58555
  installWorkBuddyStyles();
56360
58556
  return () => {};
56361
58557
  }, "dsh-workbuddy: styles");
58558
+ ctx.effect(() => ctx.locale.register(NS_SUBAGENT, dictionaries), "dsh-subagent-settings: dictionaries");
58559
+ ctx.effect(() => {
58560
+ installSubagentStyles();
58561
+ return () => {};
58562
+ }, "dsh-subagent-settings: styles");
56362
58563
  ctx.effect(() => {
56363
58564
  installPoolStyles();
56364
58565
  return () => {};
@@ -56491,6 +58692,7 @@ window.__ModuleLoader__.load({
56491
58692
  })
56492
58693
  }, MinimaxVideoToolView));
56493
58694
  installVideoDocumentPreview(ctx);
58695
+ installSubagentSettingsCard(ctx);
56494
58696
  installProgressUpdatesClient(ctx);
56495
58697
  ctx.effect(() => installVideoCommand(ctx), "dsh-minimax-code: /video command");
56496
58698
  const VideoCommandHost = createVideoCommandHost(ctx);