dsh-composer-ux 0.4.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -38,12 +38,73 @@ __export(client_exports, {
38
38
  module.exports = __toCommonJS(client_exports);
39
39
  var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
40
40
 
41
+ // src/terminal/discover.ts
42
+ function normalizePath(value) {
43
+ const trimmed = value.trim().replace(/^"|"$/g, "");
44
+ const slashed = trimmed.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
45
+ return slashed.length > 1 ? slashed.replace(/\/+$/, "") : slashed;
46
+ }
47
+
48
+ // src/terminal/contracts.ts
49
+ var TERMINAL_MODE_FIELD = "terminalMode";
50
+ var TERMINAL_BASH_PATH_FIELD = "terminalBashPath";
51
+ var TERMINAL_CANDIDATES_FIELD = "terminalCandidates";
52
+ var TERMINAL_STATUS_FIELD = "terminalStatus";
53
+ var TERMINAL_EFFECTIVE_FIELD = "terminalEffective";
54
+ var TERMINAL_API_PATH = "/composer-ux/terminal";
55
+ var TERMINAL_MODES = [
56
+ {
57
+ id: "auto",
58
+ label: "\u81EA\u52A8",
59
+ hint: "\u63A2\u6D4B\u5230 Git Bash \u5C31\u7528\u5B83\uFF08\u627E\u4E0D\u5230\u5219\u4FDD\u6301 PowerShell\uFF09\uFF1B\u5F00\u7BB1\u5373\u7528\uFF0C\u4E0D\u7528\u624B\u586B\u8DEF\u5F84"
60
+ },
61
+ {
62
+ id: "gitbash",
63
+ label: "Git Bash",
64
+ hint: "\u5F3A\u5236\u6362\u6210 Git Bash\uFF1B\u6CA1\u63A2\u6D4B\u5230\u5C31\u56DE\u843D PowerShell\uFF0C\u5E76\u5728\u72B6\u6001\u884C\u5199\u660E\u539F\u56E0"
65
+ },
66
+ {
67
+ id: "pwsh",
68
+ label: "PowerShell",
69
+ hint: "\u4FDD\u6301 DSH \u9ED8\u8BA4\uFF08\u672C\u63D2\u4EF6\u5B8C\u5168\u4E0D\u78B0\u7EC8\u7AEF\u5DE5\u5177\u9762\uFF09"
70
+ }
71
+ ];
72
+ var DEFAULT_TERMINAL_MODE = "auto";
73
+ function terminalModeFrom(value) {
74
+ return value === "auto" || value === "gitbash" || value === "pwsh" ? value : DEFAULT_TERMINAL_MODE;
75
+ }
76
+ function sanitizeTerminalCandidates(value) {
77
+ if (!Array.isArray(value)) return [];
78
+ const out = [];
79
+ const seen = /* @__PURE__ */ new Set();
80
+ for (const item of value) {
81
+ if (out.length >= 20) break;
82
+ if (typeof item !== "object" || item === null) continue;
83
+ const row2 = item;
84
+ const path = typeof row2.path === "string" ? normalizePath(row2.path).slice(0, 400) : "";
85
+ if (path === "") continue;
86
+ const key = path.toLowerCase();
87
+ if (seen.has(key)) continue;
88
+ seen.add(key);
89
+ const label = typeof row2.label === "string" ? row2.label.slice(0, 40) : "";
90
+ const kind = row2.kind === "git" || row2.kind === "msys2" || row2.kind === "cygwin" || row2.kind === "niubash" || row2.kind === "path" ? row2.kind : "path";
91
+ out.push({ path, label: label === "" ? "PATH" : label, kind, explicit: row2.explicit === true });
92
+ }
93
+ return out;
94
+ }
95
+
41
96
  // src/settings-contract.ts
42
97
  var NAMESPACE = "composer-ux";
98
+ var REPO_URL = "https://github.com/fangwen9527/dsh-composer-ux";
99
+ var RESTART_API_PATH = "/composer-ux/restart";
43
100
  var ENABLED_FIELD = "enabled";
101
+ var KEYS_ENABLED_FIELD = "keysEnabled";
102
+ var MENU_ENABLED_FIELD = "menuEnabled";
103
+ var QUICK_ENABLED_FIELD = "quickEnabled";
104
+ var PANEL_ENABLED_FIELD = "panelEnabled";
105
+ var TERMINAL_ENABLED_FIELD = "terminalEnabled";
44
106
  var SEND_KEY_FIELD = "sendKey";
45
107
  var NEWLINE_KEY_FIELD = "newlineKey";
46
- var PANEL_SCROLL_FIELD = "panelScroll";
47
108
  var PANEL_RESIZE_FIELD = "panelResize";
48
109
  var PANEL_WIDTH_FIELD = "panelWidth";
49
110
  var PANEL_HEIGHT_FIELD = "panelHeight";
@@ -103,11 +164,21 @@ function insertModeOf(prompt) {
103
164
  return "never";
104
165
  }
105
166
  var OPTIMIZER_TIERS = [
106
- { id: "basic", label: "\u666E\u901A", hint: "\u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\uFF1A\u75C5\u53E5\u3001\u9519\u522B\u5B57\u3001\u6307\u4EE3\u4E0E\u542B\u7CCA\u8BCD\uFF0C\u4E0D\u65B0\u589E\u4EFB\u4F55\u9700\u6C42\uFF0C\u7BC7\u5E45\u4E0E\u539F\u6587\u76F8\u5F53\u3002" },
107
- { id: "advanced", label: "\u9AD8\u7EA7", hint: "\u5728\u4E0D\u52A8\u76EE\u6807\u7684\u524D\u63D0\u4E0B\uFF0C\u628A\u300C\u4F60\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3\u300D\u7684\u5FC5\u8981\u8981\u6C42\u8865\u6210\u5BF9 AI \u7684\u8981\u6C42\uFF0C\u8BA9\u5B83\u4E00\u6B21\u505A\u5BF9\u3002" },
108
- { id: "extreme", label: "\u6781\u7AEF", hint: "\u6309\u590D\u6742\u4EFB\u52A1\u5904\u7406\uFF1A\u56FA\u5316\u547D\u4EE4\u7ED3\u6784 + \u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212 + 2~4 \u79CD\u60C5\u51B5\u7684\u9884\u6848\u3002" }
167
+ { id: "basic", label: "\u666E\u901A", hint: "\u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\uFF1A\u75C5\u53E5\u3001\u9519\u522B\u5B57\u3001\u6307\u4EE3\u4E0E\u542B\u7CCA\u8BCD\uFF0C\u4E0D\u65B0\u589E\u4EFB\u4F55\u9700\u6C42\uFF0C\u7BC7\u5E45\u7EA6\u4E3A\u539F\u6587 1.4 \u500D\u3002" },
168
+ { id: "advanced", label: "\u9AD8\u7EA7", hint: "\u5728\u4E0D\u52A8\u76EE\u6807\u7684\u524D\u63D0\u4E0B\uFF0C\u628A\u300C\u4F60\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3\u300D\u7684\u5FC5\u8981\u8981\u6C42\u8865\u6210\u5BF9 AI \u7684\u8981\u6C42\uFF0C\u6BCF\u6761\u90FD\u8981\u6307\u56DE\u4F60\u539F\u8BDD\u91CC\u7684\u67D0\u4E00\u53E5\u3002" },
169
+ { id: "extreme", label: "\u6781\u7AEF", hint: "\u6309\u590D\u6742\u4EFB\u52A1\u5904\u7406\uFF1A\u5728\u4E0A\u9762\u57FA\u7840\u4E0A\u518D\u52A0\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\u4E0E 2~4 \u79CD\u60C5\u51B5\u7684\u9884\u6848\u3002" }
109
170
  ];
110
171
  var DEFAULT_OPTIMIZER_TIER = "advanced";
172
+ var OPTIMIZER_PROMPT_FIELDS = {
173
+ basic: "optimizerPromptBasic",
174
+ advanced: "optimizerPromptAdvanced",
175
+ extreme: "optimizerPromptExtreme"
176
+ };
177
+ var OPTIMIZER_PROMPT_FIELD_LIST = OPTIMIZER_TIERS.map((item) => OPTIMIZER_PROMPT_FIELDS[item.id]);
178
+ var OPTIMIZER_PROMPT_MAX = 2e4;
179
+ function optimizerPromptFieldOf(tier) {
180
+ return OPTIMIZER_PROMPT_FIELDS[tier] ?? OPTIMIZER_PROMPT_FIELDS[DEFAULT_OPTIMIZER_TIER];
181
+ }
111
182
  var DEFAULT_QUICK_PROMPTS = [
112
183
  { id: "builtin-1", label: "\u4E00\u95EE\u4E00\u7B54", prompt: "\u4F60\u4E0D\u61C2\u7684\u5C31\u95EE\u6211\uFF0C\u4E00\u95EE\u4E00\u7B54\uFF1B\u540C\u65F6\u8BF4\u6E05\u695A\u4F60\u4E3A\u4EC0\u4E48\u8981\u95EE\u8BE5\u95EE\u9898\uFF1B\u76F4\u5230\u4F60\u5BF9\u6211\u7684\u76EE\u6807\u6709\u660E\u786E\u8BA4\u77E5\u540E\u518D\u5F00\u59CB\u5E72\u6D3B\u3002", always: false, firstOnly: false },
113
184
  { id: "builtin-2", label: "\u4EA4\u63A5\u6587\u6863", prompt: "\u628A\u8FD9\u6B21\u4EFB\u52A1\u3001\u5DF2\u5B8C\u6210\u5185\u5BB9\u3001\u5F53\u524D\u5361\u70B9\u3001\u4E0B\u4E00\u6B65\u8BA1\u5212\u3001\u8E29\u8FC7\u7684\u5751\uFF0C\u6574\u7406\u6210\u4E00\u4EFD\u4EA4\u63A5\u6587\u6863\uFF0C\u5199\u7ED9\u65B0\u4F1A\u8BDD\u770B\u3002", always: false, firstOnly: false },
@@ -227,7 +298,14 @@ var DEFAULT_HEADER_NAME = "x-opencode-session";
227
298
  var HEADER_VALUE_MAX = 200;
228
299
  var HEADER_NAME_MAX = 64;
229
300
  var DEFAULT_SETTINGS = {
301
+ // 总开关默认开:它只是总闸,真正"要不要用这一栏"由下面五个开关决定(默认关)。
230
302
  enabled: true,
303
+ // 五栏默认关(老文档由 sectionEnabledOf 迁移成"碰过就开")。
304
+ keysEnabled: false,
305
+ menuEnabled: false,
306
+ quickEnabled: false,
307
+ panelEnabled: false,
308
+ terminalEnabled: false,
231
309
  sendKey: "Enter",
232
310
  newlineKey: "Shift+Enter",
233
311
  menuUndo: true,
@@ -238,7 +316,6 @@ var DEFAULT_SETTINGS = {
238
316
  menuDelete: true,
239
317
  menuSelectAll: true,
240
318
  menuMode: "official",
241
- panelScroll: true,
242
319
  panelResize: true,
243
320
  headerEnabled: false,
244
321
  headerName: DEFAULT_HEADER_NAME,
@@ -248,8 +325,28 @@ var DEFAULT_SETTINGS = {
248
325
  headerAppliedValue: "",
249
326
  headerStatus: "",
250
327
  quickPrompts: DEFAULT_QUICK_PROMPTS,
251
- optimizerTier: DEFAULT_OPTIMIZER_TIER
328
+ optimizerTier: DEFAULT_OPTIMIZER_TIER,
329
+ // 空串 = 用内置提示词。默认必须是空串:它同时就是「恢复内置」要写回去的值。
330
+ optimizerPromptBasic: "",
331
+ optimizerPromptAdvanced: "",
332
+ optimizerPromptExtreme: "",
333
+ terminalMode: DEFAULT_TERMINAL_MODE,
334
+ terminalBashPath: "",
335
+ terminalCandidates: [],
336
+ terminalStatus: "",
337
+ terminalEffective: ""
252
338
  };
339
+ function activeSections(settings) {
340
+ const on = settings.enabled;
341
+ return {
342
+ keys: on && settings.keysEnabled,
343
+ menu: on && settings.menuEnabled,
344
+ quick: on && settings.quickEnabled,
345
+ panel: on && settings.panelEnabled,
346
+ header: on && settings.headerEnabled,
347
+ terminal: on && settings.terminalEnabled
348
+ };
349
+ }
253
350
  var SEND_PRESETS = ["Enter", "Ctrl+Enter", "Alt+Enter", "Shift+Enter"];
254
351
  var NEWLINE_PRESETS = ["Shift+Enter", "Enter", "Ctrl+Enter", "Alt+Enter"];
255
352
  var MENU_ITEMS = [
@@ -270,6 +367,25 @@ function newSessionId() {
270
367
  ).join("");
271
368
  return `${hex(8)}-${hex(4)}-4${hex(3)}-a${hex(3)}-${hex(12)}`;
272
369
  }
370
+ var SECTION_SIGNALS = {
371
+ [KEYS_ENABLED_FIELD]: (source) => touched(source, SEND_KEY_FIELD, DEFAULT_SETTINGS.sendKey) || touched(source, NEWLINE_KEY_FIELD, DEFAULT_SETTINGS.newlineKey),
372
+ // 「官方」=本插件不介入,等价于关;所以只有选过另外两档才算"碰过"。
373
+ // (`menuModeFrom` 对"两个键都没有"给的就是 'official',天然满足"缺省 = 默认"。)
374
+ [MENU_ENABLED_FIELD]: (source) => menuModeFrom(source[MENU_MODE_FIELD], source[MENU_NATIVE_FIELD]) !== "official",
375
+ [QUICK_ENABLED_FIELD]: (source) => Array.isArray(source[QUICK_PROMPTS_FIELD]) && source[QUICK_PROMPTS_FIELD].length !== DEFAULT_QUICK_PROMPTS.length || touched(source, OPTIMIZER_TIER_FIELD, DEFAULT_OPTIMIZER_TIER),
376
+ [PANEL_ENABLED_FIELD]: (source) => touched(source, PANEL_RESIZE_FIELD, true) || source[PANEL_WIDTH_FIELD] !== void 0 || source[PANEL_HEIGHT_FIELD] !== void 0,
377
+ [TERMINAL_ENABLED_FIELD]: (source) => touched(source, TERMINAL_MODE_FIELD, DEFAULT_TERMINAL_MODE) || touched(source, TERMINAL_BASH_PATH_FIELD, "")
378
+ };
379
+ function touched(source, field, untouched) {
380
+ const value = source[field];
381
+ return value !== void 0 && value !== untouched;
382
+ }
383
+ function sectionEnabledOf(field, source) {
384
+ const explicit = source[field];
385
+ if (typeof explicit === "boolean") return explicit;
386
+ const signal = SECTION_SIGNALS[field];
387
+ return signal === void 0 ? false : signal(source);
388
+ }
273
389
  function sanitizeSettings(value) {
274
390
  const source = typeof value === "object" && value !== null ? value : {};
275
391
  const asString = (field) => {
@@ -280,6 +396,10 @@ function sanitizeSettings(value) {
280
396
  const v = source[field];
281
397
  return typeof v === "string" && v.length <= max ? v : "";
282
398
  };
399
+ const asPrompt = (field, max) => {
400
+ const v = source[field];
401
+ return typeof v === "string" ? v.slice(0, max) : "";
402
+ };
283
403
  const asBool = (field) => {
284
404
  const v = source[field];
285
405
  return typeof v === "boolean" ? v : DEFAULT_SETTINGS[field];
@@ -319,6 +439,12 @@ function sanitizeSettings(value) {
319
439
  };
320
440
  return {
321
441
  enabled: asBool(ENABLED_FIELD),
442
+ // 五栏开关:显式写过听它的,否则按"用户碰过没"迁移(见 sectionEnabledOf)。
443
+ keysEnabled: sectionEnabledOf(KEYS_ENABLED_FIELD, source),
444
+ menuEnabled: sectionEnabledOf(MENU_ENABLED_FIELD, source),
445
+ quickEnabled: sectionEnabledOf(QUICK_ENABLED_FIELD, source),
446
+ panelEnabled: sectionEnabledOf(PANEL_ENABLED_FIELD, source),
447
+ terminalEnabled: sectionEnabledOf(TERMINAL_ENABLED_FIELD, source),
322
448
  sendKey: asString(SEND_KEY_FIELD),
323
449
  newlineKey: asString(NEWLINE_KEY_FIELD),
324
450
  menuUndo: asBool("menuUndo"),
@@ -329,7 +455,6 @@ function sanitizeSettings(value) {
329
455
  menuDelete: asBool("menuDelete"),
330
456
  menuSelectAll: asBool("menuSelectAll"),
331
457
  menuMode: menuModeFrom(source[MENU_MODE_FIELD], source[MENU_NATIVE_FIELD]),
332
- panelScroll: asBool(PANEL_SCROLL_FIELD),
333
458
  panelResize: asBool(PANEL_RESIZE_FIELD),
334
459
  panelWidth: asSize(PANEL_WIDTH_FIELD),
335
460
  panelHeight: asSize(PANEL_HEIGHT_FIELD),
@@ -343,7 +468,17 @@ function sanitizeSettings(value) {
343
468
  headerAppliedValue: asText(HEADER_APPLIED_VALUE_FIELD, HEADER_VALUE_MAX),
344
469
  headerStatus: asText(HEADER_STATUS_FIELD, HEADER_VALUE_MAX),
345
470
  quickPrompts: asQuickPrompts(),
346
- optimizerTier: asTier()
471
+ optimizerTier: asTier(),
472
+ optimizerPromptBasic: asPrompt(OPTIMIZER_PROMPT_FIELDS.basic, OPTIMIZER_PROMPT_MAX),
473
+ optimizerPromptAdvanced: asPrompt(OPTIMIZER_PROMPT_FIELDS.advanced, OPTIMIZER_PROMPT_MAX),
474
+ optimizerPromptExtreme: asPrompt(OPTIMIZER_PROMPT_FIELDS.extreme, OPTIMIZER_PROMPT_MAX),
475
+ terminalMode: terminalModeFrom(source[TERMINAL_MODE_FIELD]),
476
+ // 路径只做长度与归一化收窄,不在这里判"存不存在"——那是宿主半的探测结论,
477
+ // 由状态行告诉用户(用户看得见自己填了什么,比悄悄清空好)。
478
+ terminalBashPath: asText(TERMINAL_BASH_PATH_FIELD, 400),
479
+ terminalCandidates: sanitizeTerminalCandidates(source[TERMINAL_CANDIDATES_FIELD]),
480
+ terminalStatus: asText(TERMINAL_STATUS_FIELD, 400),
481
+ terminalEffective: asText(TERMINAL_EFFECTIVE_FIELD, 16)
347
482
  };
348
483
  }
349
484
 
@@ -692,6 +827,24 @@ function sendButtonOf(target) {
692
827
  if (last.querySelector("svg path") === null) return null;
693
828
  return last;
694
829
  }
830
+ function droppedOf(value) {
831
+ if (!Array.isArray(value)) return [];
832
+ const out = [];
833
+ for (const entry of value) {
834
+ if (typeof entry !== "object" || entry === null) continue;
835
+ const row2 = entry;
836
+ out.push({
837
+ id: typeof row2.id === "string" ? row2.id : "",
838
+ kind: typeof row2.kind === "string" ? row2.kind : "",
839
+ reason: typeof row2.reason === "string" ? row2.reason : ""
840
+ });
841
+ }
842
+ return out;
843
+ }
844
+ function warningsOf(value) {
845
+ if (!Array.isArray(value)) return [];
846
+ return value.filter((entry) => typeof entry === "string");
847
+ }
695
848
  async function optimizeDraft(text, tier) {
696
849
  const body = text.trim();
697
850
  if (body === "") return { ok: false, error: "\u8F93\u5165\u6846\u662F\u7A7A\u7684\uFF0C\u5148\u5199\u70B9\u4EC0\u4E48\u518D\u4F18\u5316" };
@@ -715,14 +868,26 @@ async function optimizeDraft(text, tier) {
715
868
  return { ok: false, error: "\u5BBF\u4E3B\u534A\u8FD4\u56DE\u7684\u4E0D\u662F JSON" };
716
869
  }
717
870
  const record = typeof payload === "object" && payload !== null ? payload : {};
871
+ const retried = record.retried === true;
718
872
  if (record.ok !== true) {
719
873
  const message = typeof record.error === "string" && record.error !== "" ? record.error : "\u4F18\u5316\u5931\u8D25";
720
- return { ok: false, error: message };
874
+ return { ok: false, error: message, retried };
721
875
  }
722
876
  const optimized = typeof record.text === "string" ? record.text.trim() : "";
723
- if (optimized === "") return { ok: false, error: "\u6A21\u578B\u6CA1\u6709\u4EA7\u51FA\u4EFB\u4F55\u5185\u5BB9" };
877
+ if (optimized === "") return { ok: false, error: "\u6A21\u578B\u6CA1\u6709\u4EA7\u51FA\u4EFB\u4F55\u5185\u5BB9", retried };
724
878
  const route = `${String(record.provider ?? "")}/${String(record.model ?? "")}`;
725
- return { ok: true, text: optimized, route };
879
+ return {
880
+ ok: true,
881
+ text: optimized,
882
+ route,
883
+ itemCount: typeof record.itemCount === "number" ? record.itemCount : 0,
884
+ dropped: droppedOf(record.dropped),
885
+ warnings: warningsOf(record.warnings),
886
+ fallback: record.fallback === true,
887
+ retried,
888
+ promptSource: typeof record.promptSource === "string" ? record.promptSource : "",
889
+ rewrittenChars: typeof record.rewrittenChars === "number" ? record.rewrittenChars : 0
890
+ };
726
891
  }
727
892
 
728
893
  // src/client/interceptors.ts
@@ -765,6 +930,7 @@ function composing(event) {
765
930
  function installInterceptors(deps) {
766
931
  const onKeyDown = (event) => {
767
932
  if (replaying) return;
933
+ if (!activeSections(deps.settings()).keys) return;
768
934
  const root = findComposerRoot(event.target);
769
935
  if (root === null) return;
770
936
  if (composing(event)) return;
@@ -788,7 +954,9 @@ function installInterceptors(deps) {
788
954
  const onContextMenu = (event) => {
789
955
  const root = findComposerRoot(event.target);
790
956
  if (root === null) return;
791
- const mode = deps.settings().menuMode;
957
+ const settings = deps.settings();
958
+ if (!activeSections(settings).menu) return;
959
+ const mode = settings.menuMode;
792
960
  if (mode === "official") return;
793
961
  if (mode === "browser") {
794
962
  if (deps.menuOpen()) deps.setMenu(null);
@@ -965,29 +1133,6 @@ var RESIZE_OUTLINE_STYLE = {
965
1133
  border: "1px solid rgba(127, 127, 137, .28)",
966
1134
  pointerEvents: "none"
967
1135
  };
968
- var PANEL_CSS = `
969
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) { min-height: 320px; }
970
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) > nav {
971
- min-height: 0;
972
- }
973
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) > nav > div:last-child {
974
- flex: 1 1 auto;
975
- min-height: 0;
976
- overflow-y: auto;
977
- overscroll-behavior: contain;
978
- scrollbar-width: thin;
979
- }
980
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) > nav > div:last-child::-webkit-scrollbar {
981
- width: 8px;
982
- }
983
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) > nav > div:last-child::-webkit-scrollbar-thumb {
984
- background: var(--dsh-scrollbar-thumb, var(--dsw-alias-scrollbar-bg-l2));
985
- border-radius: 8px;
986
- }
987
- html.dsh-ux-panel-scroll [role="dialog"][aria-modal="true"]:has(> nav) > nav > div:last-child::-webkit-scrollbar-thumb:hover {
988
- background: var(--dsh-scrollbar-thumb-hover, var(--dsw-alias-scrollbar-hover-l2));
989
- }
990
- `;
991
1136
  var RESIZE_CSS = `
992
1137
  .${RESIZE_LAYER_CLASS} { position: absolute; inset: 0; pointer-events: none; }
993
1138
  .${RESIZE_EDGE_CLASS}, .${RESIZE_GRIP_CLASS} {
@@ -1009,21 +1154,13 @@ var RESIZE_CSS = `
1009
1154
  }
1010
1155
  .${RESIZE_GRIP_CLASS}:hover { color: rgba(127, 127, 137, .95); background: rgba(127, 127, 137, .16); }
1011
1156
  `;
1012
- function installPanelStyle(settings, subscribe) {
1157
+ function installPanelResizeStyle() {
1013
1158
  const tag = document.createElement("style");
1014
1159
  tag.dataset.plugin = "dsh-composer-ux-panel";
1015
- tag.textContent = `${PANEL_CSS}
1016
- ${RESIZE_CSS}`;
1160
+ tag.textContent = RESIZE_CSS;
1017
1161
  document.head.appendChild(tag);
1018
- const applyClass = () => {
1019
- document.documentElement.classList.toggle("dsh-ux-panel-scroll", settings());
1020
- };
1021
- applyClass();
1022
- const unsubscribe = subscribe(applyClass);
1023
1162
  return () => {
1024
- unsubscribe();
1025
1163
  tag.remove();
1026
- document.documentElement.classList.remove("dsh-ux-panel-scroll");
1027
1164
  };
1028
1165
  }
1029
1166
  function findSettingsPanel() {
@@ -1053,7 +1190,8 @@ var CARD_CSS = `
1053
1190
  .dsh-ux-cardHeader {
1054
1191
  appearance: none;
1055
1192
  box-sizing: border-box;
1056
- width: 100%;
1193
+ flex: 1;
1194
+ min-width: 0;
1057
1195
  font: inherit;
1058
1196
  color: inherit;
1059
1197
  text-align: left;
@@ -1070,6 +1208,35 @@ var CARD_CSS = `
1070
1208
  outline: 2px solid var(--dsw-alias-brand-primary);
1071
1209
  outline-offset: -2px;
1072
1210
  }
1211
+ /* \u6807\u9898\u884C = \u5DE6\u8FB9"\u5C55\u5F00"\u6309\u94AE\uFF08\u5360\u6EE1\u5269\u4F59\u5BBD\u5EA6\uFF09+ \u53F3\u8FB9\u4ECE\u5C5E\u63A7\u4EF6\u4E0E\u672C\u680F\u5F00\u5173\u3002
1212
+ \u4E0D\u80FD\u5728 <button> \u91CC\u585E\u6309\u94AE\uFF0C\u6240\u4EE5\u4E24\u8005\u662F\u5144\u5F1F\u8282\u70B9\u3002 */
1213
+ .dsh-ux-cardHeaderRow {
1214
+ display: flex;
1215
+ align-items: center;
1216
+ flex-wrap: wrap;
1217
+ gap: 6px;
1218
+ padding-right: 12px;
1219
+ }
1220
+ .dsh-ux-cardControls {
1221
+ align-items: center;
1222
+ display: inline-flex;
1223
+ flex: none;
1224
+ flex-wrap: wrap;
1225
+ gap: 8px;
1226
+ }
1227
+ /* \u6807\u9898\u884C\u91CC\u7684"\u6587\u5B57 + \u5C0F\u5F00\u5173"\uFF08\u5BFC\u822A\u6EDA\u52A8 / \u8FB9\u7F18\u7F29\u653E\uFF09\u3002 */
1228
+ .dsh-ux-miniToggle {
1229
+ align-items: center;
1230
+ color: var(--dsw-alias-label-secondary);
1231
+ display: inline-flex;
1232
+ flex: none;
1233
+ font-size: 11px;
1234
+ gap: 5px;
1235
+ white-space: nowrap;
1236
+ }
1237
+ /* \u672A\u542F\u7528\uFF1A\u6807\u9898\u884C\u91CC\u8BF4\u6E05\u695A\uFF0C\u6B63\u6587\u538B\u6697\uFF0C\u8BA9\u4EBA\u4E00\u773C\u770B\u51FA"\u8FD9\u4E00\u680F\u73B0\u5728\u4E0D\u751F\u6548"\u3002 */
1238
+ .dsh-ux-cardOff { border-style: dashed; }
1239
+ .dsh-ux-cardOff .dsh-ux-cardBody { opacity: .6; }
1073
1240
  .dsh-ux-cardHeaderStatic {
1074
1241
  box-sizing: border-box;
1075
1242
  display: flex;
@@ -1097,6 +1264,109 @@ var CARD_CSS = `
1097
1264
  line-height: 1.5;
1098
1265
  margin: 0;
1099
1266
  }
1267
+ .dsh-ux-cardLink {
1268
+ align-items: center;
1269
+ color: var(--dsw-alias-label-secondary);
1270
+ display: inline-flex;
1271
+ flex: none;
1272
+ font-size: 12px;
1273
+ gap: 4px;
1274
+ text-decoration: none;
1275
+ white-space: nowrap;
1276
+ }
1277
+ .dsh-ux-cardLink:hover {
1278
+ color: var(--dsw-alias-brand-primary);
1279
+ text-decoration: underline;
1280
+ }
1281
+ /* \u62AC\u5934\u53F3\u7AEF\u90A3\u4E00\u7EC4\uFF1A\u91CD\u542F\u6309\u94AE + GitHub \u94FE\u63A5\uFF0C\u4E24\u679A\u90FD\u4E0D\u53C2\u4E0E\u6536\u7F29\u3002 */
1282
+ .dsh-ux-cardActions {
1283
+ align-items: center;
1284
+ display: inline-flex;
1285
+ flex: none;
1286
+ gap: 10px;
1287
+ }
1288
+ .dsh-ux-restartButton {
1289
+ appearance: none;
1290
+ background: 0 0;
1291
+ border: 1px solid var(--dsw-alias-border-l2);
1292
+ border-radius: 999px;
1293
+ color: var(--dsw-alias-label-primary);
1294
+ cursor: pointer;
1295
+ flex: none;
1296
+ font: inherit;
1297
+ font-size: 12px;
1298
+ line-height: 1;
1299
+ padding: 6px 12px;
1300
+ transition: border-color .16s, color .16s, background .16s;
1301
+ white-space: nowrap;
1302
+ }
1303
+ .dsh-ux-restartButton:hover:not(:disabled) {
1304
+ background: var(--dsw-alias-interactive-bg-hover);
1305
+ border-color: var(--dsw-alias-brand-primary);
1306
+ color: var(--dsw-alias-brand-primary);
1307
+ }
1308
+ .dsh-ux-restartButton:disabled {
1309
+ color: var(--dsw-alias-label-tertiary);
1310
+ cursor: default;
1311
+ opacity: .7;
1312
+ }
1313
+ /* \u786E\u8BA4\u6761\uFF1A\u62AC\u5934\u6B63\u4E0B\u65B9\u7684\u4E00\u6761\uFF0C\u4F4D\u7F6E\u5BF9\u9F50\u5E02\u573A\u7684\u300CN \u9879\u53D8\u66F4\u9700\u91CD\u542F\u300D\u6A2A\u5E45\u3002 */
1314
+ .dsh-ux-restartBanner {
1315
+ align-items: center;
1316
+ background: var(--dsw-alias-bg-layer-2);
1317
+ border: 1px solid var(--dsw-alias-border-l2);
1318
+ border-radius: 10px;
1319
+ display: flex;
1320
+ gap: 10px;
1321
+ margin: 0 16px 12px;
1322
+ padding: 10px 12px;
1323
+ }
1324
+ .dsh-ux-restartBannerFailed { border-color: var(--dsw-alias-state-error-primary); }
1325
+ .dsh-ux-restartBannerText {
1326
+ color: var(--dsw-alias-label-secondary);
1327
+ flex: 1;
1328
+ font-size: 12px;
1329
+ line-height: 1.5;
1330
+ min-width: 0;
1331
+ }
1332
+ .dsh-ux-restartBannerFailed .dsh-ux-restartBannerText { color: var(--dsw-alias-state-error-primary); }
1333
+ .dsh-ux-restartBannerActions {
1334
+ align-items: center;
1335
+ display: inline-flex;
1336
+ flex: none;
1337
+ gap: 8px;
1338
+ }
1339
+ .dsh-ux-restartGo {
1340
+ appearance: none;
1341
+ background: var(--dsw-alias-button-primary-fill);
1342
+ border: 0;
1343
+ border-radius: 999px;
1344
+ color: var(--dsw-alias-label-primary-foreground);
1345
+ cursor: pointer;
1346
+ font: inherit;
1347
+ font-size: 12px;
1348
+ line-height: 1;
1349
+ padding: 7px 14px;
1350
+ white-space: nowrap;
1351
+ }
1352
+ .dsh-ux-restartGo:hover { background: var(--dsw-alias-brand-primary); }
1353
+ .dsh-ux-restartCancel {
1354
+ appearance: none;
1355
+ background: 0 0;
1356
+ border: 1px solid var(--dsw-alias-border-l2);
1357
+ border-radius: 999px;
1358
+ color: var(--dsw-alias-label-secondary);
1359
+ cursor: pointer;
1360
+ font: inherit;
1361
+ font-size: 12px;
1362
+ line-height: 1;
1363
+ padding: 7px 14px;
1364
+ white-space: nowrap;
1365
+ }
1366
+ .dsh-ux-restartCancel:hover {
1367
+ border-color: var(--dsw-alias-label-dimmed);
1368
+ color: var(--dsw-alias-label-primary);
1369
+ }
1100
1370
  .dsh-ux-cardChevron {
1101
1371
  color: var(--dsw-alias-label-tertiary);
1102
1372
  flex: none;
@@ -1603,12 +1873,13 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1603
1873
  var EDGES = ["left", "right", "top", "bottom", "br"];
1604
1874
  function PanelResizeHandles({ useLive, actions }) {
1605
1875
  const settings = useLive((value) => ({
1606
- enabled: value.enabled,
1876
+ // 「设置面板」栏(或总开关)关着时整块停用 —— 与导航滚动那处用同一个判据。
1877
+ sectionOn: activeSections(value).panel,
1607
1878
  panelResize: value.panelResize,
1608
1879
  panelWidth: value.panelWidth,
1609
1880
  panelHeight: value.panelHeight
1610
1881
  }));
1611
- const enabled = settings.enabled === true && settings.panelResize === true;
1882
+ const enabled = settings.sectionOn === true && settings.panelResize === true;
1612
1883
  const [panel, setPanel] = (0, import_react2.useState)(null);
1613
1884
  const [active2, setActive] = (0, import_react2.useState)(null);
1614
1885
  const dragRef = (0, import_react2.useRef)(null);
@@ -1911,8 +2182,182 @@ function AddPromptRow({
1911
2182
  ] });
1912
2183
  }
1913
2184
 
1914
- // src/client/PillChoice.tsx
2185
+ // src/optimizer-prompt.ts
2186
+ var RELAY_ROLE = [
2187
+ '\u3010\u4F60\u662F\u8C01\u3011\u4F60\u662F\u4E00\u4E2A**\u4F20\u8BDD\u5668/\u610F\u56FE\u8865\u5168\u5668**\uFF0C\u7AD9\u5728\u7528\u6237\u4E0E"\u5DE5\u4F5C AI"\u4E4B\u95F4\uFF1A',
2188
+ " \u7528\u6237 \u2192\uFF08\u4F60\uFF1A\u628A\u7528\u6237\u7684\u610F\u601D\u6574\u7406\u6210\u6761\u76EE\u5E76\u7ED9\u51FA\u9010\u5B57\u4F9D\u636E\uFF09\u2192 \u5BBF\u4E3B\uFF08\u88C5\u914D\u6210\u4E00\u6761\u547D\u4EE4\uFF09\u2192 \u5DE5\u4F5C AI\u3002",
2189
+ "\u4F60\u7684\u4EA7\u51FA**\u4E0D\u4F1A**\u88AB\u76F4\u63A5\u5C55\u793A\u7ED9\u7528\u6237\uFF0C\u4E5F\u4E0D\u4F1A\u88AB\u539F\u6837\u53D1\u51FA\uFF1A\u5BBF\u4E3B\u4F1A\u7528\u4F60\u7ED9\u7684**\u9010\u5B57\u5F15\u6587**",
2190
+ "\u5728\u539F\u8BDD\u91CC\u5B9A\u4F4D\u3001\u53EA\u91C7\u7EB3\u80FD\u6838\u5BF9\u7684\u6761\u76EE\uFF0C\u518D\u88C5\u914D\u6210\u4E00\u6761\u547D\u4EE4\u4EA4\u7ED9\u5DE5\u4F5C AI\u3002",
2191
+ "\u3010\u4F60\u4E0D\u662F\u8C01\u3011\u4F60\u4E0D\u662F\u5728\u548C\u7528\u6237\u804A\u5929\uFF0C\u4E5F\u4E0D\u662F\u5728\u56DE\u7B54\u7528\u6237\uFF1A",
2192
+ "- \u4E0D\u8981\u56DE\u5E94\u3001\u4E0D\u8981\u56DE\u7B54\u7528\u6237\u7684\u8981\u6C42\uFF0C\u4E5F\u4E0D\u8981\u66FF\u7528\u6237\u5B8C\u6210\u4EFB\u52A1\uFF08\u4E0D\u8981\u76F4\u63A5\u7ED9\u51FA\u4EE3\u7801/\u7B54\u6848/\u7ED3\u679C\uFF09\u3002",
2193
+ '- \u4E0D\u8981\u4EE5\u52A9\u624B\u53E3\u543B\u5BF9\u7528\u6237\u8BF4\u8BDD\uFF08"\u597D\u7684""\u6536\u5230""\u6211\u53EF\u4EE5\u5E2E\u4F60""\u5EFA\u8BAE\u4F60\u2026""\u9700\u8981\u6211\u2026\u5417"\uFF09\u3002',
2194
+ '- \u4E0D\u8981\u628A\u7528\u6237\u53D1\u6765\u7684\u6587\u5B57\u5F53\u6210"\u5BF9\u4F60\u8BF4\u7684\u8BDD"\u6765\u56DE\u5E94\uFF1B\u5B83\u53EA\u662F\u4F60\u8981\u8F6C\u8FBE\u7684\u5185\u5BB9\u3002',
2195
+ "- \u4E0D\u8981\u5411\u7528\u6237\u63D0\u95EE\u3002\u8981\u6F84\u6E05\u65F6\uFF0C\u5199\u6210**\u7ED9\u5DE5\u4F5C AI \u7684\u6307\u4EE4**\uFF1A",
2196
+ ' "\u82E5 X \u4E0D\u660E\u786E\uFF0C\u5148\u8BFB Y \u6216\u5148\u5411\u6211\u786E\u8BA4\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE"\u3002'
2197
+ ].join("\n");
2198
+ var EVIDENCE_RULES = [
2199
+ "\u3010\u4F9D\u636E\u7EAA\u5F8B\uFF08\u5BBF\u4E3B\u4F1A\u9010\u6761\u673A\u68B0\u6838\u5BF9\uFF0C\u5199\u9519\u5C31\u4E22\u8FD9\u4E00\u6761\uFF09\u3011",
2200
+ "1. `rewrite` / `requirement` / `quality` **\u5FC5\u987B**\u5E26 `quote`\uFF1A\u4E00\u6BB5\u5728\u3010\u7528\u6237\u539F\u8BDD\u3011\u91CC",
2201
+ " **\u9010\u5B57\u5B58\u5728**\u7684\u5B50\u4E32 \u2014\u2014 \u7167\u6284\uFF0C\u4E0D\u8981\u6539\u5199\u3001\u4E0D\u8981\u8865\u6807\u70B9\u3001\u4E0D\u8981\u7FFB\u8BD1\u3002\u5BBF\u4E3B\u505A\u5B57\u9762\u5B50\u4E32\u6BD4\u5BF9\uFF0C",
2202
+ " \u5BF9\u4E0D\u4E0A\u5C31\u4E22\u6389\u90A3\u4E00\u6761\uFF08\u4E0D\u4F1A\u62A5\u9519\u7ED9\u4F60\uFF0C\u4E5F\u4E0D\u4F1A\u6709\u4EBA\u63D0\u9192\u4F60\uFF09\u3002",
2203
+ '2. **\u4E0D\u8BB8\u51ED\u7A7A\u65B0\u589E**\uFF1A\u4EA7\u54C1\u76EE\u6807\u3001\u529F\u80FD\u3001\u786C\u7EA6\u675F\uFF08"\u5FC5\u987B\u79BB\u7EBF""\u7981\u6B62\u8054\u7F51""\u53EA\u80FD\u7528\u67D0\u4E2A\u5E93"',
2204
+ ' "\u5FC5\u987B\u652F\u6301\u79FB\u52A8\u7AEF"\uFF09\u4E00\u5F8B\u4E0D\u8BB8\u7531\u4F60\u51B3\u5B9A\u3002\u4F60\u53EA\u80FD\u8865**\u80FD\u4ECE\u539F\u8BDD\u67D0\u4E00\u53E5\u76F4\u63A5\u63A8\u51FA**\u7684\u6700\u4F4E\u8981\u6C42\uFF0C',
2205
+ " \u5E76\u4E14\u5FC5\u987B\u5F15\u7528\u90A3\u4E00\u53E5\u3002",
2206
+ "3. \u4E0D\u786E\u5B9A\u3001\u4F1A\u5F71\u54CD\u7ED3\u679C\u3001\u4E14\u53EA\u6709\u7528\u6237\u80FD\u5B9A\u7684\u53D6\u820D \u2192 \u5199 `unknown`\uFF08`unknownClass` =",
2207
+ ' "user_preference"\uFF09\uFF0C**\u4E0D\u8981\u66FF\u7528\u6237\u731C**\uFF0C\u4E5F\u4E0D\u8981\u5199"\u6309\u6700\u4FDD\u5B88\u7406\u89E3\u6267\u884C"\u3002',
2208
+ ' \u5728\u8BB8\u53EF\u8303\u56F4\u5185\u8BFB\u4EE3\u7801\u5C31\u80FD\u786E\u5B9A\u7684\u4E8B\u5B9E\u5199 "lookupable_fact"\uFF1B\u53EF\u9006\u7684\u5B9E\u73B0\u7EC6\u8282',
2209
+ ' \uFF08\u95F4\u8DDD\u3001\u547D\u540D\u3001\u5E93\u7684\u5185\u90E8\u7528\u6CD5\uFF09\u5199 "implementation_detail"\u3002',
2210
+ "4. \u4E0D\u5F97\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\uFF08\u6587\u4EF6\u5185\u5BB9\u3001\u76EE\u5F55\u7ED3\u6784\u3001\u4F9D\u8D56\u7248\u672C\uFF09\u3002\u4F60\u6CA1\u8BFB\u5230\u7684\u4E1C\u897F\u4E0D\u5B58\u5728\u3002"
2211
+ ].join("\n");
2212
+ var STYLE_RULES = [
2213
+ '\u3010\u5199 text \u7684\u7EAA\u5F8B\u3011\u4F60\u7684 text \u4F1A\u88AB\u5BBF\u4E3B\u62FC\u8FDB\u6700\u7EC8\u547D\u4EE4\uFF0C\u8BFB\u8005\u53EA\u6709"\u5DE5\u4F5C AI"\u4E00\u4E2A\uFF1A',
2214
+ "- \u7948\u4F7F\u53E5\u3001\u76F4\u7ED9\u8981\u6C42\u3001\u53EF\u6267\u884C\uFF1B\u4E2D\u6587\u8FDB\u4E2D\u6587\u51FA\u3002",
2215
+ '- \u4E0D\u8981\u5143\u8BDD\u8BED\u4E0E\u5143\u6807\u9898\uFF08"\u4F18\u5316\u540E\u7684\u63D0\u793A\u8BCD""\u6539\u5199\u540E""\u8BF4\u660E""\u4EE5\u4E0B\u662F\u2026"\uFF09\u3002',
2216
+ '- \u4E0D\u8981\u63D0\u5230"\u7528\u6237/\u539F\u6587/\u4E0A\u9762\u7684\u8BDD"\uFF0C\u4E5F\u4E0D\u8981\u5199"\u6211\u6765\u5E2E\u4F60\u2026"\u3002',
2217
+ '- \u4E0D\u8981\u5199\u6D41\u7A0B\u4EEA\u5F0F\u3001\u901A\u7528\u6559\u5B66\u3001\u9A8C\u6536\u5957\u8BDD\uFF08"\u8BF7\u786E\u4FDD\u4EE3\u7801\u8D28\u91CF"\u8FD9\u79CD\u6CA1\u6709\u6307\u5411\u7684\u8BDD\uFF09\u3002',
2218
+ "- `rewrite` \u7684 text \u662F**\u66FF\u6362\u6389\u90A3\u6BB5\u5F15\u6587**\u7684\u6B63\u6587\uFF0C\u6240\u4EE5\u53EA\u5199\u90A3\u6BB5\u8BDD\u672C\u8EAB\uFF0C\u4E0D\u8981\u5E26\u524D\u7F00\u540E\u7F00\u3002"
2219
+ ].join("\n");
2220
+ var OPTIMIZER_OUTPUT_CONTRACT = [
2221
+ "\u3010\u8F93\u51FA\u5951\u7EA6\uFF08\u56FA\u5B9A\uFF0C\u4E0D\u53EF\u66F4\u6539\uFF09\u3011",
2222
+ "\u53EA\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981 Markdown \u4EE3\u7801\u5757\u3001\u4E0D\u8981\u5728 JSON \u524D\u540E\u5199\u4EFB\u4F55\u5B57\uFF1A",
2223
+ '{"items":[{"kind":"rewrite","quote":"\u539F\u8BDD\u91CC\u9010\u5B57\u5B58\u5728\u7684\u7247\u6BB5","text":"\u66FF\u6362\u6389\u8BE5\u7247\u6BB5\u7684\u6B63\u6587"}]}',
2224
+ "\u5B57\u6BB5\u4E0E\u53D6\u503C\uFF08`kind` \u53EA\u80FD\u662F\u8FD9\u516D\u79CD\uFF09\uFF1A",
2225
+ "- rewrite\uFF1A\u8BED\u8A00\u5C42\u4FEE\u590D\u3002`quote` \u5FC5\u586B\uFF1B\u540C\u4E00\u6BB5\u539F\u8BDD\u6700\u591A\u4E00\u6761 rewrite\uFF0C\u4E0D\u8981\u91CD\u53E0\u3002",
2226
+ "- requirement\uFF1A\u4ECE `quote` \u76F4\u63A5\u63A8\u51FA\u7684\u8865\u5168\u8981\u6C42\uFF08\u9A8C\u6536\u6807\u51C6/\u786C\u7EA6\u675F\uFF09\u3002`quote` \u5FC5\u586B\u3002",
2227
+ "- quality\uFF1A\u5BF9\u539F\u8BDD\u91CC\u8D28\u91CF\u8BCD\u7684\u89E3\u91CA\u3002`quote` \u5FC5\u586B\uFF08\u5C31\u586B\u90A3\u51E0\u4E2A\u8D28\u91CF\u5B57\uFF09\u3002",
2228
+ "- unknown\uFF1A\u672A\u51B3\u9879\u3002\u5FC5\u987B\u5E26 `unknownClass`\uFF08user_preference / lookupable_fact /",
2229
+ " implementation_detail\uFF09\uFF0C\u53EF\u9009 `blocking`\uFF08true/false\uFF0C\u662F\u5426\u6321\u4F4F\u4E0B\u4E00\u6B65\uFF09\u3002",
2230
+ '- plan\uFF1A\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\uFF08\u4EC5"\u6781\u7AEF"\u6863\u7528\uFF09\u3002',
2231
+ '- risk\uFF1A\u591A\u60C5\u51B5\u9884\u6848\uFF08\u4EC5"\u6781\u7AEF"\u6863\u7528\uFF09\uFF0C\u6BCF\u6761\u6309"\u89E6\u53D1\u4FE1\u53F7 \u2192 \u5E94\u5BF9 \u2192 \u7981\u6B62\u52A8\u4F5C"\u5199\u3002',
2232
+ "\u9650\u5236\uFF1A`text` \u6BCF\u6761\u4E0D\u8D85\u8FC7 300 \u5B57\uFF1B`items` \u603B\u5171\u4E0D\u8D85\u8FC7 12 \u6761\uFF1Bid \u4E0D\u9700\u8981\u7ED9\u3002",
2233
+ '\u6CA1\u6709\u53EF\u8865\u7684\u5185\u5BB9\u65F6\uFF0C\u8F93\u51FA {"items":[]} \u2014\u2014 \u4F46**\u5148\u60F3\u6E05\u695A**\uFF1A\u7528\u6237\u8FD9\u4E00\u8F6E\u7684\u539F\u8BDD\u91CC',
2234
+ "\u771F\u7684\u6CA1\u6709\u4EFB\u4F55\u53EF\u6838\u5BF9\u7684\u8865\u5168\u5417\uFF1F"
2235
+ ].join("\n");
2236
+ var TIER_TASKS = {
2237
+ basic: [
2238
+ "\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u53EA\u505A\u8BED\u8A00\u5C42\u4FEE\u590D\u3011",
2239
+ "\u7528\u6237\u539F\u8BDD\u53EF\u80FD\u6709\u75C5\u53E5\u3001\u6307\u4EE3\u4E0D\u660E\u3001\u7528\u8BCD\u542B\u7CCA\u3002\u628A\u5B83\u6539\u5199\u6210\u901A\u987A\u3001\u7CBE\u786E\u3001\u65E0\u6B67\u4E49\u7684**\u540C\u4E00\u6BB5\u8BDD**\u3002",
2240
+ "\u53EA\u4EA7\u51FA `rewrite`\uFF08\u53EF\u4EE5\u6309\u53E5\u5B50\u62C6\u6210\u591A\u6761\uFF0C\u6BCF\u6761\u5F15\u7528\u539F\u8BDD\u91CC\u5BF9\u5E94\u90A3\u4E00\u53E5\uFF09\u3002",
2241
+ "\u4E25\u7981\u4EA7\u51FA requirement / plan / risk\uFF1A\u8FD9\u4E00\u6863**\u4E0D\u65B0\u589E\u4EFB\u4F55\u8981\u6C42**\uFF0C\u53EA\u628A\u8BDD\u8BF4\u660E\u767D\u3002",
2242
+ "\u539F\u8BDD\u786E\u6709\u6B67\u4E49\u3001\u4E14\u6B67\u4E49\u4F1A\u5BFC\u81F4\u505A\u9519\u65F6\uFF0C\u624D\u8865\u4E00\u6761 `unknown`\uFF08unknownClass \u53D6",
2243
+ "user_preference \u6216 lookupable_fact\uFF09\uFF1B\u786E\u5B9E\u6CA1\u6709\u53EF\u8865\u7684\u5C31\u8F93\u51FA\u7A7A\u6570\u7EC4\u3002",
2244
+ "\u957F\u5EA6\u7EAA\u5F8B\uFF1A\u6210\u54C1\u4E0D\u8D85\u8FC7\u539F\u8BDD\u7684 1.4 \u500D\uFF1B\u539F\u8BDD 30 \u5B57\u4EE5\u5185\u65F6\u4E0D\u8D85\u8FC7 60 \u5B57\u3002"
2245
+ ],
2246
+ advanced: [
2247
+ "\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u5728\u4E0D\u52A8\u76EE\u6807\u7684\u524D\u63D0\u4E0B\u628A\u547D\u4EE4\u8BF4\u6E05\u695A\u3011",
2248
+ '\u7528\u6237\u539F\u8BDD\u542B\u7CCA\u3001\u7F3A\u5173\u952E\u7EA6\u675F\u3002\u4F60\u8981\u8865\u7684\u662F"\u7528\u6237\u663E\u7136\u60F3\u8981\u3001\u4F46\u6CA1\u8BF4\u51FA\u53E3"\u7684\u5FC5\u8981\u4FE1\u606F\uFF0C',
2249
+ "\u8BA9\u5B83\u4E00\u6B21\u505A\u5BF9 \u2014\u2014 \u4F46\u6BCF\u4E00\u6761\u90FD\u5FC5\u987B\u662F**\u4ECE\u539F\u8BDD\u67D0\u4E00\u53E5\u76F4\u63A5\u63A8\u51FA**\u7684\uFF0C\u5E76\u5F15\u7528\u90A3\u4E00\u53E5\u3002",
2250
+ "\u5141\u8BB8\u4EA7\u51FA\uFF1A",
2251
+ "- `rewrite`\uFF1A\u628A\u542B\u7CCA\u3001\u6709\u75C5\u53E5\u7684\u5730\u65B9\u8BF4\u6E05\u695A\uFF08\u540C\u4E00\u6BB5\u539F\u8BDD\u6700\u591A\u4E00\u6761\uFF09\u3002",
2252
+ '- `requirement`\uFF1A\u4ECE\u539F\u8BDD\u76F4\u63A5\u63A8\u51FA\u7684\u6700\u4F4E\u4EA4\u4ED8\u8981\u6C42\u4E0E\u9A8C\u6536\u6807\u51C6\uFF08"\u6539\u5B8C\u80FD\u8DD1\u8D77\u6765""\u9875\u9762\u80FD\u6253\u5F00"',
2253
+ " \u8FD9\u7C7B\u53EF\u89C2\u6D4B\u7684\u8BDD\uFF09\uFF0C\u5199\u6210\u5BF9\u5DE5\u4F5C AI \u7684\u8981\u6C42\u800C\u4E0D\u662F\u8BC4\u8BBA\u3002\u6BCF\u6761\u90FD\u8981\u80FD\u6307\u56DE\u539F\u8BDD\u91CC\u7684\u67D0\u4E00\u53E5\u3002",
2254
+ '- `quality`\uFF1A\u7528\u6237\u8BF4\u7684\u8D28\u91CF\u8BCD\uFF08"\u597D\u770B\u70B9""\u9AD8\u7EA7\u611F""\u6D41\u7545"\uFF09\u2192 \u89E3\u91CA\u6210\u53EF\u89C2\u5BDF\u7684\u8981\u6C42\u3002',
2255
+ " \u5B83\u662F**\u89E3\u91CA**\uFF0C\u4E0D\u662F\u65B0\u589E\u76EE\u6807\uFF1A\u4E00\u6761\u8D28\u91CF\u8BCD\u6700\u591A\u4E00\u6761 quality\u3002",
2256
+ "- `unknown`\uFF1A\u53EA\u6709\u7528\u6237\u80FD\u5B9A\u7684\u53D6\u820D\uFF08user_preference\uFF09/ \u8BE5\u53BB\u67E5\u8BC1\u7684\u4E8B\u5B9E\uFF08lookupable_fact\uFF09\u3002",
2257
+ "\u7981\u6B62\uFF1A\u65B0\u589E\u529F\u80FD\u3001\u65B0\u76EE\u6807\u3001\u65B0\u4F9D\u8D56\uFF1B\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\uFF1B\u5199\u7528\u6237\u6CA1\u6388\u6743\u7684\u6280\u672F\u9009\u578B\u3002",
2258
+ "\u6570\u91CF\u7EAA\u5F8B\uFF1Arequirement \u6700\u591A 3 \u6761\uFF0Cquality \u6700\u591A 2 \u6761\uFF0Cunknown \u6700\u591A 2 \u6761\u3002"
2259
+ ],
2260
+ extreme: [
2261
+ "\u3010\u672C\u8F6E\u4EFB\u52A1\uFF1A\u628A\u8BC9\u6C42\u56FA\u5316\u6210\u4E00\u6761\u53EF\u76F4\u63A5\u6267\u884C\u7684\u547D\u4EE4\u3011",
2262
+ "\u8FD9\u6B21\u662F\u591A\u6B65\u6267\u884C\u7684\u590D\u6742\u4EFB\u52A1\uFF0C\u5DE5\u4F5C AI \u4F1A\u7167\u8FD9\u6761\u547D\u4EE4\u5E72\uFF0C\u7528\u6237\u4E0D\u4F1A\u518D\u8865\u5145\u3002",
2263
+ '\u5728"\u9AD8\u7EA7"\u6863\u5141\u8BB8\u7684\u5168\u90E8\u6761\u76EE\u7684\u57FA\u7840\u4E0A\uFF0C\u518D\u52A0\u4E24\u7C7B\uFF08\u90FD\u8981\u4EE5\u7528\u6237\u5728\u7ED9\u5DE5\u4F5C AI \u4E0B\u547D\u4EE4\u7684\u53E3\u543B\u5199\uFF09\uFF1A',
2264
+ "- `plan`\uFF1A\u5206\u9636\u6BB5\u6267\u884C\u8BA1\u5212\u3002\u6BCF\u9636\u6BB5\u5199\u6E05\u52A8\u4F5C\u4E0E\u4EA7\u51FA\uFF0C\u5E76\u5199\u660E\u7EAA\u5F8B\uFF08\u5148\u9A8C\u8BC1\u518D\u6539\u3001\u5931\u8D25\u5373\u56DE\u9000\u3001",
2265
+ " \u4E0D\u64C5\u81EA\u6269\u5927\u8303\u56F4\u3001\u6539\u5B8C\u7ED9\u51FA\u8BC1\u636E\uFF09\u3002",
2266
+ '- `risk`\uFF1A\u591A\u60C5\u51B5\u9884\u6848 2~4 \u6761\uFF0C\u6BCF\u6761\u5199\u6210"\u5982\u679C\u51FA\u73B0 <\u89E6\u53D1\u4FE1\u53F7>\uFF0C\u5C31\u5148 <\u5E94\u5BF9\u52A8\u4F5C>\uFF0C',
2267
+ ' \u4E0D\u8981 <\u7981\u6B62\u52A8\u4F5C>"\u3002',
2268
+ "\u8FD8\u8981\u5224\u65AD\u8FD9\u6B21\u4EFB\u52A1\u662F\u5426\u503C\u5F97\u8BA9\u5DE5\u4F5C AI \u7528 goal / todo / \u8BA1\u5212\u6A21\u5F0F\u8DDF\u8E2A\uFF0C\u5E76\u628A\u7ED3\u8BBA\u5199\u6210",
2269
+ '`requirement` \u7684\u4E00\u90E8\u5206\uFF08\u4F8B\u5982"\u8BF7\u5148\u5EFA\u7ACB goal\uFF1A\u2026\uFF0C\u518D\u6309\u4E0B\u5217\u9636\u6BB5\u63A8\u8FDB"\uFF09\uFF1B\u4E0D\u9700\u8981\u5C31\u5B8C\u5168\u4E0D\u63D0\u3002',
2270
+ '\u94C1\u5F8B\uFF1A\u4E0D\u5F97\u865A\u6784\u9879\u76EE\u4E8B\u5B9E\u3002\u9700\u8981\u9879\u76EE\u4E8B\u5B9E\u65F6\u5199\u6210"\u5148\u8BFB\u53D6/\u786E\u8BA4 X"\u7684\u67E5\u8BC1\u52A8\u4F5C\u3002',
2271
+ "\u6570\u91CF\u7EAA\u5F8B\uFF1Aplan \u6700\u591A 1 \u6761\uFF0Crisk \u6700\u591A 4 \u6761\uFF0Crequirement \u6700\u591A 3 \u6761\u3002"
2272
+ ]
2273
+ };
2274
+ var OPTIMIZER_SPECS = {
2275
+ basic: {
2276
+ temperature: 0.2,
2277
+ system: [RELAY_ROLE, TIER_TASKS.basic.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
2278
+ },
2279
+ advanced: {
2280
+ temperature: 0.3,
2281
+ system: [RELAY_ROLE, TIER_TASKS.advanced.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
2282
+ },
2283
+ extreme: {
2284
+ temperature: 0.3,
2285
+ system: [RELAY_ROLE, TIER_TASKS.extreme.join("\n"), EVIDENCE_RULES, STYLE_RULES].join("\n\n")
2286
+ }
2287
+ };
2288
+
2289
+ // src/client/OptimizerPromptEditor.tsx
1915
2290
  var import_jsx_runtime4 = require("react/jsx-runtime");
2291
+ function builtinTaskPrompt(tier) {
2292
+ return OPTIMIZER_SPECS[tier]?.system ?? OPTIMIZER_SPECS.advanced.system;
2293
+ }
2294
+ function OptimizerPromptEditor({ tier, value, onChange }) {
2295
+ const label = OPTIMIZER_TIERS.find((item) => item.id === tier)?.label ?? tier;
2296
+ const custom = value.trim() !== "";
2297
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2298
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowText, children: [
2299
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowTitle, children: [
2300
+ `\u672C\u6863\u63D0\u793A\u8BCD\uFF08${label}\uFF09`,
2301
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { marginLeft: 8, opacity: 0.75 }, children: custom ? "\u81EA\u5B9A\u4E49" : "\u5185\u7F6E" })
2302
+ ] }),
2303
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: rowDesc, children: [
2304
+ "\u7559\u7A7A = \u7528\u63D2\u4EF6\u5185\u7F6E\u90A3\u4EFD\u3002\u6539\u7684\u662F\u300C\u4EFB\u52A1\u4E0E\u98CE\u683C\u300D\u8FD9\u6BB5\uFF1B",
2305
+ " ",
2306
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: "JSON \u8F93\u51FA\u5951\u7EA6" }),
2307
+ "\u7531\u63D2\u4EF6\u5728\u672B\u5C3E\u8FFD\u52A0\u3001\u4E0D\u5728\u8FD9\u91CC\u6539 \u2014\u2014 \u5BBF\u4E3B\u9760\u5B83\u9010\u6761\u6838\u5BF9\u300C\u6BCF\u6761\u8865\u5168\u90FD\u6307\u56DE\u4F60\u539F\u8BDD\u91CC\u7684\u67D0\u53E5\u300D\uFF0C\u5951\u7EA6\u88AB\u6539\u6389\u8FD9\u5957\u6821\u9A8C\u5C31\u6CA1\u4E86\u3002"
2308
+ ] })
2309
+ ] }),
2310
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2311
+ "textarea",
2312
+ {
2313
+ value,
2314
+ placeholder: "\u7559\u7A7A = \u7528\u5185\u7F6E\u63D0\u793A\u8BCD\u3002\u70B9\u4E0B\u9762\u7684\u300C\u8F7D\u5165\u5185\u7F6E\u7248\u300D\u53EF\u4EE5\u5148\u628A\u5185\u7F6E\u90A3\u4EFD\u6284\u8FDB\u6765\u518D\u6539\u3002",
2315
+ maxLength: OPTIMIZER_PROMPT_MAX,
2316
+ spellCheck: false,
2317
+ rows: value.trim() === "" ? 3 : Math.min(16, Math.max(6, Math.ceil(value.length / 60))),
2318
+ onChange: (event) => {
2319
+ onChange(event.target.value);
2320
+ },
2321
+ style: { ...textInput, resize: "vertical", fontFamily: "inherit", lineHeight: 1.5 }
2322
+ }
2323
+ ),
2324
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2325
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2326
+ "button",
2327
+ {
2328
+ type: "button",
2329
+ style: pill,
2330
+ title: "\u628A\u5185\u7F6E\u90A3\u4EFD\u4EFB\u52A1\u63D0\u793A\u8BCD\u6284\u8FDB\u8F93\u5165\u6846\uFF0C\u65B9\u4FBF\u5728\u6B64\u57FA\u7840\u4E0A\u6539",
2331
+ onClick: () => {
2332
+ onChange(builtinTaskPrompt(tier));
2333
+ },
2334
+ children: "\u8F7D\u5165\u5185\u7F6E\u7248"
2335
+ }
2336
+ ),
2337
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2338
+ "button",
2339
+ {
2340
+ type: "button",
2341
+ style: pill,
2342
+ disabled: !custom,
2343
+ title: "\u6E05\u7A7A\u81EA\u5B9A\u4E49\uFF0C\u6539\u7528\u5185\u7F6E\u63D0\u793A\u8BCD",
2344
+ onClick: () => {
2345
+ onChange("");
2346
+ },
2347
+ children: "\u6062\u590D\u5185\u7F6E"
2348
+ }
2349
+ ),
2350
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { ...rowDesc, flex: "1 1 auto" }, children: `\u5F53\u524D\u5B57\u6570 ${String(value.length)} / ${String(OPTIMIZER_PROMPT_MAX)}` })
2351
+ ] }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { children: [
2353
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("summary", { style: { ...rowDesc, cursor: "pointer" }, children: "\u770B\u63D2\u4EF6\u56FA\u5B9A\u8FFD\u52A0\u7684\u90A3\u6BB5\u8F93\u51FA\u5951\u7EA6" }),
2354
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { style: { ...rowDesc, whiteSpace: "pre-wrap", margin: "6px 0 0" }, children: OPTIMIZER_OUTPUT_CONTRACT })
2355
+ ] })
2356
+ ] });
2357
+ }
2358
+
2359
+ // src/client/PillChoice.tsx
2360
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1916
2361
  var base = {
1917
2362
  border: "0.5px solid var(--dsw-alias-border-l2)",
1918
2363
  background: "transparent",
@@ -1935,13 +2380,13 @@ function PillChoice({
1935
2380
  ariaLabel,
1936
2381
  compact = false
1937
2382
  }) {
1938
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2383
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1939
2384
  "div",
1940
2385
  {
1941
2386
  role: "group",
1942
2387
  "aria-label": ariaLabel,
1943
2388
  style: { display: "inline-flex", alignItems: "center", gap: 2, flex: "0 0 auto" },
1944
- children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2389
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1945
2390
  "button",
1946
2391
  {
1947
2392
  type: "button",
@@ -1967,9 +2412,9 @@ function PillChoice({
1967
2412
  }
1968
2413
 
1969
2414
  // src/client/InsertModeControl.tsx
1970
- var import_jsx_runtime5 = require("react/jsx-runtime");
2415
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1971
2416
  function InsertModeControl({ mode, onChange, compact = false, label }) {
1972
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2417
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1973
2418
  PillChoice,
1974
2419
  {
1975
2420
  items: INSERT_MODES,
@@ -1982,10 +2427,10 @@ function InsertModeControl({ mode, onChange, compact = false, label }) {
1982
2427
  }
1983
2428
 
1984
2429
  // src/client/SettingsSection.tsx
1985
- var import_jsx_runtime6 = require("react/jsx-runtime");
2430
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1986
2431
  var bodyLead = { ...description, margin: "12px 0" };
1987
2432
  function Chevron() {
1988
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2433
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1989
2434
  "path",
1990
2435
  {
1991
2436
  d: "M3.25 5.5L7 9.25L10.75 5.5",
@@ -1998,26 +2443,45 @@ function Chevron() {
1998
2443
  }
1999
2444
  function FoldCard(props) {
2000
2445
  const [open, setOpen] = (0, import_react4.useState)(false);
2001
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: open ? "dsh-ux-card dsh-ux-cardOpen" : "dsh-ux-card", children: [
2002
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2003
- "button",
2004
- {
2005
- type: "button",
2006
- className: "dsh-ux-cardHeader",
2007
- "aria-expanded": open,
2008
- onClick: () => {
2009
- setOpen((current) => !current);
2010
- },
2011
- children: [
2012
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2013
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-cardName", children: props.name }),
2014
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-cardDescription", children: props.summary })
2015
- ] }),
2016
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: open ? "dsh-ux-cardChevron dsh-ux-cardChevronOpen" : "dsh-ux-cardChevron", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Chevron, {}) })
2017
- ]
2018
- }
2019
- ),
2020
- open && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-ux-cardBody", children: props.children })
2446
+ const off = props.toggle !== void 0 && props.toggle.checked === false;
2447
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: [
2448
+ "dsh-ux-card",
2449
+ open ? "dsh-ux-cardOpen" : "",
2450
+ off ? "dsh-ux-cardOff" : ""
2451
+ ].filter((part) => part !== "").join(" "), children: [
2452
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-ux-cardHeaderRow", children: [
2453
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2454
+ "button",
2455
+ {
2456
+ type: "button",
2457
+ className: "dsh-ux-cardHeader",
2458
+ "aria-expanded": open,
2459
+ onClick: () => {
2460
+ setOpen((current) => !current);
2461
+ },
2462
+ children: [
2463
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2464
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-cardName", children: props.name }),
2465
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-cardDescription", children: off ? `\u672A\u542F\u7528 \xB7 ${props.summary}` : props.summary })
2466
+ ] }),
2467
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: open ? "dsh-ux-cardChevron dsh-ux-cardChevronOpen" : "dsh-ux-cardChevron", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Chevron, {}) })
2468
+ ]
2469
+ }
2470
+ ),
2471
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-cardControls", children: [
2472
+ props.controls,
2473
+ props.toggle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2474
+ Switch,
2475
+ {
2476
+ small: true,
2477
+ label: `${props.name}\uFF1A\u542F\u7528\u8FD9\u4E00\u680F`,
2478
+ checked: props.toggle.checked,
2479
+ onChange: props.toggle.onChange
2480
+ }
2481
+ )
2482
+ ] })
2483
+ ] }),
2484
+ open && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-ux-cardBody", children: props.children })
2021
2485
  ] });
2022
2486
  }
2023
2487
  function KeyRow(props) {
@@ -2062,14 +2526,14 @@ function KeyRow(props) {
2062
2526
  };
2063
2527
  }, [recording, conflict, onChange]);
2064
2528
  const base2 = first === true ? { ...row, borderTop: "none" } : row;
2065
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2066
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2067
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: title }),
2068
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
2529
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2530
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: title }),
2532
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: desc })
2069
2533
  ] }),
2070
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2071
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: kbd, children: displayChord(value) }),
2072
- !recording && presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2534
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2535
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: kbd, children: displayChord(value) }),
2536
+ !recording && presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2073
2537
  "button",
2074
2538
  {
2075
2539
  type: "button",
@@ -2082,11 +2546,11 @@ function KeyRow(props) {
2082
2546
  },
2083
2547
  preset
2084
2548
  )),
2085
- !recording && value !== "" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2549
+ !recording && value !== "" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, onClick: () => {
2086
2550
  setError(null);
2087
2551
  onChange("");
2088
2552
  }, children: "\u6E05\u9664" }),
2089
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2553
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2090
2554
  "button",
2091
2555
  {
2092
2556
  type: "button",
@@ -2098,58 +2562,73 @@ function KeyRow(props) {
2098
2562
  children: recording ? "\u8BF7\u6309\u4E0B\u65B0\u7EC4\u5408\u952E\u2026" : "\u81EA\u5B9A\u4E49\u2026"
2099
2563
  }
2100
2564
  ),
2101
- recording && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2565
+ recording && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, onClick: () => {
2102
2566
  setRecording(false);
2103
2567
  setError(null);
2104
2568
  }, children: "Esc \u53D6\u6D88" }),
2105
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: "var(--dsw-alias-state-error-primary)", fontSize: 12 }, children: error })
2569
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { color: "var(--dsw-alias-state-error-primary)", fontSize: 12 }, children: error })
2106
2570
  ] })
2107
2571
  ] });
2108
2572
  }
2573
+ function Switch(props) {
2574
+ const { checked, onChange, label, small = false } = props;
2575
+ const width = small ? 30 : 36;
2576
+ const height = small ? 16 : 20;
2577
+ const knob = small ? 12 : 14;
2578
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2579
+ "button",
2580
+ {
2581
+ type: "button",
2582
+ role: "switch",
2583
+ "aria-checked": checked,
2584
+ "aria-label": label,
2585
+ title: label,
2586
+ onClick: () => {
2587
+ onChange(!checked);
2588
+ },
2589
+ style: {
2590
+ width,
2591
+ height,
2592
+ borderRadius: 999,
2593
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2594
+ cursor: "pointer",
2595
+ background: checked ? "var(--dsw-alias-button-primary-fill)" : "var(--dsw-alias-interactive-bg-hover)",
2596
+ position: "relative",
2597
+ flex: "0 0 auto",
2598
+ padding: 0
2599
+ },
2600
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2601
+ "span",
2602
+ {
2603
+ style: {
2604
+ position: "absolute",
2605
+ top: small ? 1 : 2,
2606
+ left: checked ? width - knob - (small ? 1 : 2) : small ? 1 : 2,
2607
+ width: knob,
2608
+ height: knob,
2609
+ borderRadius: "50%",
2610
+ background: checked ? "var(--dsw-alias-label-primary-foreground)" : "var(--dsw-alias-label-secondary)",
2611
+ transition: "left 0.12s ease"
2612
+ }
2613
+ }
2614
+ )
2615
+ }
2616
+ );
2617
+ }
2618
+ function MiniToggle(props) {
2619
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-miniToggle", children: [
2620
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-miniToggleLabel", children: props.label }),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Switch, { small: true, label: props.label, checked: props.checked, onChange: props.onChange })
2622
+ ] });
2623
+ }
2109
2624
  function ToggleRow(props) {
2110
2625
  const { label, desc, checked, onChange, first } = props;
2111
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: first === true ? { ...row, borderTop: "none" } : row, children: [
2112
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2113
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: label }),
2114
- desc !== void 0 && desc !== "" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
2626
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: first === true ? { ...row, borderTop: "none" } : row, children: [
2627
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
2628
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: label }),
2629
+ desc !== void 0 && desc !== "" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: desc })
2115
2630
  ] }),
2116
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2117
- "button",
2118
- {
2119
- type: "button",
2120
- role: "switch",
2121
- "aria-checked": checked,
2122
- onClick: () => {
2123
- onChange(!checked);
2124
- },
2125
- style: {
2126
- width: 36,
2127
- height: 20,
2128
- borderRadius: 999,
2129
- border: "0.5px solid var(--dsw-alias-border-l2)",
2130
- cursor: "pointer",
2131
- background: checked ? "var(--dsw-alias-button-primary-fill)" : "var(--dsw-alias-interactive-bg-hover)",
2132
- position: "relative",
2133
- flex: "0 0 auto",
2134
- padding: 0
2135
- },
2136
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2137
- "span",
2138
- {
2139
- style: {
2140
- position: "absolute",
2141
- top: 2,
2142
- left: checked ? 18 : 2,
2143
- width: 14,
2144
- height: 14,
2145
- borderRadius: "50%",
2146
- background: checked ? "var(--dsw-alias-label-primary-foreground)" : "var(--dsw-alias-label-secondary)",
2147
- transition: "left 0.12s ease"
2148
- }
2149
- }
2150
- )
2151
- }
2152
- )
2631
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Switch, { label, checked, onChange })
2153
2632
  ] });
2154
2633
  }
2155
2634
  function TextFieldRow(props) {
@@ -2164,13 +2643,13 @@ function TextFieldRow(props) {
2164
2643
  onChange(draft.trim());
2165
2644
  };
2166
2645
  const base2 = first === true ? { ...row, borderTop: "none" } : row;
2167
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2168
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2169
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: title }),
2170
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
2646
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2647
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
2648
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: title }),
2649
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: desc })
2171
2650
  ] }),
2172
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2173
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2651
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2652
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2174
2653
  "input",
2175
2654
  {
2176
2655
  type: "text",
@@ -2199,7 +2678,7 @@ function TextFieldRow(props) {
2199
2678
  style: textInput
2200
2679
  }
2201
2680
  ),
2202
- action !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: action.onClick, children: action.label })
2681
+ action !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, onClick: action.onClick, children: action.label })
2203
2682
  ] })
2204
2683
  ] });
2205
2684
  }
@@ -2233,9 +2712,9 @@ function QuickPromptsEditor(props) {
2233
2712
  border: "0.5px solid var(--dsw-alias-border-l2)",
2234
2713
  background: "var(--dsw-alias-bg-layer-1)"
2235
2714
  };
2236
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2237
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap" }, children: [
2238
- draft.categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2715
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2716
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap" }, children: [
2717
+ draft.categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2239
2718
  "button",
2240
2719
  {
2241
2720
  type: "button",
@@ -2252,7 +2731,7 @@ function QuickPromptsEditor(props) {
2252
2731
  },
2253
2732
  category.id
2254
2733
  )),
2255
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2734
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2256
2735
  "input",
2257
2736
  {
2258
2737
  type: "text",
@@ -2266,7 +2745,7 @@ function QuickPromptsEditor(props) {
2266
2745
  style: { ...textInput, flex: "0 0 110px" }
2267
2746
  }
2268
2747
  ),
2269
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2748
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2270
2749
  "button",
2271
2750
  {
2272
2751
  type: "button",
@@ -2280,10 +2759,10 @@ function QuickPromptsEditor(props) {
2280
2759
  }
2281
2760
  )
2282
2761
  ] }),
2283
- current === void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: rowDesc, children: "\u8FD8\u6CA1\u6709\u5206\u7C7B\u3002\u5148\u52A0\u4E00\u4E2A\u5206\u7C7B\uFF0C\u518D\u5F80\u91CC\u653E\u6761\u76EE\u3002" }),
2284
- current !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2285
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2286
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2762
+ current === void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: rowDesc, children: "\u8FD8\u6CA1\u6709\u5206\u7C7B\u3002\u5148\u52A0\u4E00\u4E2A\u5206\u7C7B\uFF0C\u518D\u5F80\u91CC\u653E\u6761\u76EE\u3002" }),
2763
+ current !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2764
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2765
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2287
2766
  "input",
2288
2767
  {
2289
2768
  type: "text",
@@ -2297,13 +2776,13 @@ function QuickPromptsEditor(props) {
2297
2776
  style: { ...textInput, flex: "0 0 150px" }
2298
2777
  }
2299
2778
  ),
2300
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0A\u79FB", onClick: () => {
2779
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0A\u79FB", onClick: () => {
2301
2780
  edit(withCategoryMoved(draft, current.id, -1));
2302
2781
  }, children: "\u2191" }),
2303
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0B\u79FB", onClick: () => {
2782
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0B\u79FB", onClick: () => {
2304
2783
  edit(withCategoryMoved(draft, current.id, 1));
2305
2784
  }, children: "\u2193" }),
2306
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2785
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2307
2786
  "button",
2308
2787
  {
2309
2788
  type: "button",
@@ -2315,16 +2794,16 @@ function QuickPromptsEditor(props) {
2315
2794
  children: "\u2715 \u5220\u9664\u5206\u7C7B"
2316
2795
  }
2317
2796
  ),
2318
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: rowDesc, children: [
2797
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: rowDesc, children: [
2319
2798
  current.prompts.length,
2320
2799
  " / ",
2321
2800
  QUICK_PROMPT_MAX,
2322
2801
  " \u6761"
2323
2802
  ] })
2324
2803
  ] }),
2325
- current.prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowBox, children: [
2326
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2327
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2804
+ current.prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowBox, children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2806
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2328
2807
  "input",
2329
2808
  {
2330
2809
  type: "text",
@@ -2338,7 +2817,7 @@ function QuickPromptsEditor(props) {
2338
2817
  style: { ...textInput, flex: "0 0 150px" }
2339
2818
  }
2340
2819
  ),
2341
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2820
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2342
2821
  InsertModeControl,
2343
2822
  {
2344
2823
  label: prompt.label,
@@ -2348,18 +2827,18 @@ function QuickPromptsEditor(props) {
2348
2827
  }
2349
2828
  }
2350
2829
  ),
2351
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
2352
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u4E0A\u79FB", onClick: () => {
2830
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { flex: 1 } }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, title: "\u4E0A\u79FB", onClick: () => {
2353
2832
  edit(withPromptMoved(draft, current.id, prompt.id, -1));
2354
2833
  }, children: "\u2191" }),
2355
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u4E0B\u79FB", onClick: () => {
2834
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, title: "\u4E0B\u79FB", onClick: () => {
2356
2835
  edit(withPromptMoved(draft, current.id, prompt.id, 1));
2357
2836
  }, children: "\u2193" }),
2358
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5220\u9664\u8FD9\u6761", onClick: () => {
2837
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, title: "\u5220\u9664\u8FD9\u6761", onClick: () => {
2359
2838
  edit(withPromptRemoved(draft, current.id, prompt.id));
2360
2839
  }, children: "\u2715" })
2361
2840
  ] }),
2362
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2841
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2363
2842
  "textarea",
2364
2843
  {
2365
2844
  value: prompt.prompt,
@@ -2374,7 +2853,7 @@ function QuickPromptsEditor(props) {
2374
2853
  }
2375
2854
  )
2376
2855
  ] }, prompt.id)),
2377
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2856
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2378
2857
  AddPromptRow,
2379
2858
  {
2380
2859
  book: draft,
@@ -2388,8 +2867,8 @@ function QuickPromptsEditor(props) {
2388
2867
  }
2389
2868
  )
2390
2869
  ] }),
2391
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2392
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2870
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2871
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2393
2872
  "button",
2394
2873
  {
2395
2874
  type: "button",
@@ -2411,13 +2890,13 @@ function QuickPromptsEditor(props) {
2411
2890
  children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : dirty ? "\u4FDD\u5B58\u4FEE\u6539" : "\u5DF2\u4FDD\u5B58"
2412
2891
  }
2413
2892
  ),
2414
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2893
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, onClick: () => {
2415
2894
  props.onReload();
2416
2895
  }, children: "\u91CD\u65B0\u8BFB\u53D6" }),
2417
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2896
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: pill, onClick: () => {
2418
2897
  props.onReset();
2419
2898
  }, children: "\u6062\u590D\u5185\u7F6E 9 \u6761" }),
2420
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: rowDesc, children: [
2899
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: rowDesc, children: [
2421
2900
  "\u5171 ",
2422
2901
  counts.categories,
2423
2902
  " \u4E2A\u5206\u7C7B \xB7 ",
@@ -2431,46 +2910,315 @@ function QuickPromptsEditor(props) {
2431
2910
  failed ? ` \xB7 ${props.status}` : ""
2432
2911
  ] })
2433
2912
  ] }),
2434
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: rowDesc, children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: rowDesc, children: [
2435
2914
  "\u6570\u636E\u5B58\u5728 ",
2436
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "~/.dsh/quick-prompts.json" }),
2915
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: "~/.dsh/quick-prompts.json" }),
2437
2916
  "\uFF08\u4E0E\u4F1A\u8BDD\u3001\u9879\u76EE\u65E0\u5173\uFF0C\u53EF\u5355\u72EC\u5907\u4EFD\u6216\u624B\u5DE5\u7F16\u8F91\uFF0C \u6539\u5B8C\u70B9\u300C\u91CD\u65B0\u8BFB\u53D6\u300D\u5373\u53EF\u52A0\u8F7D\uFF09\u3002"
2438
2917
  ] })
2439
2918
  ] });
2440
2919
  }
2441
- function SettingsSection({ useLive, useBook, useBookStatus, actions }) {
2442
- const settings = useLive((item) => item);
2443
- const book = useBook((item) => item);
2444
- const bookStatus = useBookStatus((item) => item);
2445
- const [conflict, setConflict] = (0, import_react4.useState)(null);
2446
- const setKey = (side, chord) => {
2447
- const other = side === "send" ? settings.newlineKey : settings.sendKey;
2448
- if (chord !== "" && chord === other) {
2449
- setConflict(chord);
2450
- return;
2920
+ var candidatePill = {
2921
+ ...pill,
2922
+ textAlign: "left",
2923
+ maxWidth: "100%",
2924
+ overflowWrap: "anywhere",
2925
+ lineHeight: 1.4
2926
+ };
2927
+ function DefaultTerminalBody(props) {
2928
+ const { settings, setField, hideMode = false } = props;
2929
+ const [note, setNote] = (0, import_react4.useState)("");
2930
+ const [busy, setBusy] = (0, import_react4.useState)(false);
2931
+ const candidates = settings.terminalCandidates;
2932
+ if (settings.terminalEffective === "unsupported") {
2933
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\u672C\u63D2\u4EF6\u53EA\u5728 Windows \u4E0A\u63A5\u7BA1\u7EC8\u7AEF\uFF08Windows \u4E0A DSH \u9ED8\u8BA4\u7ED9\u6A21\u578B\u7684\u662F PowerShell\uFF09\u3002\u5F53\u524D\u5E73\u53F0\u4E0D\u9700\u8981\u5B83\uFF0C \u8FD9\u91CC\u7684\u8BBE\u7F6E\u4E0D\u4F1A\u751F\u6548\u3002" });
2934
+ }
2935
+ const discover = async () => {
2936
+ setBusy(true);
2937
+ setNote("");
2938
+ try {
2939
+ const response = await fetch(TERMINAL_API_PATH, { method: "POST" });
2940
+ const parsed = await response.json();
2941
+ const found = sanitizeTerminalCandidates(parsed.candidates);
2942
+ setNote(found.length === 0 ? "\u6CA1\u6709\u627E\u5230\u53EF\u7528\u7684 bash\uFF08WSL \u7684 bash.exe \u4F1A\u88AB\u5FFD\u7565\uFF0C\u5B83\u6309 Linux \u89C4\u5219\u89E3\u91CA\u8DEF\u5F84\uFF09" : `\u627E\u5230 ${String(found.length)} \u4E2A\u5019\u9009\uFF0C\u5DF2\u5217\u5728\u4E0B\u65B9`);
2943
+ } catch (error) {
2944
+ setNote(`\u81EA\u52A8\u53D1\u73B0\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`);
2945
+ } finally {
2946
+ setBusy(false);
2451
2947
  }
2452
- setConflict(null);
2453
- actions.setField(side === "send" ? "sendKey" : "newlineKey", chord);
2454
2948
  };
2455
- const conflictHint = conflict !== null ? `\u300C${displayChord(conflict)}\u300D\u5DF2\u88AB\u53E6\u4E00\u4FA7\u5360\u7528\uFF0C\u8BF7\u5148\u4E3A\u53E6\u4E00\u4FA7\u9009\u62E9\u5176\u5B83\u6309\u952E\u3002` : null;
2456
- const menuEnabled = MENU_ITEMS.filter((item) => settings[item.field]).length;
2457
- const keySummary = `\u53D1\u9001 ${displayChord(settings.sendKey)} \xB7 \u6362\u884C ${displayChord(settings.newlineKey)}`;
2458
- const menuSummary = settings.menuMode === "official" ? "\u5F53\u524D\uFF1A\u5B98\u65B9\u4E0D\u4ECB\u5165" : settings.menuMode === "browser" ? "\u5F53\u524D\uFF1A\u6D4F\u89C8\u5668\u83DC\u5355\uFF08\u7C98\u8D34\u514D\u6388\u6743\uFF09" : `\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49\u83DC\u5355 \xB7 ${menuEnabled} / ${MENU_ITEMS.length} \u9879\u5F00\u542F`;
2459
- const panelSummary = `\u5BFC\u822A\u6EDA\u52A8 ${settings.panelScroll ? "\u5F00" : "\u5173"} \xB7 \u8FB9\u7F18\u7F29\u653E ${settings.panelResize ? "\u5F00" : "\u5173"} \xB7 ${settings.panelWidth}\xD7${settings.panelHeight}`;
2460
- const headerSummary = settings.headerEnabled ? settings.headerStatus === "" ? "\u5DF2\u542F\u7528" : settings.headerStatus : "\u672A\u542F\u7528";
2461
- const quickCounts = bookCounts(book);
2462
- const quickSummary = `${quickCounts.categories} \u4E2A\u5206\u7C7B \xB7 ${quickCounts.prompts} \u6761 \xB7 \u6BCF\u6B21 ${quickCounts.always} \xB7 \u4EC5\u9996\u6B21 ${quickCounts.first} \xB7 \u4F18\u5316\u6863\u4F4D ${OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.label ?? "\u9AD8\u7EA7"}`;
2463
- const headerStatusText = settings.headerEnabled ? settings.headerStatus === "" ? "\u7B49\u5F85\u9996\u6B21\u5199\u5165\u2026" : settings.headerStatus : "\u672A\u542F\u7528\uFF08\u6253\u5F00\u4E0A\u65B9\u5F00\u5173\u5373\u5199\u5165\uFF09";
2464
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { padding: "4px 2px" }, children: [
2465
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "dsh-ux-card", children: [
2466
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-ux-cardHeaderStatic", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2467
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "dsh-ux-cardName", children: "\u8F93\u5165\u4F53\u9A8C" }),
2468
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "dsh-ux-cardDescription", children: "dsh-composer-ux \xB7 \u4E3B\u804A\u5929\u8F93\u5165\u6846\u7684\u952E\u4F4D\u3001\u53F3\u952E\u83DC\u5355\u4E0E\u8BBE\u7F6E\u9762\u677F\uFF1B\u8BBE\u7F6E\u5373\u65F6\u751F\u6548\u5E76\u6301\u4E45\u4FDD\u5B58\u3002" })
2469
- ] }) }),
2470
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-ux-cardBody", children: [
2471
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2472
- ToggleRow,
2473
- {
2949
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2950
+ !hideMode && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
2952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: "\u7EC8\u7AEF\u5DE5\u5177" }),
2953
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: TERMINAL_MODES.find((item) => item.id === settings.terminalMode)?.hint ?? "" })
2954
+ ] }),
2955
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2956
+ PillChoice,
2957
+ {
2958
+ items: TERMINAL_MODES,
2959
+ value: settings.terminalMode,
2960
+ onChange: (mode) => {
2961
+ setField(TERMINAL_MODE_FIELD, mode);
2962
+ },
2963
+ ariaLabel: "\u7EC8\u7AEF\u5DE5\u5177"
2964
+ }
2965
+ )
2966
+ ] }),
2967
+ settings.terminalMode !== "pwsh" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
2968
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2969
+ TextFieldRow,
2970
+ {
2971
+ title: "Git Bash \u8DEF\u5F84",
2972
+ desc: "\u7559\u7A7A = \u7528\u81EA\u52A8\u63A2\u6D4B\u5230\u7684\u90A3\u4E00\u4E2A\uFF08\u5148\u627E git\uFF0C\u518D\u7531\u540C\u4E00\u4E2A\u5B89\u88C5\u53CD\u63A8 bash\uFF09",
2973
+ value: settings.terminalBashPath,
2974
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8",
2975
+ maxLength: 400,
2976
+ onChange: (next) => {
2977
+ setField(TERMINAL_BASH_PATH_FIELD, next);
2978
+ },
2979
+ action: { label: busy ? "\u63A2\u6D4B\u4E2D\u2026" : "\u81EA\u52A8\u53D1\u73B0", onClick: () => {
2980
+ void discover();
2981
+ } }
2982
+ }
2983
+ ),
2984
+ candidates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 2 }, children: candidates.map((candidate) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2985
+ "button",
2986
+ {
2987
+ type: "button",
2988
+ title: candidate.path,
2989
+ style: candidate.path === settings.terminalBashPath ? { ...candidatePill, ...pillActive } : candidatePill,
2990
+ onClick: () => {
2991
+ setField(TERMINAL_BASH_PATH_FIELD, candidate.path);
2992
+ },
2993
+ children: [
2994
+ candidate.label,
2995
+ "\uFF1A",
2996
+ candidate.path,
2997
+ candidate.explicit ? "\uFF08\u4F60\u586B\u7684\uFF09" : ""
2998
+ ]
2999
+ },
3000
+ candidate.path
3001
+ )) }),
3002
+ note !== "" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: note })
3003
+ ] }),
3004
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: hintInfo, children: [
3005
+ "\u72B6\u6001\uFF1A",
3006
+ settings.terminalStatus === "" ? "\u7B49\u5F85\u5BBF\u4E3B\u534A\u63A2\u6D4B\u2026" : settings.terminalStatus
3007
+ ] }),
3008
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\xB7 \u6362\u6210 Git Bash \u540E\uFF0C\u6A21\u578B\u770B\u5230\u7684\u7EC8\u7AEF\u5DE5\u5177\u5C31\u53EB bash\uFF08\u547D\u4EE4\u6309 bash/POSIX \u5199\uFF09\uFF0CPowerShell \u90A3\u4E2A\u5DE5\u5177 \u4F1A\u4ECE\u5B83\u7684\u5DE5\u5177\u5217\u8868\u91CC\u6D88\u5931 \u2014\u2014 \u4E00\u4E2A\u4F1A\u8BDD\u53EA\u9762\u5BF9\u4E00\u4E2A\u7EC8\u7AEF\u5DE5\u5177\u3002" }),
3009
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\xB7 \u6539\u6863\u4F4D\u4F1A\u7ACB\u523B\u91CD\u65B0\u4E0B\u53D1\u7ED9\u6B63\u5728\u8DD1\u7684\u4F1A\u8BDD\u3002\u4F46\u4F1A\u8BDD\u5386\u53F2\u91CC\u53EF\u80FD\u8FD8\u7559\u7740\u65E7\u5DE5\u5177\u540D\uFF1A\u5982\u679C\u54EA\u513F\u62A5\u4E86 unknown tool \u4E4B\u7C7B\u7684\u9519\uFF0C\u8BA9\u6A21\u578B\u6539\u7528 bash \u91CD\u8BD5\u5373\u53EF\uFF0C\u4E0D\u5F71\u54CD\u4F1A\u8BDD\u672C\u8EAB\u3002" }),
3010
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\xB7 \u53EA\u5BF9 Windows \u751F\u6548\uFF1BWSL \u7684 bash.exe \u4F1A\u88AB\u4E3B\u52A8\u6392\u9664\uFF08\u5B83\u628A D:\\ \u8FD9\u7C7B\u8DEF\u5F84\u89E3\u91CA\u6210 /mnt/d\uFF0C\u4E0E\u6A21\u578B\u624B\u91CC\u7684 Windows \u5DE5\u4F5C\u76EE\u5F55\u4E0D\u517C\u5BB9\uFF09\u3002\u6C99\u7BB1\u3001\u5BA1\u6279\u3001\u8D85\u65F6\u4E0E\u8F93\u51FA\u622A\u65AD\u7684\u884C\u4E3A\u4E0E DSH \u81EA\u5E26\u7EC8\u7AEF\u4E00\u81F4\u3002" })
3011
+ ] });
3012
+ }
3013
+ var RESTART_WAIT_MS = 6e4;
3014
+ var RESTART_POLL_MS = 1500;
3015
+ function blockedText(blocked) {
3016
+ if (blocked === "debugger") {
3017
+ return "\u8FD9\u4E2A\u5BBF\u4E3B\u6B63\u88AB\u8C03\u8BD5\u5668\u9644\u7740\uFF1A\u4ECE\u754C\u9762\u91CC\u6740\u6389\u5B83\u53EA\u4F1A\u8FDE\u8C03\u8BD5\u4F1A\u8BDD\u4E00\u8D77\u4E22\u6389\uFF0C\u8BF7\u4ECE IDE \u6216\u7EC8\u7AEF\u505C\u6B62\u5B83\u518D\u542F\u52A8\u3002";
3018
+ }
3019
+ if (blocked.startsWith("supervised:")) {
3020
+ return `\u8FD9\u4E2A\u5BBF\u4E3B\u7531 ${blocked.slice("supervised:".length)} \u5F53\u670D\u52A1\u5728\u8DD1\uFF0C\u91CD\u542F\u8BE5\u5F52\u5B83\u7BA1\uFF08\u5B83\u4F1A\u8FDE\u540C\u6574\u4E2A cgroup \u4E00\u8D77\u6536\u6389\uFF0C\u63D2\u4EF6\u81EA\u5DF1\u91CD\u542F\u53EA\u4F1A\u8BA9\u670D\u52A1\u518D\u4E5F\u8D77\u4E0D\u6765\uFF09\u3002`;
3021
+ }
3022
+ return `\u8FD9\u4E2A\u5BBF\u4E3B\u5F53\u524D\u4E0D\u5141\u8BB8\u4ECE\u754C\u9762\u91CD\u542F\uFF08${blocked}\uFF09\u3002`;
3023
+ }
3024
+ function useRestart() {
3025
+ const [stage, setStage] = (0, import_react4.useState)("idle");
3026
+ const [detail, setDetail] = (0, import_react4.useState)("");
3027
+ const [blocked, setBlocked] = (0, import_react4.useState)(null);
3028
+ const readFacts = async () => {
3029
+ const response = await fetch(RESTART_API_PATH, { cache: "no-store" });
3030
+ if (!response.ok) return { error: `HTTP ${String(response.status)}` };
3031
+ const parsed = await response.json();
3032
+ return {
3033
+ running: typeof parsed.running === "number" ? parsed.running : 0,
3034
+ command: typeof parsed.command === "string" ? parsed.command : "",
3035
+ logHint: typeof parsed.logHint === "string" ? parsed.logHint : "",
3036
+ blocked: typeof parsed.blocked === "string" ? parsed.blocked : null,
3037
+ boot: typeof parsed.boot === "string" ? parsed.boot : null
3038
+ };
3039
+ };
3040
+ const awaitNewBoot = async (previousBoot, logHint) => {
3041
+ const deadline = Date.now() + RESTART_WAIT_MS;
3042
+ while (Date.now() < deadline) {
3043
+ await new Promise((done) => {
3044
+ setTimeout(done, RESTART_POLL_MS);
3045
+ });
3046
+ try {
3047
+ const facts = await readFacts();
3048
+ if ("error" in facts) continue;
3049
+ if (facts.boot !== null && facts.boot !== previousBoot) {
3050
+ location.reload();
3051
+ return;
3052
+ }
3053
+ } catch {
3054
+ }
3055
+ }
3056
+ setStage("failed");
3057
+ setDetail("\u7B49\u4E86 60 \u79D2\u4E5F\u6CA1\u7B49\u5230\u65B0\u8FDB\u7A0B\u3002\u8BF7\u624B\u52A8\u8FD0\u884C restart-webui.bat \u91CD\u542F\u4E00\u6B21\u3002" + (logHint === "" ? "" : `\u5BBF\u4E3B\u534A\u7684\u8BCA\u65AD\u65E5\u5FD7\u5728 ${logHint}\u3002`));
3058
+ };
3059
+ const ask = () => {
3060
+ setStage("asking");
3061
+ setDetail("\u6B63\u5728\u8BFB\u53D6\u91CD\u542F\u65B9\u5F0F\u2026");
3062
+ void (async () => {
3063
+ try {
3064
+ const facts = await readFacts();
3065
+ if ("error" in facts) {
3066
+ setStage("failed");
3067
+ setDetail(`\u8BFB\u4E0D\u5230\u91CD\u542F\u72B6\u6001\uFF08${facts.error}\uFF09\u2014\u2014 \u5BBF\u4E3B\u534A\u53EF\u80FD\u8FD8\u6CA1\u6362\u5230\u5E26\u8FD9\u6761\u8DEF\u7531\u7684\u7248\u672C\uFF0C\u8BF7\u5148\u624B\u52A8\u8FD0\u884C\u4E00\u6B21 restart-webui.bat\u3002`);
3068
+ return;
3069
+ }
3070
+ setBlocked(facts.blocked);
3071
+ if (facts.blocked !== null) {
3072
+ setStage("failed");
3073
+ setDetail(blockedText(facts.blocked));
3074
+ return;
3075
+ }
3076
+ setStage("asking");
3077
+ setDetail((facts.boot === null ? "\u5BBF\u4E3B\u534A\u8FD8\u662F\u4E0A\u4E00\u7248\uFF1A\u8FD9\u6B21\u91CD\u542F\u4F1A\u8D70\u65E7\u673A\u5236\uFF08\u5199\u811A\u672C + \u81EA\u5DF1\u9000\u51FA\uFF09\uFF0C\u91CD\u542F\u4E4B\u540E\u6309\u94AE\u5C31\u662F\u65B0\u7248\u4E86\u3002" : `\u91CD\u542F\u65B9\u5F0F\uFF1A${facts.command}\u3002`) + `\u5F53\u524D\u6709 ${String(facts.running)} \u4E2A\u4F1A\u8BDD\u5728\u8DD1 \u2014\u2014 \u91CD\u542F\u4F1A\u6253\u65AD\u5B83\u4EEC\uFF08\u5305\u62EC\u6B63\u5728\u751F\u6210\u7684\u90A3\u4E00\u8F6E\uFF09\u3002`);
3078
+ } catch (error) {
3079
+ setStage("failed");
3080
+ setDetail(`\u8BFB\u4E0D\u5230\u91CD\u542F\u72B6\u6001\uFF1A${error instanceof Error ? error.message : String(error)}`);
3081
+ }
3082
+ })();
3083
+ };
3084
+ const confirm = () => {
3085
+ setStage("restarting");
3086
+ setDetail("\u5DF2\u53D1\u51FA\u91CD\u542F\u8BF7\u6C42 \u2014\u2014 \u6B63\u5728\u7B49\u65B0\u8FDB\u7A0B\u8D77\u6765\uFF08\u8FD9\u4E2A\u9875\u9762\u4F1A\u81EA\u5DF1\u56DE\u6765\uFF09\u2026");
3087
+ void (async () => {
3088
+ let previousBoot = null;
3089
+ let logHint = "";
3090
+ try {
3091
+ const before = await readFacts();
3092
+ if (!("error" in before)) {
3093
+ previousBoot = before.boot;
3094
+ logHint = before.logHint;
3095
+ }
3096
+ } catch {
3097
+ }
3098
+ try {
3099
+ const response = await fetch(RESTART_API_PATH, {
3100
+ method: "POST",
3101
+ headers: { "content-type": "application/json" },
3102
+ body: "{}"
3103
+ });
3104
+ const parsed = await response.json();
3105
+ if (response.status !== 202 && parsed.ok !== true) {
3106
+ setStage("failed");
3107
+ setDetail(`\u91CD\u542F\u6CA1\u6210\u529F\uFF1A${parsed.error ?? `HTTP ${String(response.status)}`} \u2014\u2014 \u8BF7\u624B\u52A8\u8FD0\u884C restart-webui.bat\u3002`);
3108
+ return;
3109
+ }
3110
+ } catch {
3111
+ }
3112
+ await awaitNewBoot(previousBoot, logHint);
3113
+ })();
3114
+ };
3115
+ const cancel = () => {
3116
+ setStage("idle");
3117
+ setDetail("");
3118
+ };
3119
+ return { stage, detail, blocked, ask, confirm, cancel };
3120
+ }
3121
+ function RestartButton({ restart }) {
3122
+ const busy = restart.stage === "restarting" || restart.stage === "asking";
3123
+ const blocked = restart.blocked;
3124
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3125
+ "button",
3126
+ {
3127
+ type: "button",
3128
+ className: "dsh-ux-restartButton",
3129
+ disabled: busy || blocked !== null,
3130
+ title: blocked === null ? "\u91CD\u542F DSH\uFF1A\u8BA9\u5BBF\u4E3B\u534A\u7684\u65B0\u4EE3\u7801\uFF08\u9ED8\u8BA4\u7EC8\u7AEF\u3001\u952E\u4F4D schema\uFF09\u751F\u6548\u3002\u70B9\u4E00\u4E0B\u4F1A\u5148\u8BA9\u4F60\u786E\u8BA4\u4E00\u6B21\u3002" : blockedText(blocked),
3131
+ onClick: () => {
3132
+ restart.ask();
3133
+ },
3134
+ children: restart.stage === "restarting" ? "\u91CD\u542F\u4E2D\u2026" : "\u91CD\u542F DSH"
3135
+ }
3136
+ );
3137
+ }
3138
+ function RestartBanner({ restart }) {
3139
+ if (restart.stage === "idle") return null;
3140
+ const failed = restart.stage === "failed";
3141
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: failed ? "dsh-ux-restartBanner dsh-ux-restartBannerFailed" : "dsh-ux-restartBanner", children: [
3142
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-restartBannerText", children: restart.detail }),
3143
+ restart.stage === "asking" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-restartBannerActions", children: [
3144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-ux-restartGo", onClick: () => {
3145
+ restart.confirm();
3146
+ }, children: "\u786E\u8BA4\u91CD\u542F" }),
3147
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-ux-restartCancel", onClick: () => {
3148
+ restart.cancel();
3149
+ }, children: "\u53D6\u6D88" })
3150
+ ] }),
3151
+ failed && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-restartBannerActions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-ux-restartCancel", onClick: () => {
3152
+ restart.cancel();
3153
+ }, children: "\u77E5\u9053\u4E86" }) })
3154
+ ] });
3155
+ }
3156
+ function SettingsSection({ useLive, useBook, useBookStatus, useWriteNotice, actions }) {
3157
+ const settings = useLive((item) => item);
3158
+ const book = useBook((item) => item);
3159
+ const bookStatus = useBookStatus((item) => item);
3160
+ const writeNotice = useWriteNotice((item) => item);
3161
+ const [conflict, setConflict] = (0, import_react4.useState)(null);
3162
+ const restart = useRestart();
3163
+ const sections = activeSections(settings);
3164
+ const setKey = (side, chord) => {
3165
+ const other = side === "send" ? settings.newlineKey : settings.sendKey;
3166
+ if (chord !== "" && chord === other) {
3167
+ setConflict(chord);
3168
+ return;
3169
+ }
3170
+ setConflict(null);
3171
+ actions.setField(side === "send" ? "sendKey" : "newlineKey", chord);
3172
+ };
3173
+ const conflictHint = conflict !== null ? `\u300C${displayChord(conflict)}\u300D\u5DF2\u88AB\u53E6\u4E00\u4FA7\u5360\u7528\uFF0C\u8BF7\u5148\u4E3A\u53E6\u4E00\u4FA7\u9009\u62E9\u5176\u5B83\u6309\u952E\u3002` : null;
3174
+ const menuEnabled = MENU_ITEMS.filter((item) => settings[item.field]).length;
3175
+ const keySummary = `\u53D1\u9001 ${displayChord(settings.sendKey)} \xB7 \u6362\u884C ${displayChord(settings.newlineKey)}`;
3176
+ const menuSummary = settings.menuMode === "official" ? "\u5F53\u524D\uFF1A\u5B98\u65B9\u4E0D\u4ECB\u5165" : settings.menuMode === "browser" ? "\u5F53\u524D\uFF1A\u6D4F\u89C8\u5668\u83DC\u5355\uFF08\u7C98\u8D34\u514D\u6388\u6743\uFF09" : `\u5F53\u524D\uFF1A\u81EA\u5B9A\u4E49\u83DC\u5355 \xB7 ${menuEnabled} / ${MENU_ITEMS.length} \u9879\u5F00\u542F`;
3177
+ const panelSummary = `\u8FB9\u7F18\u7F29\u653E ${settings.panelResize ? "\u5F00" : "\u5173"} \xB7 ${settings.panelWidth}\xD7${settings.panelHeight}`;
3178
+ const headerSummary = settings.headerEnabled ? settings.headerStatus === "" ? "\u5DF2\u542F\u7528" : settings.headerStatus : "\u672A\u542F\u7528";
3179
+ const quickCounts = bookCounts(book);
3180
+ const quickSummary = `${quickCounts.categories} \u4E2A\u5206\u7C7B \xB7 ${quickCounts.prompts} \u6761 \xB7 \u6BCF\u6B21 ${quickCounts.always} \xB7 \u4EC5\u9996\u6B21 ${quickCounts.first} \xB7 \u4F18\u5316\u6863\u4F4D ${OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.label ?? "\u9AD8\u7EA7"}`;
3181
+ const headerStatusText = settings.headerEnabled ? settings.headerStatus === "" ? "\u7B49\u5F85\u9996\u6B21\u5199\u5165\u2026" : settings.headerStatus : "\u672A\u542F\u7528\uFF08\u6253\u5F00\u4E0A\u65B9\u5F00\u5173\u5373\u5199\u5165\uFF09";
3182
+ const terminalSummary = sections.terminal === false ? settings.terminalMode === "pwsh" ? "\u4FDD\u6301 PowerShell" : "\u6253\u5F00\u540E\u63A5\u7BA1\u7EC8\u7AEF" : settings.terminalEffective === "unsupported" ? "\u975E Windows\uFF1A\u4E0D\u9700\u8981" : settings.terminalMode === "pwsh" ? "\u5F53\u524D\uFF1A\u4FDD\u6301 PowerShell" : settings.terminalEffective === "bash" ? "\u5F53\u524D\uFF1AGit Bash" : "\u5F53\u524D\uFF1APowerShell\uFF08\u672A\u63A5\u7BA1\uFF09";
3183
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { padding: "4px 2px" }, children: [
3184
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-ux-card", children: [
3185
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-ux-cardHeaderStatic", children: [
3186
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
3187
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { className: "dsh-ux-cardName", children: "\u8F93\u5165\u4F53\u9A8C" }),
3188
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dsh-ux-cardDescription", children: "dsh-composer-ux \xB7 \u4E3B\u804A\u5929\u8F93\u5165\u6846\u7684\u952E\u4F4D\u3001\u53F3\u952E\u83DC\u5355\u4E0E\u8BBE\u7F6E\u9762\u677F\uFF1B\u8BBE\u7F6E\u5373\u65F6\u751F\u6548\u5E76\u6301\u4E45\u4FDD\u5B58\u3002" })
3189
+ ] }),
3190
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-cardActions", children: [
3191
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RestartButton, { restart }),
3192
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3193
+ "a",
3194
+ {
3195
+ className: "dsh-ux-cardLink",
3196
+ href: REPO_URL,
3197
+ target: "_blank",
3198
+ rel: "noreferrer noopener",
3199
+ title: "\u5728 GitHub \u4E0A\u67E5\u770B\u8FD9\u4E2A\u63D2\u4EF6\uFF08\u65B0\u6807\u7B7E\u6253\u5F00\uFF09",
3200
+ children: [
3201
+ "GitHub ",
3202
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\u2197" })
3203
+ ]
3204
+ }
3205
+ )
3206
+ ] })
3207
+ ] }),
3208
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RestartBanner, { restart }),
3209
+ writeNotice !== "" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-ux-restartBanner dsh-ux-restartBannerFailed", role: "status", children: [
3210
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-ux-restartBannerText", children: [
3211
+ "\u8BBE\u7F6E\u672A\u751F\u6548\uFF1A",
3212
+ writeNotice
3213
+ ] }),
3214
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-ux-restartBannerActions", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-ux-restartCancel", onClick: () => {
3215
+ actions.dismissNotice();
3216
+ }, children: "\u77E5\u9053\u4E86" }) })
3217
+ ] }),
3218
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-ux-cardBody", children: [
3219
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3220
+ ToggleRow,
3221
+ {
2474
3222
  first: true,
2475
3223
  label: "\u542F\u7528\u8F93\u5165\u589E\u5F3A",
2476
3224
  desc: "\u5173\u95ED\u540E\u952E\u4F4D\u3001\u53F3\u952E\u83DC\u5355\u4E0E\u8BBE\u7F6E\u9762\u677F\u6EDA\u52A8/\u7F29\u653E\u5168\u90E8\u505C\u7528\uFF08\u672C\u9875\u4FDD\u7559\u7528\u4E8E\u91CD\u65B0\u5F00\u542F\uFF09",
@@ -2480,293 +3228,385 @@ function SettingsSection({ useLive, useBook, useBookStatus, actions }) {
2480
3228
  }
2481
3229
  }
2482
3230
  ),
2483
- !settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\u5DF2\u505C\u7528\uFF1A\u53D1\u9001/\u6362\u884C\u952E\u4F4D\u3001\u53F3\u952E\u83DC\u5355\u3001\u8BBE\u7F6E\u9762\u677F\u6EDA\u52A8\u4E0E\u8FB9\u7F18\u7F29\u653E\u5747\u4E0D\u518D\u751F\u6548\uFF0C\u8F93\u5165\u6846\u6062\u590D DSH \u539F\u751F\u884C\u4E3A\u3002 \u6253\u5F00\u4E0A\u65B9\u5F00\u5173\u5373\u53EF\u4E00\u952E\u6062\u590D\uFF1B\u6240\u6709\u8BBE\u7F6E\u503C\u4ECD\u4FDD\u7559\u3002" })
3231
+ !settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\u5DF2\u505C\u7528\uFF1A\u53D1\u9001/\u6362\u884C\u952E\u4F4D\u3001\u53F3\u952E\u83DC\u5355\u3001\u8BBE\u7F6E\u9762\u677F\u6EDA\u52A8\u4E0E\u8FB9\u7F18\u7F29\u653E\u5747\u4E0D\u518D\u751F\u6548\uFF0C\u8F93\u5165\u6846\u6062\u590D DSH \u539F\u751F\u884C\u4E3A\u3002 \u6253\u5F00\u4E0A\u65B9\u5F00\u5173\u5373\u53EF\u4E00\u952E\u6062\u590D\uFF1B\u6240\u6709\u8BBE\u7F6E\u503C\u4ECD\u4FDD\u7559\u3002" })
2484
3232
  ] })
2485
3233
  ] }),
2486
- settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2487
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(FoldCard, { name: "\u952E\u4F4D", summary: keySummary, children: [
2488
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: bodyLead, children: "\u652F\u6301\u5E38\u7528\u9884\u8BBE\uFF0C\u4E5F\u53EF\u4EE5\u70B9\u51FB\u300C\u81EA\u5B9A\u4E49\u2026\u300D\u540E\u76F4\u63A5\u6309\u4E0B\u4EFB\u610F\u7EC4\u5408\u952E\u5F55\u5236\uFF08Esc \u53D6\u6D88\uFF0CBackspace \u6E05\u9664\uFF09\u3002 \u672A\u7ED1\u5B9A\u7684 Enter \u7CFB\u6309\u952E\u4E0D\u4F1A\u89E6\u53D1\u53D1\u9001\u6216\u6362\u884C\uFF1BCtrl+Enter / \u2318+Enter \u672A\u88AB\u7ED1\u5B9A\u65F6\u4FDD\u7559\u539F\u300C\u52A0\u901F\u63D0\u4EA4\u300D\u884C\u4E3A\uFF1B \u4E2D\u6587\u8F93\u5165\u6CD5\u7EC4\u5408\u671F\u95F4\u4E0D\u53D7\u5F71\u54CD\u3002" }),
2489
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2490
- KeyRow,
2491
- {
2492
- first: true,
2493
- title: "\u53D1\u9001\u952E",
2494
- desc: "\u6309\u4E0B\u540E\u53D1\u9001\u5F53\u524D\u8F93\u5165",
2495
- value: settings.sendKey,
2496
- presets: SEND_PRESETS,
2497
- conflict: (chord) => chord !== "" && chord === settings.newlineKey,
2498
- onChange: (chord) => {
2499
- setKey("send", chord);
2500
- }
2501
- }
2502
- ),
2503
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2504
- KeyRow,
2505
- {
2506
- title: "\u6362\u884C\u952E",
2507
- desc: "\u6309\u4E0B\u540E\u5728\u8F93\u5165\u5185\u6362\u884C",
2508
- value: settings.newlineKey,
2509
- presets: NEWLINE_PRESETS,
2510
- conflict: (chord) => chord !== "" && chord === settings.sendKey,
2511
- onChange: (chord) => {
2512
- setKey("newline", chord);
2513
- }
2514
- }
2515
- ),
2516
- conflictHint !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintError, children: conflictHint }),
2517
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2518
- "button",
2519
- {
2520
- type: "button",
2521
- style: pill,
2522
- onClick: () => {
2523
- setConflict(null);
2524
- actions.resetAll();
2525
- },
2526
- children: "\u6062\u590D\u9ED8\u8BA4"
2527
- }
2528
- ) })
2529
- ] }),
2530
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(FoldCard, { name: "\u53F3\u952E\u83DC\u5355", summary: menuSummary, children: [
2531
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: bodyLead, children: "\u53F3\u952E\u70B9\u51FB\u8F93\u5165\u6846\u65F6\u5F39\u51FA\u54EA\u4E00\u79CD\u83DC\u5355\u3002\u53EA\u5F71\u54CD\u53F3\u952E\uFF0C\u4E0D\u5F71\u54CD\u952E\u4F4D\u4E0E\u5176\u5B83\u529F\u80FD\u3002" }),
2532
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2533
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2534
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u83DC\u5355\u6765\u6E90" }),
2535
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: MENU_MODES.find((item) => item.id === settings.menuMode)?.hint ?? "" })
2536
- ] }),
2537
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2538
- PillChoice,
2539
- {
2540
- items: MENU_MODES,
2541
- value: settings.menuMode,
2542
- onChange: (mode) => {
2543
- actions.setField(MENU_MODE_FIELD, mode);
2544
- },
2545
- ariaLabel: "\u53F3\u952E\u83DC\u5355\u6765\u6E90"
3234
+ settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3235
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3236
+ FoldCard,
3237
+ {
3238
+ name: "\u952E\u4F4D",
3239
+ summary: keySummary,
3240
+ toggle: {
3241
+ checked: sections.keys,
3242
+ onChange: (next) => {
3243
+ actions.setField(KEYS_ENABLED_FIELD, next);
2546
3244
  }
2547
- )
2548
- ] }),
2549
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\u5B98\u65B9\uFF1A\u672C\u63D2\u4EF6\u5B8C\u5168\u4E0D\u4ECB\u5165\uFF0CDSH \u4E0E\u5176\u5B83\u63D2\u4EF6\u81EA\u5DF1\u7684\u53F3\u952E\u5904\u7406\u539F\u6837\u751F\u6548\uFF08DSH \u5B98\u65B9\u8F93\u5165\u6846\u672C\u8EAB\u6CA1\u6709 \u53F3\u952E\u83DC\u5355\uFF0C\u6240\u4EE5\u901A\u5E38\u770B\u5230\u7684\u5C31\u662F\u6D4F\u89C8\u5668\u7684\u83DC\u5355\uFF09\u3002" }),
2550
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\u6D4F\u89C8\u5668\uFF1A\u56FA\u5B9A\u7528\u6D4F\u89C8\u5668\u81EA\u5E26\u7684\u83DC\u5355\uFF08\u6837\u5B50\u968F\u6D4F\u89C8\u5668\u800C\u53D8\uFF09\uFF0C\u5E76\u5728\u672C\u63D2\u4EF6\u8FD9\u4E00\u5C42\u6321\u4F4F\u5176\u5B83\u63D2\u4EF6\u7684\u83DC\u5355\uFF1B \u597D\u5904\u662F\u7C98\u8D34\u514D\u6388\u6743\u3001\u96F6\u914D\u7F6E\u3002" }),
2551
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\u81EA\u5B9A\u4E49\uFF1A\u7528\u672C\u63D2\u4EF6\u56FA\u5B9A\u6837\u5F0F\u7684\u83DC\u5355\uFF08\u672A\u9009\u4E2D\u6587\u672C\u65F6\u300C\u526A\u5207 / \u590D\u5236 / \u5220\u9664\u300D\u7F6E\u7070\uFF09\u3002\u8FD9\u4E00\u6863\u7684\u300C\u7C98\u8D34\u300D \u8981\u8BFB\u526A\u8D34\u677F\uFF0C\u6D4F\u89C8\u5668\u4F1A\u5148\u8981\u4E00\u6B21\u6388\u6743\u2014\u2014\u4E09\u5BB6\u6D4F\u89C8\u5668\u7684\u5904\u7406\u4E0D\u4E00\u6837\uFF1A" }),
2552
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\xB7 Chrome / Edge\uFF08\u8C37\u6B4C / \u5FAE\u8F6F\u6D4F\u89C8\u5668\uFF09\uFF1A\u5F39\u51FA\u540E\u70B9\u300C\u5141\u8BB8\u300D\u5373\u53EF\uFF0C\u4E4B\u540E\u4F1A\u8BB0\u4F4F\u8FD9\u4E2A\u7AD9\u70B9\u3001\u4E0D\u518D\u95EE\u3002 \u8981\u6539\u6216\u64A4\u9500\u6388\u6743\uFF1A\u70B9\u5730\u5740\u680F\u6700\u5DE6\u8FB9\u7684\u7F51\u7AD9\u56FE\u6807 \u2192 \u7F51\u7AD9\u8BBE\u7F6E\uFF08Edge \u53EB\u300C\u6B64\u7AD9\u70B9\u7684\u6743\u9650\u300D\uFF09\u2192 \u526A\u8D34\u677F\uFF1B \u4E5F\u53EF\u4EE5\u76F4\u63A5\u5728\u5730\u5740\u680F\u8F93\u5165 chrome://settings/content/clipboard\uFF08Edge \u8F93\u5165 edge://settings/content/clipboard\uFF09\u3002" }),
2553
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\xB7 Firefox\uFF1A\u4E0D\u5141\u8BB8\u7F51\u9875\u9759\u9ED8\u8BFB\u526A\u8D34\u677F\u2014\u2014\u4F60\u70B9\u672C\u63D2\u4EF6\u7684\u300C\u7C98\u8D34\u300D\u540E\uFF0C\u5B83\u4F1A\u5148\u5F39\u4E00\u4E2A\u53EA\u6709\u300C\u7C98\u8D34(P)\u300D \u4E00\u9879\u7684\u5C0F\u7A97\uFF08\u7EA6 1 \u79D2\u540E\u624D\u53EF\u70B9\uFF09\uFF0C\u70B9\u5B83\u624D\u5B8C\u6210\u8FD9\u6B21\u7C98\u8D34\u3002\u8FD9\u662F Firefox \u7684\u5B89\u5168\u673A\u5236\uFF0C\u63D2\u4EF6\u5173\u4E0D\u6389 \uFF08\u5B9E\u6D4B\uFF1Aabout:config \u91CC\u7684\u526A\u8D34\u677F\u9996\u9009\u9879\u5BF9\u5B83\u65E0\u6548\uFF09\u3002\u4E0D\u60F3\u591A\u8FD9\u4E00\u6B65\u5C31\u76F4\u63A5\u6309 Ctrl+V\uFF0C \u6216\u628A\u4E0A\u9762\u7684\u300C\u83DC\u5355\u6765\u6E90\u300D\u6362\u6210\u300C\u6D4F\u89C8\u5668 / \u5B98\u65B9\u300D\u6863\u2014\u2014\u90A3\u4E24\u6863\u7528\u7684\u662F\u6D4F\u89C8\u5668\u81EA\u5DF1\u7684\u7C98\u8D34\u3002" }),
2554
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: "\u6CE8\u610F\uFF1Achrome://\u3001edge:// \u8FD9\u4E9B\u5730\u5740\u6D4F\u89C8\u5668\u4E0D\u5141\u8BB8\u505A\u6210\u7F51\u9875\u91CC\u7684\u94FE\u63A5\uFF0C\u53EA\u80FD\u624B\u8F93\uFF0C \u6216\u590D\u5236\u4E0A\u9762\u90A3\u4E32\u7C98\u8D34\u5230\u5730\u5740\u680F\u3002" }),
2555
- settings.menuMode === "custom" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2556
- MENU_ITEMS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2557
- ToggleRow,
2558
- {
2559
- label: item.label,
2560
- desc: item.shortcut !== "" ? `\u5FEB\u6377\u952E ${item.shortcut}` : "",
2561
- checked: settings[item.field],
2562
- onChange: (next) => {
2563
- actions.setField(item.field, next);
3245
+ },
3246
+ children: [
3247
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: bodyLead, children: "\u652F\u6301\u5E38\u7528\u9884\u8BBE\uFF0C\u4E5F\u53EF\u4EE5\u70B9\u51FB\u300C\u81EA\u5B9A\u4E49\u2026\u300D\u540E\u76F4\u63A5\u6309\u4E0B\u4EFB\u610F\u7EC4\u5408\u952E\u5F55\u5236\uFF08Esc \u53D6\u6D88\uFF0CBackspace \u6E05\u9664\uFF09\u3002 \u672A\u7ED1\u5B9A\u7684 Enter \u7CFB\u6309\u952E\u4E0D\u4F1A\u89E6\u53D1\u53D1\u9001\u6216\u6362\u884C\uFF1BCtrl+Enter / \u2318+Enter \u672A\u88AB\u7ED1\u5B9A\u65F6\u4FDD\u7559\u539F\u300C\u52A0\u901F\u63D0\u4EA4\u300D\u884C\u4E3A\uFF1B \u4E2D\u6587\u8F93\u5165\u6CD5\u7EC4\u5408\u671F\u95F4\u4E0D\u53D7\u5F71\u54CD\u3002" }),
3248
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3249
+ KeyRow,
3250
+ {
3251
+ first: true,
3252
+ title: "\u53D1\u9001\u952E",
3253
+ desc: "\u6309\u4E0B\u540E\u53D1\u9001\u5F53\u524D\u8F93\u5165",
3254
+ value: settings.sendKey,
3255
+ presets: SEND_PRESETS,
3256
+ conflict: (chord) => chord !== "" && chord === settings.newlineKey,
3257
+ onChange: (chord) => {
3258
+ setKey("send", chord);
3259
+ }
2564
3260
  }
2565
- },
2566
- item.field
2567
- )),
2568
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2569
- "button",
2570
- {
2571
- type: "button",
2572
- style: pill,
2573
- onClick: () => {
2574
- for (const item of MENU_ITEMS) actions.setField(item.field, true);
2575
- },
2576
- children: "\u5168\u90E8\u5F00\u542F"
2577
- }
2578
- ) })
2579
- ] })
2580
- ] }),
2581
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(FoldCard, { name: "\u5FEB\u6377\u6307\u4EE4", summary: quickSummary, children: [
2582
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: bodyLead, children: [
2583
- "\u8F93\u5165\u6846\u5DE5\u5177\u884C\u91CC\u90A3\u4E2A\u300C\u5FEB\u6377\u6307\u4EE4\u300D\u6309\u94AE\u70B9\u5F00\u5C31\u662F\u8FD9\u5F20\u6E05\u5355\uFF1A\u70B9\u6761\u76EE\u628A\u5185\u5BB9\u63D2\u5165\u8F93\u5165\u6846\u3002 \u6BCF\u6761\u53F3\u4FA7\u7684\u4E09\u9009\u4E00\u51B3\u5B9A",
2584
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u53D1\u9001\u65F6\u600E\u4E48\u9644\u52A0" }),
2585
- "\uFF1A \u300C\u5173\u300D= \u53EA\u63D2\u5165\u4E0D\u9644\u52A0\uFF1B\u300C\u6BCF\u6B21\u300D= \u6BCF\u6B21\u53D1\u9001\u90FD\u9644\u52A0\u5230\u6D88\u606F",
2586
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u672B\u5C3E" }),
2587
- "\uFF1B \u300C\u4EC5\u9996\u6B21\u300D= \u53EA\u5728",
2588
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u8FD9\u4E2A\u4F1A\u8BDD\u7684\u7B2C\u4E00\u6761\u6D88\u606F" }),
2589
- "\u4E0A\u9644\u52A0\uFF08\u4E4B\u540E\u4E0D\u518D\u9644\u52A0\uFF0C\u5237\u65B0\u9875\u9762\u4E5F\u4E0D\u4F1A\u91CD\u590D\uFF09\u3002 \u591A\u6761\u6309\u5217\u8868\u987A\u5E8F\u62FC\u63A5\uFF0C\u8F93\u5165\u6846\u91CC\u4E0D\u63D0\u524D\u663E\u793A\u3002 \u300C\u4F18\u5316\u63D0\u793A\u8BCD\u300D\u4F1A\u7528\u53E6\u4E00\u4E2A AI \u628A\u8F93\u5165\u6846\u91CC\u7684\u8BDD\u6574\u7406\u6210\u4E00\u6761\u80FD\u76F4\u63A5\u53D1\u51FA\u53BB\u7684\u6E05\u6670\u6307\u4EE4\uFF0C \u7ED3\u679C\u76F4\u63A5\u5199\u56DE\u8F93\u5165\u6846\uFF08Ctrl+Z \u53EF\u8FD8\u539F\uFF09\u2014\u2014\u4E0D\u4F1A\u6C61\u67D3\u5F53\u524D\u5BF9\u8BDD\uFF0C\u4E5F\u4E0D\u5360\u4F60\u7684\u5BF9\u8BDD\u8F6E\u6B21\u3002"
2590
- ] }),
2591
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2592
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2593
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u4F18\u5316\u5F3A\u5EA6" }),
2594
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.hint ?? "" })
2595
- ] }),
2596
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2597
- "button",
2598
- {
2599
- type: "button",
2600
- title: item.hint,
2601
- style: settings.optimizerTier === item.id ? pillActive : pill,
2602
- onClick: () => {
2603
- actions.setField(OPTIMIZER_TIER_FIELD, item.id);
2604
- },
2605
- children: item.label
2606
- },
2607
- item.id
2608
- )) })
2609
- ] }),
2610
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2611
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2612
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u5FEB\u6377\u6307\u4EE4\u6E05\u5355" }),
2613
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: "\u5206\u7C7B\u5728\u8FD9\u91CC\u7BA1\u7406\uFF08\u9762\u677F\u91CC\u53EA\u505A\u5207\u6362\uFF09\uFF1B\u5185\u7F6E 9 \u6761\u53EF\u4EE5\u76F4\u63A5\u7528\uFF0C\u6539\u5B8C\u8BB0\u5F97\u70B9\u300C\u4FDD\u5B58\u4FEE\u6539\u300D\u3002" })
2614
- ] }),
2615
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2616
- QuickPromptsEditor,
2617
- {
2618
- book,
2619
- status: bookStatus,
2620
- onSave: (next) => {
2621
- actions.saveBook(next);
2622
- },
2623
- onReload: () => {
2624
- actions.reloadBook();
2625
- },
2626
- onReset: () => {
2627
- actions.resetBook();
3261
+ ),
3262
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3263
+ KeyRow,
3264
+ {
3265
+ title: "\u6362\u884C\u952E",
3266
+ desc: "\u6309\u4E0B\u540E\u5728\u8F93\u5165\u5185\u6362\u884C",
3267
+ value: settings.newlineKey,
3268
+ presets: NEWLINE_PRESETS,
3269
+ conflict: (chord) => chord !== "" && chord === settings.sendKey,
3270
+ onChange: (chord) => {
3271
+ setKey("newline", chord);
3272
+ }
2628
3273
  }
2629
- }
2630
- )
2631
- ] })
2632
- ] }),
2633
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(FoldCard, { name: "\u8BBE\u7F6E\u9762\u677F", summary: panelSummary, children: [
2634
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: bodyLead, children: "\u63D2\u4EF6\u88C5\u5F97\u591A\u65F6\u8BBE\u7F6E\u6761\u76EE\u5F88\u957F\uFF1A\u5F00\u542F\u300C\u5BFC\u822A\u53EF\u6EDA\u52A8\u300D\u540E\uFF0C\u5DE6\u4FA7\u5BFC\u822A\u5728\u6EA2\u51FA\u65F6\u4F1A\u51FA\u73B0\u6EDA\u52A8\u6761\u3002 \u5F00\u542F\u300C\u8FB9\u7F18\u8C03\u6574\u5927\u5C0F\u300D\u540E\uFF0C\u628A\u9F20\u6807\u79FB\u5230\u8BBE\u7F6E\u9762\u677F\u7684\u8FB9\u6216\u89D2\u4E0A\uFF08\u51FA\u73B0\u9AD8\u4EAE\u6216\u5149\u6807\u53D8\u5316\uFF09\u62D6\u52A8\u5373\u53EF\u6539\u53D8\u9762\u677F\u5927\u5C0F\uFF0C \u5C3A\u5BF8\u4F1A\u8BB0\u4F4F\uFF0C\u4E0B\u6B21\u6253\u5F00\u4FDD\u6301\u3002" }),
2635
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2636
- ToggleRow,
2637
- {
2638
- first: true,
2639
- label: "\u5BFC\u822A\u53EF\u6EDA\u52A8",
2640
- desc: "\u8BBE\u7F6E\u6761\u76EE\u8D85\u51FA\u9762\u677F\u9AD8\u5EA6\u65F6\u663E\u793A\u6EDA\u52A8\u6761",
2641
- checked: settings.panelScroll,
3274
+ ),
3275
+ conflictHint !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintError, children: conflictHint }),
3276
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3277
+ "button",
3278
+ {
3279
+ type: "button",
3280
+ style: pill,
3281
+ onClick: () => {
3282
+ setConflict(null);
3283
+ actions.resetAll();
3284
+ },
3285
+ children: "\u6062\u590D\u9ED8\u8BA4"
3286
+ }
3287
+ ) })
3288
+ ]
3289
+ }
3290
+ ),
3291
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3292
+ FoldCard,
3293
+ {
3294
+ name: "\u53F3\u952E\u83DC\u5355",
3295
+ summary: menuSummary,
3296
+ toggle: {
3297
+ checked: sections.menu,
2642
3298
  onChange: (next) => {
2643
- actions.setField(PANEL_SCROLL_FIELD, next);
3299
+ actions.setField(MENU_ENABLED_FIELD, next);
2644
3300
  }
2645
- }
2646
- ),
2647
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2648
- ToggleRow,
2649
- {
2650
- label: "\u8FB9\u7F18\u8C03\u6574\u5927\u5C0F",
2651
- desc: "\u62D6\u52A8\u9762\u677F\u56DB\u8FB9 / \u56DB\u89D2\u6539\u53D8\u9762\u677F\u5C3A\u5BF8",
2652
- checked: settings.panelResize,
3301
+ },
3302
+ children: [
3303
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: bodyLead, children: "\u53F3\u952E\u70B9\u51FB\u8F93\u5165\u6846\u65F6\u5F39\u51FA\u54EA\u4E00\u79CD\u83DC\u5355\u3002\u53EA\u5F71\u54CD\u53F3\u952E\uFF0C\u4E0D\u5F71\u54CD\u952E\u4F4D\u4E0E\u5176\u5B83\u529F\u80FD\u3002" }),
3304
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3305
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowText, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: "\u83DC\u5355\u6765\u6E90" }) }),
3306
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3307
+ PillChoice,
3308
+ {
3309
+ items: MENU_MODES,
3310
+ value: settings.menuMode,
3311
+ onChange: (mode) => {
3312
+ actions.setField(MENU_MODE_FIELD, mode);
3313
+ },
3314
+ ariaLabel: "\u53F3\u952E\u83DC\u5355\u6765\u6E90"
3315
+ }
3316
+ )
3317
+ ] }),
3318
+ settings.menuMode === "official" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: hintInfo, children: [
3319
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u5B98\u65B9" }),
3320
+ "\uFF1A\u672C\u63D2\u4EF6\u5B8C\u5168\u4E0D\u4ECB\u5165\uFF0CDSH \u4E0E\u5176\u5B83\u63D2\u4EF6\u81EA\u5DF1\u7684\u53F3\u952E\u5904\u7406\u539F\u6837\u751F\u6548 \uFF08DSH \u5B98\u65B9\u8F93\u5165\u6846\u672C\u8EAB\u6CA1\u6709\u53F3\u952E\u83DC\u5355\uFF0C\u6240\u4EE5\u901A\u5E38\u770B\u5230\u7684\u5C31\u662F\u6D4F\u89C8\u5668\u7684\u83DC\u5355\uFF09\u3002"
3321
+ ] }),
3322
+ settings.menuMode === "browser" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: hintInfo, children: [
3323
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u6D4F\u89C8\u5668" }),
3324
+ "\uFF1A\u56FA\u5B9A\u7528\u6D4F\u89C8\u5668\u81EA\u5E26\u7684\u83DC\u5355\uFF08\u6837\u5B50\u968F\u6D4F\u89C8\u5668\u800C\u53D8\uFF09\uFF0C\u5E76\u5728\u672C\u63D2\u4EF6\u8FD9\u4E00\u5C42 \u6321\u4F4F\u5176\u5B83\u63D2\u4EF6\u7684\u83DC\u5355\uFF1B\u597D\u5904\u662F\u7C98\u8D34\u514D\u6388\u6743\u3001\u96F6\u914D\u7F6E\u3002"
3325
+ ] }),
3326
+ settings.menuMode === "custom" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
3327
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: hintInfo, children: [
3328
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u81EA\u5B9A\u4E49" }),
3329
+ "\uFF1A\u7528\u672C\u63D2\u4EF6\u56FA\u5B9A\u6837\u5F0F\u7684\u83DC\u5355\uFF08\u672A\u9009\u4E2D\u6587\u672C\u65F6\u300C\u526A\u5207 / \u590D\u5236 / \u5220\u9664\u300D\u7F6E\u7070\uFF09\u3002 \u8FD9\u4E00\u6863\u7684\u300C\u7C98\u8D34\u300D\u8981\u8BFB\u526A\u8D34\u677F\uFF0C\u6D4F\u89C8\u5668\u4F1A\u5148\u8981\u4E00\u6B21\u6388\u6743\u2014\u2014\u4E09\u5BB6\u6D4F\u89C8\u5668\u7684\u5904\u7406\u4E0D\u4E00\u6837\uFF1A"
3330
+ ] }),
3331
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\xB7 Chrome / Edge\uFF08\u8C37\u6B4C / \u5FAE\u8F6F\u6D4F\u89C8\u5668\uFF09\uFF1A\u5F39\u51FA\u540E\u70B9\u300C\u5141\u8BB8\u300D\u5373\u53EF\uFF0C\u4E4B\u540E\u4F1A\u8BB0\u4F4F\u8FD9\u4E2A\u7AD9\u70B9\u3001\u4E0D\u518D\u95EE\u3002 \u8981\u6539\u6216\u64A4\u9500\u6388\u6743\uFF1A\u70B9\u5730\u5740\u680F\u6700\u5DE6\u8FB9\u7684\u7F51\u7AD9\u56FE\u6807 \u2192 \u7F51\u7AD9\u8BBE\u7F6E\uFF08Edge \u53EB\u300C\u6B64\u7AD9\u70B9\u7684\u6743\u9650\u300D\uFF09\u2192 \u526A\u8D34\u677F\uFF1B \u4E5F\u53EF\u4EE5\u76F4\u63A5\u5728\u5730\u5740\u680F\u8F93\u5165 chrome://settings/content/clipboard\uFF08Edge \u8F93\u5165 edge://settings/content/clipboard\uFF09\u3002" }),
3332
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\xB7 Firefox\uFF1A\u4E0D\u5141\u8BB8\u7F51\u9875\u9759\u9ED8\u8BFB\u526A\u8D34\u677F\u2014\u2014\u4F60\u70B9\u672C\u63D2\u4EF6\u7684\u300C\u7C98\u8D34\u300D\u540E\uFF0C\u5B83\u4F1A\u5148\u5F39\u4E00\u4E2A\u53EA\u6709\u300C\u7C98\u8D34(P)\u300D \u4E00\u9879\u7684\u5C0F\u7A97\uFF08\u7EA6 1 \u79D2\u540E\u624D\u53EF\u70B9\uFF09\uFF0C\u70B9\u5B83\u624D\u5B8C\u6210\u8FD9\u6B21\u7C98\u8D34\u3002\u8FD9\u662F Firefox \u7684\u5B89\u5168\u673A\u5236\uFF0C\u63D2\u4EF6\u5173\u4E0D\u6389 \uFF08\u5B9E\u6D4B\uFF1Aabout:config \u91CC\u7684\u526A\u8D34\u677F\u9996\u9009\u9879\u5BF9\u5B83\u65E0\u6548\uFF09\u3002\u4E0D\u60F3\u591A\u8FD9\u4E00\u6B65\u5C31\u76F4\u63A5\u6309 Ctrl+V\uFF0C \u6216\u628A\u4E0A\u9762\u7684\u300C\u83DC\u5355\u6765\u6E90\u300D\u6362\u6210\u300C\u6D4F\u89C8\u5668 / \u5B98\u65B9\u300D\u6863\u2014\u2014\u90A3\u4E24\u6863\u7528\u7684\u662F\u6D4F\u89C8\u5668\u81EA\u5DF1\u7684\u7C98\u8D34\u3002" }),
3333
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintInfo, children: "\u6CE8\u610F\uFF1Achrome://\u3001edge:// \u8FD9\u4E9B\u5730\u5740\u6D4F\u89C8\u5668\u4E0D\u5141\u8BB8\u505A\u6210\u7F51\u9875\u91CC\u7684\u94FE\u63A5\uFF0C\u53EA\u80FD\u624B\u8F93\uFF0C \u6216\u590D\u5236\u4E0A\u9762\u90A3\u4E32\u7C98\u8D34\u5230\u5730\u5740\u680F\u3002" }),
3334
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...row, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
3335
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: "\u83DC\u5355\u6761\u76EE" }),
3336
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: "\u8FD9 7 \u4E2A\u5F00\u5173\u51B3\u5B9A\u81EA\u5B9A\u4E49\u83DC\u5355\u91CC\u51FA\u73B0\u54EA\u4E9B\u6761\u76EE\uFF0C\u5173\u6389\u7684\u4E0D\u663E\u793A\u3002" })
3337
+ ] }) }),
3338
+ MENU_ITEMS.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3339
+ ToggleRow,
3340
+ {
3341
+ first: index === 0,
3342
+ label: item.label,
3343
+ desc: item.shortcut !== "" ? `\u5FEB\u6377\u952E ${item.shortcut}` : "",
3344
+ checked: settings[item.field],
3345
+ onChange: (next) => {
3346
+ actions.setField(item.field, next);
3347
+ }
3348
+ },
3349
+ item.field
3350
+ )),
3351
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { padding: "8px 0 2px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3352
+ "button",
3353
+ {
3354
+ type: "button",
3355
+ style: pill,
3356
+ onClick: () => {
3357
+ for (const item of MENU_ITEMS) actions.setField(item.field, true);
3358
+ },
3359
+ children: "\u5168\u90E8\u5F00\u542F"
3360
+ }
3361
+ ) })
3362
+ ] })
3363
+ ]
3364
+ }
3365
+ ),
3366
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3367
+ FoldCard,
3368
+ {
3369
+ name: "\u5FEB\u6377\u6307\u4EE4",
3370
+ summary: quickSummary,
3371
+ toggle: {
3372
+ checked: sections.quick,
2653
3373
  onChange: (next) => {
2654
- actions.setField(PANEL_RESIZE_FIELD, next);
3374
+ actions.setField(QUICK_ENABLED_FIELD, next);
2655
3375
  }
2656
- }
2657
- ),
2658
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginTop: 10 }, children: [
2659
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: rowDesc, children: "\u5C3A\u5BF8\u9884\u8BBE\uFF1A" }),
2660
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2661
- "button",
2662
- {
2663
- type: "button",
2664
- style: pill,
2665
- onClick: () => {
2666
- actions.clearField(PANEL_WIDTH_FIELD);
2667
- actions.clearField(PANEL_HEIGHT_FIELD);
2668
- },
2669
- children: "\u9ED8\u8BA4\uFF08800\uFF09"
3376
+ },
3377
+ children: [
3378
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: bodyLead, children: [
3379
+ "\u8F93\u5165\u6846\u5DE5\u5177\u884C\u91CC\u90A3\u4E2A\u300C\u5FEB\u6377\u6307\u4EE4\u300D\u6309\u94AE\u70B9\u5F00\u5C31\u662F\u8FD9\u5F20\u6E05\u5355\uFF1A\u70B9\u6761\u76EE\u628A\u5185\u5BB9\u63D2\u5165\u8F93\u5165\u6846\u3002 \u6BCF\u6761\u53F3\u4FA7\u7684\u4E09\u9009\u4E00\u51B3\u5B9A",
3380
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u53D1\u9001\u65F6\u600E\u4E48\u9644\u52A0" }),
3381
+ "\uFF1A \u300C\u5173\u300D= \u53EA\u63D2\u5165\u4E0D\u9644\u52A0\uFF1B\u300C\u6BCF\u6B21\u300D= \u6BCF\u6B21\u53D1\u9001\u90FD\u9644\u52A0\u5230\u6D88\u606F",
3382
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u672B\u5C3E" }),
3383
+ "\uFF1B \u300C\u4EC5\u9996\u6B21\u300D= \u53EA\u5728",
3384
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u8FD9\u4E2A\u4F1A\u8BDD\u7684\u7B2C\u4E00\u6761\u6D88\u606F" }),
3385
+ '\u4E0A\u9644\u52A0\uFF08\u4E4B\u540E\u4E0D\u518D\u9644\u52A0\uFF0C\u5237\u65B0\u9875\u9762\u4E5F\u4E0D\u4F1A\u91CD\u590D\uFF09\u3002 \u591A\u6761\u6309\u5217\u8868\u987A\u5E8F\u62FC\u63A5\uFF0C\u8F93\u5165\u6846\u91CC\u4E0D\u63D0\u524D\u663E\u793A\u3002 \u300C\u4F18\u5316\u63D0\u793A\u8BCD\u300D\u4F1A\u7528\u53E6\u4E00\u4E2A AI \u628A\u8F93\u5165\u6846\u91CC\u7684\u8BDD\u6574\u7406\u6210\u4E00\u6761\u80FD\u76F4\u63A5\u53D1\u51FA\u53BB\u7684\u6E05\u6670\u6307\u4EE4\uFF0C \u7ED3\u679C\u76F4\u63A5\u5199\u56DE\u8F93\u5165\u6846\uFF08Ctrl+Z \u53EF\u8FD8\u539F\uFF09\u2014\u2014\u4E0D\u4F1A\u6C61\u67D3\u5F53\u524D\u5BF9\u8BDD\uFF0C\u4E5F\u4E0D\u5360\u4F60\u7684\u5BF9\u8BDD\u8F6E\u6B21\u3002 0.6.0 \u8D77\u5B83\u4E0D\u518D"\u81EA\u7531\u6539\u5199"\uFF1A\u5B83\u53EA\u80FD\u4EA7\u51FA',
3386
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: "\u80FD\u6307\u56DE\u4F60\u539F\u8BDD\u67D0\u4E00\u53E5\u8BDD" }),
3387
+ '\u7684\u6761\u76EE\uFF0C \u5BBF\u4E3B\u9010\u6761\u505A\u5B57\u9762\u6BD4\u5BF9\uFF0C\u5BF9\u4E0D\u4E0A\u5C31\u4E22\u6389\u90A3\u4E00\u6761\u5E76\u5728\u72B6\u6001\u884C\u91CC\u8BB0\u8D26 \u2014\u2014 \u6240\u4EE5"\u66FF\u4F60\u53D1\u660E\u4E00\u6761\u4F60\u6CA1\u8BF4\u8FC7\u7684\u9700\u6C42"\u5728\u7ED3\u6784\u4E0A\u505A\u4E0D\u5230\u3002\u4E0B\u9762\u53EF\u4EE5\u6539\u6BCF\u4E00\u6863\u7528\u7684\u63D0\u793A\u8BCD\u3002'
3388
+ ] }),
3389
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3390
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
3391
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: "\u4F18\u5316\u5F3A\u5EA6" }),
3392
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.hint ?? "" })
3393
+ ] }),
3394
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3395
+ "button",
3396
+ {
3397
+ type: "button",
3398
+ title: item.hint,
3399
+ style: settings.optimizerTier === item.id ? pillActive : pill,
3400
+ onClick: () => {
3401
+ actions.setField(OPTIMIZER_TIER_FIELD, item.id);
3402
+ },
3403
+ children: item.label
3404
+ },
3405
+ item.id
3406
+ )) })
3407
+ ] }),
3408
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3409
+ OptimizerPromptEditor,
3410
+ {
3411
+ tier: settings.optimizerTier,
3412
+ value: settings[optimizerPromptFieldOf(settings.optimizerTier)],
3413
+ onChange: (next) => {
3414
+ actions.setField(optimizerPromptFieldOf(settings.optimizerTier), next);
3415
+ }
3416
+ }
3417
+ ),
3418
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3419
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: rowText, children: [
3420
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowTitle, children: "\u5FEB\u6377\u6307\u4EE4\u6E05\u5355" }),
3421
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: rowDesc, children: "\u5206\u7C7B\u5728\u8FD9\u91CC\u7BA1\u7406\uFF08\u9762\u677F\u91CC\u53EA\u505A\u5207\u6362\uFF09\uFF1B\u5185\u7F6E 9 \u6761\u53EF\u4EE5\u76F4\u63A5\u7528\uFF0C\u6539\u5B8C\u8BB0\u5F97\u70B9\u300C\u4FDD\u5B58\u4FEE\u6539\u300D\u3002" })
3422
+ ] }),
3423
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3424
+ QuickPromptsEditor,
3425
+ {
3426
+ book,
3427
+ status: bookStatus,
3428
+ onSave: (next) => {
3429
+ actions.saveBook(next);
3430
+ },
3431
+ onReload: () => {
3432
+ actions.reloadBook();
3433
+ },
3434
+ onReset: () => {
3435
+ actions.resetBook();
3436
+ }
3437
+ }
3438
+ )
3439
+ ] })
3440
+ ]
3441
+ }
3442
+ ),
3443
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3444
+ FoldCard,
3445
+ {
3446
+ name: "\u8BBE\u7F6E\u9762\u677F",
3447
+ summary: panelSummary,
3448
+ toggle: {
3449
+ checked: sections.panel,
3450
+ onChange: (next) => {
3451
+ actions.setField(PANEL_ENABLED_FIELD, next);
2670
3452
  }
2671
- ),
2672
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2673
- "button",
3453
+ },
3454
+ controls: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3455
+ MiniToggle,
2674
3456
  {
2675
- type: "button",
2676
- style: settings.panelWidth === 640 && settings.panelHeight === 600 ? pillActive : pill,
2677
- onClick: () => {
2678
- actions.setField(PANEL_WIDTH_FIELD, 640);
2679
- actions.setField(PANEL_HEIGHT_FIELD, 600);
2680
- },
2681
- children: "\u7D27\u51D1\uFF08640\xD7600\uFF09"
3457
+ label: "\u8FB9\u7F18\u7F29\u653E",
3458
+ checked: settings.panelResize,
3459
+ onChange: (next) => {
3460
+ actions.setField(PANEL_RESIZE_FIELD, next);
3461
+ }
2682
3462
  }
2683
3463
  ),
2684
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2685
- "button",
2686
- {
2687
- type: "button",
2688
- style: settings.panelWidth === 1040 && settings.panelHeight === 760 ? pillActive : pill,
2689
- onClick: () => {
2690
- actions.setField(PANEL_WIDTH_FIELD, 1040);
2691
- actions.setField(PANEL_HEIGHT_FIELD, 760);
2692
- },
2693
- children: "\u5BBD\u655E\uFF081040\xD7760\uFF09"
2694
- }
2695
- )
2696
- ] })
2697
- ] }),
2698
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(FoldCard, { name: "OpenCode \u8BF7\u6C42\u5934", summary: headerSummary, children: [
2699
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintError, children: "\u26A0\uFE0F \u8BF7\u4F7F\u7528\u81EA\u5B9A\u4E49\u7684 OpenCode API \u5730\u5740\uFF0C\u4E0D\u8981\u7528 DSH \u81EA\u5E26\u7684 API \u5730\u5740\u914D\u7F6E\uFF1A \u7528\u81EA\u5E26\u7684\u914D\u7F6E\u65E0\u6CD5\u4E0A\u4F20\u56FE\u7247\uFF0C\u4E00\u65E6\u53D1\u9001\u56FE\u7247\u5C31\u4F1A\u62A5\u9519\u3002" }),
2700
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: bodyLead, children: "OpenCode \u7684\u63A5\u53E3\u8981\u6C42\u5BA2\u6237\u7AEF\u6BCF\u6B21\u8BF7\u6C42\u90FD\u5E26\u4E0A\u4E00\u4E2A\u7A33\u5B9A\u7684\u4F1A\u8BDD ID \u8BF7\u6C42\u5934\uFF08\u5B98\u65B9 Go \u6587\u6863 \u300C\u53EF\u4EE5\u5728\u54EA\u91CC\u4F7F\u7528\uFF1F\u300D\u7B2C 3 \u6761\uFF1A\u4E3A\u6BCF\u6BB5\u5BF9\u8BDD\u5728 x-opencode-session \u4E2D\u53D1\u9001\u4F1A\u8BDD ID\uFF0C \u4EE5\u4FBF\u5176\u4F18\u5316\u8DEF\u7531\u4E0E\u63D0\u793A\u8BCD\u7F13\u5B58\uFF09\u3002DSH \u7684\u8BBE\u7F6E\u9875\u4E0D\u63D0\u4F9B\u8BF7\u6C42\u5934\u7F16\u8F91\u5668\uFF0C\u6240\u4EE5\u8FD9\u91CC\u76F4\u63A5\u628A\u5B83\u5199\u8FDB llm-pi-ai \u7684 provider \u914D\u7F6E\u2014\u2014\u4E0B\u4E00\u6B21\u6A21\u578B\u8BF7\u6C42\u5C31\u751F\u6548\uFF0C\u4E0D\u7528\u91CD\u542F\uFF0C\u4E5F\u4E0D\u7528\u624B\u5DE5\u6539 settings.yaml\u3002 \u53EA\u5BF9 llm-pi-ai \u91CC\u300C\u5DF2\u5B58\u5728\u300D\u7684 opencode \u7CFB\u8DEF\u7531\u751F\u6548\uFF0C\u4E0D\u4F1A\u51ED\u7A7A\u65B0\u5EFA provider\uFF1B \u603B\u5F00\u5173\u5173\u95ED\u6216\u672C\u680F\u76EE\u505C\u7528\u65F6\uFF0C\u5199\u5165\u7684\u5934\u4F1A\u81EA\u52A8\u64A4\u9500\u3002" }),
2701
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2702
- ToggleRow,
2703
- {
2704
- first: true,
2705
- label: "\u9644\u52A0\u8BF7\u6C42\u5934",
2706
- desc: "\u6253\u5F00\u5373\u5199\u5165\uFF0C\u5E76\u5728\u6BCF\u6B21\u542F\u52A8\u65F6\u8865\u9F50\uFF1B\u5173\u95ED\u5373\u64A4\u9500",
2707
- checked: settings.headerEnabled,
3464
+ children: [
3465
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: bodyLead, children: "\u5BFC\u822A\u5217\u7684\u6EDA\u52A8\u7531 DSH \u5B98\u65B9\u7684\u8BBE\u7F6E\u9875\u81EA\u5DF1\u8D1F\u8D23\uFF0C\u672C\u63D2\u4EF6\u4E0D\u518D\u4ECB\u5165\u3002 \u5F00\u542F\u300C\u8FB9\u7F18\u8C03\u6574\u5927\u5C0F\u300D\u540E\uFF0C\u628A\u9F20\u6807\u79FB\u5230\u8BBE\u7F6E\u9762\u677F\u7684\u8FB9\u6216\u89D2\u4E0A\uFF08\u51FA\u73B0\u9AD8\u4EAE\u6216\u5149\u6807\u53D8\u5316\uFF09\u62D6\u52A8\u5373\u53EF\u6539\u53D8\u9762\u677F\u5927\u5C0F\uFF0C \u5C3A\u5BF8\u4F1A\u8BB0\u4F4F\uFF0C\u4E0B\u6B21\u6253\u5F00\u4FDD\u6301\u3002\uFF08\u8FD9\u4E2A\u5F00\u5173\u5728\u6807\u9898\u884C\u4E0A\u3002\uFF09" }),
3466
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginTop: 10 }, children: [
3467
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: rowDesc, children: "\u5C3A\u5BF8\u9884\u8BBE\uFF1A" }),
3468
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3469
+ "button",
3470
+ {
3471
+ type: "button",
3472
+ style: pill,
3473
+ onClick: () => {
3474
+ actions.clearField(PANEL_WIDTH_FIELD);
3475
+ actions.clearField(PANEL_HEIGHT_FIELD);
3476
+ },
3477
+ children: "\u9ED8\u8BA4\uFF08800\uFF09"
3478
+ }
3479
+ ),
3480
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3481
+ "button",
3482
+ {
3483
+ type: "button",
3484
+ style: settings.panelWidth === 640 && settings.panelHeight === 600 ? pillActive : pill,
3485
+ onClick: () => {
3486
+ actions.setField(PANEL_WIDTH_FIELD, 640);
3487
+ actions.setField(PANEL_HEIGHT_FIELD, 600);
3488
+ },
3489
+ children: "\u7D27\u51D1\uFF08640\xD7600\uFF09"
3490
+ }
3491
+ ),
3492
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3493
+ "button",
3494
+ {
3495
+ type: "button",
3496
+ style: settings.panelWidth === 1040 && settings.panelHeight === 760 ? pillActive : pill,
3497
+ onClick: () => {
3498
+ actions.setField(PANEL_WIDTH_FIELD, 1040);
3499
+ actions.setField(PANEL_HEIGHT_FIELD, 760);
3500
+ },
3501
+ children: "\u5BBD\u655E\uFF081040\xD7760\uFF09"
3502
+ }
3503
+ )
3504
+ ] })
3505
+ ]
3506
+ }
3507
+ ),
3508
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3509
+ FoldCard,
3510
+ {
3511
+ name: "OpenCode \u8BF7\u6C42\u5934",
3512
+ summary: headerSummary,
3513
+ toggle: {
3514
+ checked: sections.header,
2708
3515
  onChange: (next) => {
2709
3516
  actions.setField(HEADER_ENABLED_FIELD, next);
2710
3517
  }
2711
- }
2712
- ),
2713
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2714
- TextFieldRow,
2715
- {
2716
- title: "\u5934\u540D",
2717
- desc: `\u9ED8\u8BA4 ${DEFAULT_HEADER_NAME}\uFF08OpenCode \u5B98\u65B9\u8981\u6C42\u7684\u90A3\u4E00\u4E2A\uFF09`,
2718
- value: settings.headerName,
2719
- placeholder: DEFAULT_HEADER_NAME,
2720
- maxLength: HEADER_NAME_MAX,
2721
- onChange: (next) => {
2722
- actions.setField(HEADER_NAME_FIELD, next);
2723
- }
2724
- }
2725
- ),
2726
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2727
- TextFieldRow,
2728
- {
2729
- title: "\u503C",
2730
- desc: "\u6240\u6709\u5BF9\u8BDD\u5171\u7528\u8FD9\u4E00\u4E2A\u503C\uFF1B\u7559\u7A7A\u65F6\u9996\u6B21\u542F\u7528\u4F1A\u81EA\u52A8\u751F\u6210\u4E00\u4E2A UUID \u5E76\u4FDD\u5B58\u6CBF\u7528",
2731
- value: settings.headerValue,
2732
- placeholder: "\u7559\u7A7A = \u81EA\u52A8\u751F\u6210",
2733
- maxLength: HEADER_VALUE_MAX,
2734
- onChange: (next) => {
2735
- actions.setField(HEADER_VALUE_FIELD, next);
2736
- },
2737
- action: {
2738
- label: "\u91CD\u65B0\u751F\u6210",
2739
- onClick: () => {
2740
- actions.setField(HEADER_VALUE_FIELD, newSessionId());
3518
+ },
3519
+ children: [
3520
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: hintError, children: "\u26A0\uFE0F \u8BF7\u4F7F\u7528\u81EA\u5B9A\u4E49\u7684 OpenCode API \u5730\u5740\uFF0C\u4E0D\u8981\u7528 DSH \u81EA\u5E26\u7684 API \u5730\u5740\u914D\u7F6E\uFF1A \u7528\u81EA\u5E26\u7684\u914D\u7F6E\u65E0\u6CD5\u4E0A\u4F20\u56FE\u7247\uFF0C\u4E00\u65E6\u53D1\u9001\u56FE\u7247\u5C31\u4F1A\u62A5\u9519\u3002" }),
3521
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: bodyLead, children: "OpenCode \u7684\u63A5\u53E3\u8981\u6C42\u5BA2\u6237\u7AEF\u6BCF\u6B21\u8BF7\u6C42\u90FD\u5E26\u4E0A\u4E00\u4E2A\u7A33\u5B9A\u7684\u4F1A\u8BDD ID \u8BF7\u6C42\u5934\uFF08\u5B98\u65B9 Go \u6587\u6863 \u300C\u53EF\u4EE5\u5728\u54EA\u91CC\u4F7F\u7528\uFF1F\u300D\u7B2C 3 \u6761\uFF1A\u4E3A\u6BCF\u6BB5\u5BF9\u8BDD\u5728 x-opencode-session \u4E2D\u53D1\u9001\u4F1A\u8BDD ID\uFF0C \u4EE5\u4FBF\u5176\u4F18\u5316\u8DEF\u7531\u4E0E\u63D0\u793A\u8BCD\u7F13\u5B58\uFF09\u3002DSH \u7684\u8BBE\u7F6E\u9875\u4E0D\u63D0\u4F9B\u8BF7\u6C42\u5934\u7F16\u8F91\u5668\uFF0C\u6240\u4EE5\u8FD9\u91CC\u76F4\u63A5\u628A\u5B83\u5199\u8FDB llm-pi-ai \u7684 provider \u914D\u7F6E\u2014\u2014\u4E0B\u4E00\u6B21\u6A21\u578B\u8BF7\u6C42\u5C31\u751F\u6548\uFF0C\u4E0D\u7528\u91CD\u542F\uFF0C\u4E5F\u4E0D\u7528\u624B\u5DE5\u6539 settings.yaml\u3002 \u53EA\u5BF9 llm-pi-ai \u91CC\u300C\u5DF2\u5B58\u5728\u300D\u7684 opencode \u7CFB\u8DEF\u7531\u751F\u6548\uFF0C\u4E0D\u4F1A\u51ED\u7A7A\u65B0\u5EFA provider\uFF1B \u603B\u5F00\u5173\u5173\u95ED\u6216\u672C\u680F\u76EE\u505C\u7528\u65F6\uFF0C\u5199\u5165\u7684\u5934\u4F1A\u81EA\u52A8\u64A4\u9500\u3002" }),
3522
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3523
+ TextFieldRow,
3524
+ {
3525
+ title: "\u5934\u540D",
3526
+ desc: `\u9ED8\u8BA4 ${DEFAULT_HEADER_NAME}\uFF08OpenCode \u5B98\u65B9\u8981\u6C42\u7684\u90A3\u4E00\u4E2A\uFF09`,
3527
+ value: settings.headerName,
3528
+ placeholder: DEFAULT_HEADER_NAME,
3529
+ maxLength: HEADER_NAME_MAX,
3530
+ onChange: (next) => {
3531
+ actions.setField(HEADER_NAME_FIELD, next);
3532
+ }
2741
3533
  }
2742
- }
2743
- }
2744
- ),
2745
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2746
- TextFieldRow,
2747
- {
2748
- title: "\u4F5C\u7528\u8DEF\u7531",
2749
- desc: "\u9017\u53F7\u6216\u7A7A\u683C\u5206\u9694\uFF1B\u7559\u7A7A = \u81EA\u52A8\u5339\u914D OpenCode \u8DEF\u7531\uFF08\u540D\u5B57\u4EE5 opencode \u5F00\u5934\uFF0C\u6216 baseURL \u6307\u5411 opencode.ai\uFF09",
2750
- value: settings.headerRoutes,
2751
- placeholder: "\u7559\u7A7A = \u81EA\u52A8\uFF08opencode* \u6216 opencode.ai \u7AEF\u70B9\uFF09",
2752
- maxLength: HEADER_VALUE_MAX,
3534
+ ),
3535
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3536
+ TextFieldRow,
3537
+ {
3538
+ title: "\u503C",
3539
+ desc: "\u6240\u6709\u5BF9\u8BDD\u5171\u7528\u8FD9\u4E00\u4E2A\u503C\uFF1B\u7559\u7A7A\u65F6\u9996\u6B21\u542F\u7528\u4F1A\u81EA\u52A8\u751F\u6210\u4E00\u4E2A UUID \u5E76\u4FDD\u5B58\u6CBF\u7528",
3540
+ value: settings.headerValue,
3541
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8\u751F\u6210",
3542
+ maxLength: HEADER_VALUE_MAX,
3543
+ onChange: (next) => {
3544
+ actions.setField(HEADER_VALUE_FIELD, next);
3545
+ },
3546
+ action: {
3547
+ label: "\u91CD\u65B0\u751F\u6210",
3548
+ onClick: () => {
3549
+ actions.setField(HEADER_VALUE_FIELD, newSessionId());
3550
+ }
3551
+ }
3552
+ }
3553
+ ),
3554
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3555
+ TextFieldRow,
3556
+ {
3557
+ title: "\u4F5C\u7528\u8DEF\u7531",
3558
+ desc: "\u9017\u53F7\u6216\u7A7A\u683C\u5206\u9694\uFF1B\u7559\u7A7A = \u81EA\u52A8\u5339\u914D OpenCode \u8DEF\u7531\uFF08\u540D\u5B57\u4EE5 opencode \u5F00\u5934\uFF0C\u6216 baseURL \u6307\u5411 opencode.ai\uFF09",
3559
+ value: settings.headerRoutes,
3560
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8\uFF08opencode* \u6216 opencode.ai \u7AEF\u70B9\uFF09",
3561
+ maxLength: HEADER_VALUE_MAX,
3562
+ onChange: (next) => {
3563
+ actions.setField(HEADER_ROUTES_FIELD, next);
3564
+ }
3565
+ }
3566
+ ),
3567
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: hintInfo, children: [
3568
+ "\u72B6\u6001\uFF1A",
3569
+ headerStatusText
3570
+ ] })
3571
+ ]
3572
+ }
3573
+ ),
3574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3575
+ FoldCard,
3576
+ {
3577
+ name: "\u9ED8\u8BA4\u7EC8\u7AEF",
3578
+ summary: terminalSummary,
3579
+ toggle: {
3580
+ checked: sections.terminal,
2753
3581
  onChange: (next) => {
2754
- actions.setField(HEADER_ROUTES_FIELD, next);
3582
+ actions.setField(TERMINAL_ENABLED_FIELD, next);
2755
3583
  }
2756
- }
2757
- ),
2758
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
2759
- "\u72B6\u6001\uFF1A",
2760
- headerStatusText
2761
- ] })
2762
- ] })
3584
+ },
3585
+ controls: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3586
+ PillChoice,
3587
+ {
3588
+ compact: true,
3589
+ items: TERMINAL_MODES,
3590
+ value: settings.terminalMode,
3591
+ onChange: (mode) => {
3592
+ actions.setField(TERMINAL_MODE_FIELD, mode);
3593
+ },
3594
+ ariaLabel: "\u7EC8\u7AEF\u5DE5\u5177"
3595
+ }
3596
+ ),
3597
+ children: [
3598
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: bodyLead, children: "Windows \u4E0A DSH \u7ED9\u6A21\u578B\u7684\u7EC8\u7AEF\u5DE5\u5177\u662F PowerShell\uFF0C\u800C\u6A21\u578B\u5BF9 bash \u8BED\u6CD5\u7684\u628A\u63E1\u660E\u663E\u66F4\u597D\u3002\u8FD9\u4E00\u680F\u628A\u7EC8\u7AEF \u6362\u6210 Git Bash\uFF1A\u6A21\u578B\u770B\u5230\u7684\u5DE5\u5177\u5C31\u53EB bash\u3001PowerShell \u90A3\u4E2A\u5DE5\u5177\u4F1A\u4ECE\u5B83\u7684\u5DE5\u5177\u5217\u8868\u91CC\u6D88\u5931\uFF0C \u547D\u4EE4\u91CC\u7684\u8DEF\u5F84\u4E0E\u5F15\u53F7\u6309 bash \u89C4\u5219\u5199\u3002\u672C\u673A\u4E0D\u9700\u8981\u88C5 Git for Windows \u5230\u9ED8\u8BA4\u76EE\u5F55\u2014\u2014\u63A2\u6D4B\u4F1A\u5148\u627E git\uFF0C\u518D\u7531\u540C\u4E00\u4E2A\u5B89\u88C5\u53CD\u63A8 bash\u3002\uFF08\u6863\u4F4D\u5728\u6807\u9898\u884C\u4E0A\uFF1A\u81EA\u52A8 / Git Bash / PowerShell\u3002\uFF09" }),
3599
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DefaultTerminalBody, { settings, setField: actions.setField, hideMode: true })
3600
+ ]
3601
+ }
3602
+ )
2763
3603
  ] })
2764
3604
  ] });
2765
3605
  }
2766
3606
 
2767
3607
  // src/client/QuickCommandsButton.tsx
2768
3608
  var import_react5 = require("react");
2769
- var import_jsx_runtime7 = require("react/jsx-runtime");
3609
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2770
3610
  function QuickCommandsButton({
2771
3611
  useInput,
2772
3612
  inputActions,
@@ -2793,9 +3633,9 @@ function QuickCommandsButton({
2793
3633
  releaseInputBridge(sid);
2794
3634
  };
2795
3635
  }, [inputActions, draft, sessionId, blank]);
2796
- if (settings.enabled !== true) return null;
3636
+ if (!activeSections(settings).quick) return null;
2797
3637
  const open = anchor !== null;
2798
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
3638
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2799
3639
  "button",
2800
3640
  {
2801
3641
  ref,
@@ -2816,14 +3656,14 @@ function QuickCommandsButton({
2816
3656
  });
2817
3657
  },
2818
3658
  children: [
2819
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3659
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2820
3660
  "svg",
2821
3661
  {
2822
3662
  viewBox: "0 0 16 16",
2823
3663
  width: "12",
2824
3664
  height: "12",
2825
3665
  "aria-hidden": true,
2826
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3666
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2827
3667
  "path",
2828
3668
  {
2829
3669
  d: "M9.2 1.2 3.4 9.1h3.5l-0.9 5.7 6-8.1H8.4l0.8-5.5Z",
@@ -2832,7 +3672,7 @@ function QuickCommandsButton({
2832
3672
  )
2833
3673
  }
2834
3674
  ),
2835
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u5FEB\u6377\u6307\u4EE4" })
3675
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "\u5FEB\u6377\u6307\u4EE4" })
2836
3676
  ]
2837
3677
  }
2838
3678
  );
@@ -2840,7 +3680,7 @@ function QuickCommandsButton({
2840
3680
 
2841
3681
  // src/client/QuickCommandsPanel.tsx
2842
3682
  var import_react6 = require("react");
2843
- var import_jsx_runtime8 = require("react/jsx-runtime");
3683
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2844
3684
  var MARGIN = 8;
2845
3685
  var GAP = 8;
2846
3686
  function QuickCommandsPanel({
@@ -2903,7 +3743,7 @@ function QuickCommandsPanel({
2903
3743
  const tier = settings.optimizerTier;
2904
3744
  const items = active2?.prompts ?? [];
2905
3745
  const failure = status !== "" && status !== "saving" ? status : "";
2906
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3746
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2907
3747
  "div",
2908
3748
  {
2909
3749
  ref,
@@ -2911,10 +3751,10 @@ function QuickCommandsPanel({
2911
3751
  "aria-label": "\u5FEB\u6377\u6307\u4EE4",
2912
3752
  style: { ...quickPanel, left: position?.left ?? anchor.left, top: position?.top ?? anchor.bottom },
2913
3753
  children: [
2914
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelHead, children: [
2915
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelTitleRow, children: [
2916
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickPanelTitle, children: "\u5FEB\u6377\u6307\u4EE4" }),
2917
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: quickTierRow, role: "group", "aria-label": "\u4F18\u5316\u5F3A\u5EA6", children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3754
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickPanelHead, children: [
3755
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickPanelTitleRow, children: [
3756
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: quickPanelTitle, children: "\u5FEB\u6377\u6307\u4EE4" }),
3757
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: quickTierRow, role: "group", "aria-label": "\u4F18\u5316\u5F3A\u5EA6", children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2918
3758
  "button",
2919
3759
  {
2920
3760
  type: "button",
@@ -2932,12 +3772,12 @@ function QuickCommandsPanel({
2932
3772
  item.id
2933
3773
  )) })
2934
3774
  ] }),
2935
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3775
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2936
3776
  "button",
2937
3777
  {
2938
3778
  type: "button",
2939
3779
  disabled: busy,
2940
- title: "\u628A\u8F93\u5165\u6846\u91CC\u7684\u8BDD\u4EA4\u7ED9\u53E6\u4E00\u4E2A AI \u6574\u7406\u6210\u4E00\u6761\u53EF\u4EE5\u76F4\u63A5\u53D1\u51FA\u53BB\u7684\u6E05\u6670\u6307\u4EE4\uFF0C\u7ED3\u679C\u76F4\u63A5\u5199\u56DE\u8F93\u5165\u6846",
3780
+ title: "\u628A\u8F93\u5165\u6846\u91CC\u7684\u8BDD\u4EA4\u7ED9\u53E6\u4E00\u4E2A AI \u6574\u7406\u6210\u4E00\u6761\u53EF\u4EE5\u76F4\u63A5\u53D1\u51FA\u53BB\u7684\u6E05\u6670\u6307\u4EE4\uFF0C\u7ED3\u679C\u76F4\u63A5\u5199\u56DE\u8F93\u5165\u6846\u3002\u5B83\u53EA\u80FD\u4EA7\u51FA\u80FD\u6307\u56DE\u4F60\u539F\u8BDD\u67D0\u4E00\u53E5\u7684\u8865\u5168\uFF0C\u6307\u4E0D\u56DE\u53BB\u7684\u4F1A\u88AB\u4E22\u6389\u5E76\u8BB0\u8D26",
2941
3781
  style: busy ? quickPrimaryButtonDisabled : quickPrimaryButton,
2942
3782
  onMouseDown: (event) => {
2943
3783
  event.preventDefault();
@@ -2946,13 +3786,13 @@ function QuickCommandsPanel({
2946
3786
  actions.optimize();
2947
3787
  },
2948
3788
  children: [
2949
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, children: "\u2728" }),
2950
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: busy ? "\u4F18\u5316\u4E2D\u2026" : "\u4F18\u5316\u63D0\u793A\u8BCD" })
3789
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { "aria-hidden": true, children: "\u2728" }),
3790
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: busy ? "\u4F18\u5316\u4E2D\u2026" : "\u4F18\u5316\u63D0\u793A\u8BCD" })
2951
3791
  ]
2952
3792
  }
2953
3793
  ),
2954
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickCategoryRow, children: [
2955
- categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3794
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickCategoryRow, children: [
3795
+ categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2956
3796
  "button",
2957
3797
  {
2958
3798
  type: "button",
@@ -2969,7 +3809,7 @@ function QuickCommandsPanel({
2969
3809
  },
2970
3810
  category.id
2971
3811
  )),
2972
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3812
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2973
3813
  "button",
2974
3814
  {
2975
3815
  type: "button",
@@ -2987,14 +3827,14 @@ function QuickCommandsPanel({
2987
3827
  )
2988
3828
  ] })
2989
3829
  ] }),
2990
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickList, children: [
2991
- items.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickEmpty, children: [
3830
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickList, children: [
3831
+ items.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickEmpty, children: [
2992
3832
  "\u8FD9\u4E2A\u5206\u7C7B\u91CC\u8FD8\u6CA1\u6709\u6761\u76EE\u3002",
2993
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("br", {}),
3833
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {}),
2994
3834
  "\u5728\u300C\u8BBE\u7F6E \u2192 \u8F93\u5165\u4F53\u9A8C \u2192 \u5FEB\u6377\u6307\u4EE4\u6E05\u5355\u300D\u91CC\u6DFB\u52A0\u3002"
2995
3835
  ] }),
2996
- items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
2997
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3836
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
3837
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
2998
3838
  "button",
2999
3839
  {
3000
3840
  type: "button",
@@ -3007,12 +3847,12 @@ function QuickCommandsPanel({
3007
3847
  actions.insert(item.prompt);
3008
3848
  },
3009
3849
  children: [
3010
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickItemLabel, children: item.label }),
3011
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickItemPreview, children: item.prompt.replace(/\s+/g, " ") })
3850
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: quickItemLabel, children: item.label }),
3851
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: quickItemPreview, children: item.prompt.replace(/\s+/g, " ") })
3012
3852
  ]
3013
3853
  }
3014
3854
  ),
3015
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3855
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3016
3856
  InsertModeControl,
3017
3857
  {
3018
3858
  compact: true,
@@ -3024,7 +3864,7 @@ function QuickCommandsPanel({
3024
3864
  }
3025
3865
  )
3026
3866
  ] }, item.id)),
3027
- active2 !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3867
+ active2 !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
3028
3868
  AddPromptRow,
3029
3869
  {
3030
3870
  variant: "panel",
@@ -3039,9 +3879,9 @@ function QuickCommandsPanel({
3039
3879
  }
3040
3880
  )
3041
3881
  ] }),
3042
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelFoot, children: [
3043
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickNotice, role: "status", children: notice !== "" ? notice : failure }),
3044
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3882
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: quickPanelFoot, children: [
3883
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: quickNotice, role: "status", children: notice !== "" ? notice : failure }),
3884
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
3045
3885
  "span",
3046
3886
  {
3047
3887
  style: quickFootHint,
@@ -3062,28 +3902,94 @@ function QuickCommandsPanel({
3062
3902
 
3063
3903
  // src/client.tsx
3064
3904
  var name = "composer-ux";
3065
- var inject = ["slots", "settingsScope"];
3905
+ var inject = ["slots"];
3906
+ var NULL_SCOPE = {
3907
+ getSnapshot: () => ({ status: "unavailable", value: void 0 }),
3908
+ subscribe: () => () => {
3909
+ },
3910
+ set: async () => false,
3911
+ unset: async () => false,
3912
+ mutate: async () => false
3913
+ };
3066
3914
  function apply(ctx) {
3067
3915
  const slots = ctx.slots;
3068
- const scope = ctx.settingsScope.bind({ namespace: NAMESPACE });
3069
3916
  const live = (0, import_dsh_client_store.createSnapshotStore)({ ...DEFAULT_SETTINGS });
3070
3917
  const menu2 = (0, import_dsh_client_store.createSnapshotStore)(null);
3071
3918
  const panel = (0, import_dsh_client_store.createSnapshotStore)(null);
3072
3919
  const optimizing = (0, import_dsh_client_store.createSnapshotStore)(false);
3073
3920
  const panelNotice = (0, import_dsh_client_store.createSnapshotStore)("");
3921
+ const writeNotice = (0, import_dsh_client_store.createSnapshotStore)("");
3922
+ let scope = NULL_SCOPE;
3074
3923
  const sync = () => {
3075
3924
  const snapshot = scope.getSnapshot();
3076
3925
  live.set(snapshot.status === "ready" && snapshot.value !== void 0 ? { ...DEFAULT_SETTINGS, ...sanitizeSettings(snapshot.value) } : { ...DEFAULT_SETTINGS });
3077
3926
  };
3078
3927
  sync();
3079
- ctx.effect(() => scope.subscribe(sync), "composer-ux: settings sync");
3928
+ let adopted = false;
3929
+ const adoptSettings = (service, shape) => {
3930
+ if (adopted || service === null || service === void 0) return;
3931
+ const api = service;
3932
+ const next = shape === "get" ? api.get?.(NAMESPACE) : api.bind?.({ namespace: NAMESPACE });
3933
+ if (next === null || next === void 0) return;
3934
+ if (typeof next.getSnapshot !== "function") return;
3935
+ adopted = true;
3936
+ scope = next;
3937
+ sync();
3938
+ ctx.effect(() => scope.subscribe(sync), "composer-ux: settings sync");
3939
+ };
3940
+ const whenService = (deps, callback) => {
3941
+ if (typeof ctx.inject !== "function") return;
3942
+ try {
3943
+ ctx.inject(deps, callback);
3944
+ } catch (error) {
3945
+ console.warn("[composer-ux] settings service inject failed", error);
3946
+ }
3947
+ };
3948
+ whenService(["configForms"], (view) => {
3949
+ adoptSettings(view.configForms, "get");
3950
+ });
3951
+ whenService(["settingsScope"], (view) => {
3952
+ adoptSettings(view.settingsScope, "bind");
3953
+ });
3954
+ const peekService = (name2) => {
3955
+ try {
3956
+ return ctx[name2];
3957
+ } catch {
3958
+ return void 0;
3959
+ }
3960
+ };
3961
+ adoptSettings(peekService("configForms"), "get");
3962
+ adoptSettings(peekService("settingsScope"), "bind");
3963
+ const WRITE_READBACK_MS = 1200;
3080
3964
  const setField = (field, value) => {
3081
- void scope.set(field, value).catch((error) => {
3965
+ writeNotice.set("");
3966
+ const verify = typeof value === "boolean";
3967
+ void scope.set(field, value).then((accepted) => {
3968
+ if (accepted === false) {
3969
+ console.warn("[composer-ux] settings write refused", field);
3970
+ writeNotice.set(
3971
+ `\u5199\u5165\u300C${field}\u300D\u88AB\u5BBF\u4E3B\u62D2\u7EDD\u3002\u5E38\u89C1\u539F\u56E0\uFF1Aprofile \u7684\u5199\u5165\u9501\u88AB\u5360\u7528\uFF0C\u6216\u662F\u4E00\u628A\u5B64\u513F\u9501\uFF08\u786C\u6740\u91CD\u542F\u7559\u4E0B\u7684\uFF09\u2014\u2014\u89C1 README\u300C\u8BBE\u7F6E\u5199\u4E0D\u8FDB\u53BB\u300D\u4E00\u8282\uFF1B\u91CD\u542F DSH \u540E\u4ECD\u65E0\u6548\uFF0C\u5C31\u624B\u5DE5\u5220\u6389 profiles/<\u4F60\u7684 profile>/package.json.lock\u3002`
3972
+ );
3973
+ return;
3974
+ }
3975
+ if (!verify) return;
3976
+ setTimeout(() => {
3977
+ const now = live.getSnapshot()[field];
3978
+ if (now === value) return;
3979
+ console.warn("[composer-ux] settings write had no visible effect", field, now, value);
3980
+ writeNotice.set(
3981
+ `\u5199\u5165\u300C${field}\u300D\u5DF2\u88AB\u5BBF\u4E3B\u63A5\u53D7\uFF0C\u4F46\u8FD0\u884C\u65F6\u7684\u503C\u6CA1\u6709\u53D8\u5316\uFF08\u4ECD\u662F ${String(now)}\uFF09\u3002\u914D\u7F6E\u53EF\u80FD\u5DF2\u7ECF\u843D\u76D8\uFF0C\u53EA\u662F\u8FD9\u4E2A\u8FDB\u7A0B\u6CA1\u63A5\u4F4F\u2014\u2014\u91CD\u542F DSH \u5373\u53EF\u751F\u6548\u3002`
3982
+ );
3983
+ }, WRITE_READBACK_MS);
3984
+ }, (error) => {
3082
3985
  console.error("[composer-ux] settings write failed", error);
3986
+ writeNotice.set(`\u5199\u5165\u300C${field}\u300D\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`);
3083
3987
  });
3084
3988
  };
3085
3989
  const clearField = (field) => {
3086
- void scope.unset(field).catch((error) => {
3990
+ void scope.unset(field).then((accepted) => {
3991
+ if (accepted === false) console.warn("[composer-ux] settings clear refused", field);
3992
+ }, (error) => {
3087
3993
  console.error("[composer-ux] settings clear failed", error);
3088
3994
  });
3089
3995
  };
@@ -3168,7 +4074,6 @@ function apply(ctx) {
3168
4074
  MENU_MODE_FIELD,
3169
4075
  // 旧的布尔字段也一并清掉:它只是迁移线索,留着会把「恢复默认」后的档位又拉回旧值。
3170
4076
  MENU_NATIVE_FIELD,
3171
- PANEL_SCROLL_FIELD,
3172
4077
  PANEL_RESIZE_FIELD,
3173
4078
  PANEL_WIDTH_FIELD,
3174
4079
  PANEL_HEIGHT_FIELD,
@@ -3176,7 +4081,20 @@ function apply(ctx) {
3176
4081
  HEADER_NAME_FIELD,
3177
4082
  HEADER_VALUE_FIELD,
3178
4083
  HEADER_ROUTES_FIELD,
3179
- OPTIMIZER_TIER_FIELD
4084
+ OPTIMIZER_TIER_FIELD,
4085
+ // 0.5.0 新增的用户配置:终端档位/路径(「恢复默认」也该把它们恢复)。
4086
+ TERMINAL_MODE_FIELD,
4087
+ TERMINAL_BASH_PATH_FIELD,
4088
+ // 五栏开关也清掉:清掉 = 回到"从没碰过这一栏"⇒ 全关(新装默认的样子)。
4089
+ // 若不清,恢复默认之后六栏还会保持之前打开的状态,与"默认关"的语义不符。
4090
+ KEYS_ENABLED_FIELD,
4091
+ MENU_ENABLED_FIELD,
4092
+ QUICK_ENABLED_FIELD,
4093
+ PANEL_ENABLED_FIELD,
4094
+ TERMINAL_ENABLED_FIELD,
4095
+ // 0.5.0 里那个「可选重启命令」字段已经删掉,但老文档里可能还留着值:
4096
+ // 顺手清掉,免得它永远躺在设置文件里没人认识。
4097
+ "restartCommand"
3180
4098
  ].map((field) => ({ op: "unset", path: [field] }))
3181
4099
  ).catch((error) => {
3182
4100
  console.error("[composer-ux] settings reset failed", error);
@@ -3230,7 +4148,14 @@ function apply(ctx) {
3230
4148
  }
3231
4149
  replaceDraft(result.text ?? "");
3232
4150
  focusComposer();
3233
- note(`\u5DF2\u5199\u56DE\u8F93\u5165\u6846\uFF08${result.route}\uFF09\xB7 Ctrl+Z \u53EF\u8FD8\u539F`);
4151
+ const bits = [];
4152
+ if (result.fallback === true) bits.push("\u6A21\u578B\u6CA1\u6309\u6761\u76EE\u5951\u7EA6\u8F93\u51FA\uFF0C\u5DF2\u6574\u6BB5\u7167\u6536\uFF08\u672A\u6821\u9A8C\u4F9D\u636E\uFF09");
4153
+ else bits.push(`${String(result.itemCount ?? 0)} \u6761\u8865\u5168`);
4154
+ const lost = result.dropped?.length ?? 0;
4155
+ if (lost > 0) bits.push(`\u4E22\u5F03 ${String(lost)} \u6761`);
4156
+ if (result.promptSource === "custom") bits.push("\u81EA\u5B9A\u4E49\u63D0\u793A\u8BCD");
4157
+ if (result.retried === true) bits.push("\u91CD\u8BD5\u8FC7\u4E00\u6B21");
4158
+ note(`\u5DF2\u5199\u56DE\u8F93\u5165\u6846\uFF08${result.route}\uFF09\xB7 ${bits.join(" \xB7 ")} \xB7 Ctrl+Z \u53EF\u8FD8\u539F`);
3234
4159
  },
3235
4160
  (error) => {
3236
4161
  optimizing.set(false);
@@ -3257,14 +4182,17 @@ function apply(ctx) {
3257
4182
  order: 40,
3258
4183
  label: "\u8F93\u5165\u4F53\u9A8C",
3259
4184
  inject: () => ({
3260
- hooks: { live, book, bookStatus },
4185
+ hooks: { live, book, bookStatus, writeNotice },
3261
4186
  actions: {
3262
4187
  setField,
3263
4188
  clearField,
3264
4189
  resetAll,
3265
4190
  saveBook: bookActions.saveBook,
3266
4191
  reloadBook: bookActions.reload,
3267
- resetBook: bookActions.resetBook
4192
+ resetBook: bookActions.resetBook,
4193
+ dismissNotice: () => {
4194
+ writeNotice.set("");
4195
+ }
3268
4196
  }
3269
4197
  })
3270
4198
  }, SettingsSection));
@@ -3325,38 +4253,31 @@ function apply(ctx) {
3325
4253
  }, QuickCommandsPanel));
3326
4254
  ctx.effect(() => installSettingsCardStyle(), "composer-ux: settings card style");
3327
4255
  ctx.effect(() => installQuickButtonStyle(), "composer-ux: quick button style");
3328
- ctx.effect(
3329
- () => installPanelStyle(
3330
- () => {
3331
- const settings = live.getSnapshot();
3332
- return settings.enabled && settings.panelScroll;
3333
- },
3334
- (listener) => live.subscribe(listener)
3335
- ),
3336
- "composer-ux: panel style"
3337
- );
4256
+ ctx.effect(() => installPanelResizeStyle(), "composer-ux: panel resize style");
3338
4257
  ctx.effect(() => {
3339
4258
  let dispose = null;
3340
4259
  const syncInterceptors = () => {
3341
- const enabled = live.getSnapshot().enabled;
3342
- if (enabled && dispose === null) {
4260
+ const settings = live.getSnapshot();
4261
+ const sections = activeSections(settings);
4262
+ const wanted = sections.keys || sections.menu || sections.quick;
4263
+ if (wanted && dispose === null) {
3343
4264
  dispose = installInterceptors({
3344
4265
  settings: () => live.getSnapshot(),
3345
4266
  // 「仅首次」由这里决定是否算进这一批:会话还是空的(blank)才带上。
3346
- promptsForSend: () => appendBatchForSend(book.getSnapshot(), currentBlankSession()),
4267
+ // 「快捷指令」栏关掉时这里直接给空批次 —— 这是唯一一处"关掉就不附加"的闸,
4268
+ // 键位发送与官方按钮两条路都从这里取批次,不需要各写一遍。
4269
+ promptsForSend: () => activeSections(live.getSnapshot()).quick ? appendBatchForSend(book.getSnapshot(), currentBlankSession()) : [],
3347
4270
  setMenu: (state2) => {
3348
4271
  menu2.set(state2);
3349
4272
  },
3350
4273
  menuOpen: () => menu2.getSnapshot() !== null
3351
4274
  });
3352
- } else if (!enabled) {
4275
+ } else if (!wanted) {
3353
4276
  dispose?.();
3354
4277
  dispose = null;
3355
- menu2.set(null);
3356
- panel.set(null);
3357
4278
  }
3358
- if (live.getSnapshot().menuMode !== "custom") menu2.set(null);
3359
- if (!live.getSnapshot().enabled) panel.set(null);
4279
+ if (settings.menuMode !== "custom" || !sections.menu) menu2.set(null);
4280
+ if (!sections.quick) panel.set(null);
3360
4281
  };
3361
4282
  syncInterceptors();
3362
4283
  const unsubscribe = live.subscribe(syncInterceptors);