dsh-composer-ux 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -38,9 +38,71 @@ __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
108
  var PANEL_SCROLL_FIELD = "panelScroll";
@@ -56,7 +118,31 @@ var MENU_FIELDS = [
56
118
  "menuDelete",
57
119
  "menuSelectAll"
58
120
  ];
121
+ var MENU_MODE_FIELD = "menuMode";
59
122
  var MENU_NATIVE_FIELD = "menuNative";
123
+ var MENU_MODES = [
124
+ {
125
+ id: "official",
126
+ label: "\u5B98\u65B9",
127
+ hint: "\u672C\u63D2\u4EF6\u5B8C\u5168\u4E0D\u4ECB\u5165\uFF1ADSH \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\u901A\u5E38\u770B\u5230\u7684\u5C31\u662F\u6D4F\u89C8\u5668\u7684\u83DC\u5355\uFF09"
128
+ },
129
+ {
130
+ id: "browser",
131
+ label: "\u6D4F\u89C8\u5668",
132
+ hint: "\u56FA\u5B9A\u4F7F\u7528\u6D4F\u89C8\u5668\u81EA\u5E26\u7684\u83DC\u5355\uFF0C\u5E76\u5728\u672C\u63D2\u4EF6\u8FD9\u4E00\u5C42\u6321\u4F4F\u5176\u5B83\u63D2\u4EF6\u7684\u83DC\u5355\uFF1B\u7C98\u8D34\u514D\u6388\u6743\u3001\u96F6\u914D\u7F6E"
133
+ },
134
+ {
135
+ id: "custom",
136
+ label: "\u81EA\u5B9A\u4E49",
137
+ hint: "\u4F7F\u7528\u672C\u63D2\u4EF6\u7684\u56FA\u5B9A\u6837\u5F0F\u83DC\u5355\uFF1B\u672A\u9009\u4E2D\u6587\u672C\u65F6\u300C\u526A\u5207 / \u590D\u5236 / \u5220\u9664\u300D\u7F6E\u7070\uFF0C\u7C98\u8D34\u9700\u8981\u6D4F\u89C8\u5668\u526A\u8D34\u677F\u6388\u6743"
138
+ }
139
+ ];
140
+ function menuModeFrom(storedMode, legacyNative) {
141
+ if (storedMode === "official" || storedMode === "browser" || storedMode === "custom") return storedMode;
142
+ if (legacyNative === true) return "browser";
143
+ if (legacyNative === false) return "custom";
144
+ return DEFAULT_SETTINGS.menuMode;
145
+ }
60
146
  var QUICK_PROMPTS_FIELD = "quickPrompts";
61
147
  var OPTIMIZER_TIER_FIELD = "optimizerTier";
62
148
  var QUICK_PROMPT_MAX = 60;
@@ -68,6 +154,16 @@ var QUICK_PROMPTS_API_PATH = "/composer-ux/prompts";
68
154
  var QUICK_BOOK_VERSION = 2;
69
155
  var DEFAULT_CATEGORY_NAME = "\u9ED8\u8BA4";
70
156
  var OPTIMIZER_API_PATH = "/composer-ux/optimize";
157
+ var INSERT_MODES = [
158
+ { id: "never", label: "\u5173", hint: "\u70B9\u6761\u76EE\u53EA\u63D2\u5165\u8F93\u5165\u6846\uFF0C\u53D1\u9001\u65F6\u4E0D\u9644\u52A0" },
159
+ { id: "always", label: "\u6BCF\u6B21", hint: "\u6BCF\u6B21\u53D1\u9001\u90FD\u628A\u8FD9\u6761\u9644\u52A0\u5230\u6D88\u606F\u672B\u5C3E" },
160
+ { id: "first", label: "\u4EC5\u9996\u6B21", hint: "\u53EA\u5728\u5F53\u524D\u4F1A\u8BDD\u7684\u7B2C\u4E00\u6761\u6D88\u606F\u4E0A\u9644\u52A0" }
161
+ ];
162
+ function insertModeOf(prompt) {
163
+ if (prompt.always) return "always";
164
+ if (prompt.firstOnly) return "first";
165
+ return "never";
166
+ }
71
167
  var OPTIMIZER_TIERS = [
72
168
  { 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" },
73
169
  { 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" },
@@ -75,15 +171,15 @@ var OPTIMIZER_TIERS = [
75
171
  ];
76
172
  var DEFAULT_OPTIMIZER_TIER = "advanced";
77
173
  var DEFAULT_QUICK_PROMPTS = [
78
- { 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 },
79
- { 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 },
80
- { id: "builtin-3", label: "\u4EC5\u8BF4\u660E\u539F\u56E0", prompt: "\u4EC5\u8BF4\u660E\u539F\u56E0\uFF0C\u4E0D\u8981\u505A\u5176\u4ED6\u52A8\u4F5C\u3002", always: false },
81
- { id: "builtin-4", label: "\u5206\u6790\u540E\u76F4\u63A5\u5E72", prompt: "\u5206\u6790\u539F\u56E0\uFF0C\u7136\u540E\u76F4\u63A5\u5F00\u59CB\u5E72\u6D3B\uFF0C\u4E0D\u9700\u8981\u8FC7\u95EE\u6211\u3002", always: false },
82
- { id: "builtin-5", label: "\u63D0\u4EA4\u4EE3\u7801", prompt: "\u8BF7\u5E2E\u6211\u63D0\u4EA4\u4EE3\u7801\uFF1A\u68C0\u67E5\u5F53\u524D git \u53D8\u66F4\uFF0C\u751F\u6210\u89C4\u8303\u7684 commit message \u5E76\u6267\u884C\u63D0\u4EA4\u3002", always: false },
83
- { id: "builtin-6", label: "\u7ED9\u65B9\u6848", prompt: "\u8BF7\u9488\u5BF9\u4E0A\u9762\u7684\u95EE\u9898\u7ED9\u51FA\u4E00\u4E2A\u5B8C\u6574\u65B9\u6848\uFF0C\u5305\u62EC\u601D\u8DEF\u3001\u6B65\u9AA4\u3001\u6CE8\u610F\u4E8B\u9879\u548C\u98CE\u9669\u3002", always: false },
84
- { id: "builtin-7", label: "\u89E3\u91CA\u4EE3\u7801", prompt: "\u8BF7\u89E3\u91CA\u8FD9\u6BB5\u4EE3\u7801\u7684\u4F5C\u7528\u548C\u5B9E\u73B0\u601D\u8DEF\u3002", always: false },
85
- { id: "builtin-8", label: "\u5199\u6D4B\u8BD5", prompt: "\u8BF7\u4E3A\u4E0B\u9762\u7684\u4EE3\u7801\u7F16\u5199\u5355\u5143\u6D4B\u8BD5\u3002", always: false },
86
- { id: "builtin-9", label: "\u4EE3\u7801\u5BA1\u67E5", prompt: "\u8BF7\u5BF9\u4E0B\u9762\u7684\u4EE3\u7801\u8FDB\u884C\u4EE3\u7801\u5BA1\u67E5\uFF0C\u6307\u51FA\u95EE\u9898\u5E76\u7ED9\u51FA\u6539\u8FDB\u5EFA\u8BAE\u3002", always: false }
174
+ { 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 },
175
+ { 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 },
176
+ { id: "builtin-3", label: "\u4EC5\u8BF4\u660E\u539F\u56E0", prompt: "\u4EC5\u8BF4\u660E\u539F\u56E0\uFF0C\u4E0D\u8981\u505A\u5176\u4ED6\u52A8\u4F5C\u3002", always: false, firstOnly: false },
177
+ { id: "builtin-4", label: "\u5206\u6790\u540E\u76F4\u63A5\u5E72", prompt: "\u5206\u6790\u539F\u56E0\uFF0C\u7136\u540E\u76F4\u63A5\u5F00\u59CB\u5E72\u6D3B\uFF0C\u4E0D\u9700\u8981\u8FC7\u95EE\u6211\u3002", always: false, firstOnly: false },
178
+ { id: "builtin-5", label: "\u63D0\u4EA4\u4EE3\u7801", prompt: "\u8BF7\u5E2E\u6211\u63D0\u4EA4\u4EE3\u7801\uFF1A\u68C0\u67E5\u5F53\u524D git \u53D8\u66F4\uFF0C\u751F\u6210\u89C4\u8303\u7684 commit message \u5E76\u6267\u884C\u63D0\u4EA4\u3002", always: false, firstOnly: false },
179
+ { id: "builtin-6", label: "\u7ED9\u65B9\u6848", prompt: "\u8BF7\u9488\u5BF9\u4E0A\u9762\u7684\u95EE\u9898\u7ED9\u51FA\u4E00\u4E2A\u5B8C\u6574\u65B9\u6848\uFF0C\u5305\u62EC\u601D\u8DEF\u3001\u6B65\u9AA4\u3001\u6CE8\u610F\u4E8B\u9879\u548C\u98CE\u9669\u3002", always: false, firstOnly: false },
180
+ { id: "builtin-7", label: "\u89E3\u91CA\u4EE3\u7801", prompt: "\u8BF7\u89E3\u91CA\u8FD9\u6BB5\u4EE3\u7801\u7684\u4F5C\u7528\u548C\u5B9E\u73B0\u601D\u8DEF\u3002", always: false, firstOnly: false },
181
+ { id: "builtin-8", label: "\u5199\u6D4B\u8BD5", prompt: "\u8BF7\u4E3A\u4E0B\u9762\u7684\u4EE3\u7801\u7F16\u5199\u5355\u5143\u6D4B\u8BD5\u3002", always: false, firstOnly: false },
182
+ { id: "builtin-9", label: "\u4EE3\u7801\u5BA1\u67E5", prompt: "\u8BF7\u5BF9\u4E0B\u9762\u7684\u4EE3\u7801\u8FDB\u884C\u4EE3\u7801\u5BA1\u67E5\uFF0C\u6307\u51FA\u95EE\u9898\u5E76\u7ED9\u51FA\u6539\u8FDB\u5EFA\u8BAE\u3002", always: false, firstOnly: false }
87
183
  ];
88
184
  function newQuickPromptId() {
89
185
  return `qp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
@@ -110,7 +206,13 @@ function asPromptRow(value) {
110
206
  const id = typeof row2.id === "string" && row2.id !== "" ? row2.id.slice(0, 64) : newQuickPromptId();
111
207
  const order = typeof row2.order === "number" && Number.isFinite(row2.order) ? Math.max(1, Math.round(row2.order)) : void 0;
112
208
  return {
113
- prompt: { id, label: label === "" ? prompt.slice(0, 12) : label, prompt, always: row2.always === true || row2.autoSend === true },
209
+ prompt: {
210
+ id,
211
+ label: label === "" ? prompt.slice(0, 12) : label,
212
+ prompt,
213
+ always: row2.always === true || row2.autoSend === true,
214
+ firstOnly: row2.firstOnly === true || row2.autoSendFirst === true
215
+ },
114
216
  order
115
217
  };
116
218
  }
@@ -166,7 +268,15 @@ function flattenQuickPrompts(book) {
166
268
  return book.categories.flatMap((category) => category.prompts);
167
269
  }
168
270
  function alwaysQuickPrompts(book) {
169
- return flattenQuickPrompts(book).filter((prompt) => prompt.always);
271
+ return flattenQuickPrompts(book).filter((prompt) => insertModeOf(prompt) === "always");
272
+ }
273
+ function firstOnlyQuickPrompts(book) {
274
+ return flattenQuickPrompts(book).filter((prompt) => insertModeOf(prompt) === "first");
275
+ }
276
+ function appendBatchForSend(book, blank) {
277
+ const every = alwaysQuickPrompts(book);
278
+ if (!blank) return every;
279
+ return [...every, ...firstOnlyQuickPrompts(book)];
170
280
  }
171
281
  var HEADER_ENABLED_FIELD = "headerEnabled";
172
282
  var HEADER_NAME_FIELD = "headerName";
@@ -179,7 +289,14 @@ var DEFAULT_HEADER_NAME = "x-opencode-session";
179
289
  var HEADER_VALUE_MAX = 200;
180
290
  var HEADER_NAME_MAX = 64;
181
291
  var DEFAULT_SETTINGS = {
292
+ // 总开关默认开:它只是总闸,真正"要不要用这一栏"由下面五个开关决定(默认关)。
182
293
  enabled: true,
294
+ // 五栏默认关(老文档由 sectionEnabledOf 迁移成"碰过就开")。
295
+ keysEnabled: false,
296
+ menuEnabled: false,
297
+ quickEnabled: false,
298
+ panelEnabled: false,
299
+ terminalEnabled: false,
183
300
  sendKey: "Enter",
184
301
  newlineKey: "Shift+Enter",
185
302
  menuUndo: true,
@@ -189,7 +306,7 @@ var DEFAULT_SETTINGS = {
189
306
  menuPaste: true,
190
307
  menuDelete: true,
191
308
  menuSelectAll: true,
192
- menuNative: false,
309
+ menuMode: "official",
193
310
  panelScroll: true,
194
311
  panelResize: true,
195
312
  headerEnabled: false,
@@ -200,8 +317,24 @@ var DEFAULT_SETTINGS = {
200
317
  headerAppliedValue: "",
201
318
  headerStatus: "",
202
319
  quickPrompts: DEFAULT_QUICK_PROMPTS,
203
- optimizerTier: DEFAULT_OPTIMIZER_TIER
320
+ optimizerTier: DEFAULT_OPTIMIZER_TIER,
321
+ terminalMode: DEFAULT_TERMINAL_MODE,
322
+ terminalBashPath: "",
323
+ terminalCandidates: [],
324
+ terminalStatus: "",
325
+ terminalEffective: ""
204
326
  };
327
+ function activeSections(settings) {
328
+ const on = settings.enabled;
329
+ return {
330
+ keys: on && settings.keysEnabled,
331
+ menu: on && settings.menuEnabled,
332
+ quick: on && settings.quickEnabled,
333
+ panel: on && settings.panelEnabled,
334
+ header: on && settings.headerEnabled,
335
+ terminal: on && settings.terminalEnabled
336
+ };
337
+ }
205
338
  var SEND_PRESETS = ["Enter", "Ctrl+Enter", "Alt+Enter", "Shift+Enter"];
206
339
  var NEWLINE_PRESETS = ["Shift+Enter", "Enter", "Ctrl+Enter", "Alt+Enter"];
207
340
  var MENU_ITEMS = [
@@ -222,6 +355,25 @@ function newSessionId() {
222
355
  ).join("");
223
356
  return `${hex(8)}-${hex(4)}-4${hex(3)}-a${hex(3)}-${hex(12)}`;
224
357
  }
358
+ var SECTION_SIGNALS = {
359
+ [KEYS_ENABLED_FIELD]: (source) => touched(source, SEND_KEY_FIELD, DEFAULT_SETTINGS.sendKey) || touched(source, NEWLINE_KEY_FIELD, DEFAULT_SETTINGS.newlineKey),
360
+ // 「官方」=本插件不介入,等价于关;所以只有选过另外两档才算"碰过"。
361
+ // (`menuModeFrom` 对"两个键都没有"给的就是 'official',天然满足"缺省 = 默认"。)
362
+ [MENU_ENABLED_FIELD]: (source) => menuModeFrom(source[MENU_MODE_FIELD], source[MENU_NATIVE_FIELD]) !== "official",
363
+ [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),
364
+ [PANEL_ENABLED_FIELD]: (source) => touched(source, PANEL_SCROLL_FIELD, true) || touched(source, PANEL_RESIZE_FIELD, true) || source[PANEL_WIDTH_FIELD] !== void 0 || source[PANEL_HEIGHT_FIELD] !== void 0,
365
+ [TERMINAL_ENABLED_FIELD]: (source) => touched(source, TERMINAL_MODE_FIELD, DEFAULT_TERMINAL_MODE) || touched(source, TERMINAL_BASH_PATH_FIELD, "")
366
+ };
367
+ function touched(source, field, untouched) {
368
+ const value = source[field];
369
+ return value !== void 0 && value !== untouched;
370
+ }
371
+ function sectionEnabledOf(field, source) {
372
+ const explicit = source[field];
373
+ if (typeof explicit === "boolean") return explicit;
374
+ const signal = SECTION_SIGNALS[field];
375
+ return signal === void 0 ? false : signal(source);
376
+ }
225
377
  function sanitizeSettings(value) {
226
378
  const source = typeof value === "object" && value !== null ? value : {};
227
379
  const asString = (field) => {
@@ -255,7 +407,13 @@ function sanitizeSettings(value) {
255
407
  const id = typeof row2.id === "string" && row2.id !== "" ? row2.id.slice(0, 64) : newQuickPromptId();
256
408
  if (seen.has(id)) continue;
257
409
  seen.add(id);
258
- out.push({ id, label: label === "" ? prompt.slice(0, 12) : label, prompt, always: row2.always === true });
410
+ out.push({
411
+ id,
412
+ label: label === "" ? prompt.slice(0, 12) : label,
413
+ prompt,
414
+ always: row2.always === true,
415
+ firstOnly: row2.firstOnly === true
416
+ });
259
417
  }
260
418
  return out;
261
419
  };
@@ -265,6 +423,12 @@ function sanitizeSettings(value) {
265
423
  };
266
424
  return {
267
425
  enabled: asBool(ENABLED_FIELD),
426
+ // 五栏开关:显式写过听它的,否则按"用户碰过没"迁移(见 sectionEnabledOf)。
427
+ keysEnabled: sectionEnabledOf(KEYS_ENABLED_FIELD, source),
428
+ menuEnabled: sectionEnabledOf(MENU_ENABLED_FIELD, source),
429
+ quickEnabled: sectionEnabledOf(QUICK_ENABLED_FIELD, source),
430
+ panelEnabled: sectionEnabledOf(PANEL_ENABLED_FIELD, source),
431
+ terminalEnabled: sectionEnabledOf(TERMINAL_ENABLED_FIELD, source),
268
432
  sendKey: asString(SEND_KEY_FIELD),
269
433
  newlineKey: asString(NEWLINE_KEY_FIELD),
270
434
  menuUndo: asBool("menuUndo"),
@@ -274,7 +438,7 @@ function sanitizeSettings(value) {
274
438
  menuPaste: asBool("menuPaste"),
275
439
  menuDelete: asBool("menuDelete"),
276
440
  menuSelectAll: asBool("menuSelectAll"),
277
- menuNative: asBool(MENU_NATIVE_FIELD),
441
+ menuMode: menuModeFrom(source[MENU_MODE_FIELD], source[MENU_NATIVE_FIELD]),
278
442
  panelScroll: asBool(PANEL_SCROLL_FIELD),
279
443
  panelResize: asBool(PANEL_RESIZE_FIELD),
280
444
  panelWidth: asSize(PANEL_WIDTH_FIELD),
@@ -289,7 +453,14 @@ function sanitizeSettings(value) {
289
453
  headerAppliedValue: asText(HEADER_APPLIED_VALUE_FIELD, HEADER_VALUE_MAX),
290
454
  headerStatus: asText(HEADER_STATUS_FIELD, HEADER_VALUE_MAX),
291
455
  quickPrompts: asQuickPrompts(),
292
- optimizerTier: asTier()
456
+ optimizerTier: asTier(),
457
+ terminalMode: terminalModeFrom(source[TERMINAL_MODE_FIELD]),
458
+ // 路径只做长度与归一化收窄,不在这里判"存不存在"——那是宿主半的探测结论,
459
+ // 由状态行告诉用户(用户看得见自己填了什么,比悄悄清空好)。
460
+ terminalBashPath: asText(TERMINAL_BASH_PATH_FIELD, 400),
461
+ terminalCandidates: sanitizeTerminalCandidates(source[TERMINAL_CANDIDATES_FIELD]),
462
+ terminalStatus: asText(TERMINAL_STATUS_FIELD, 400),
463
+ terminalEffective: asText(TERMINAL_EFFECTIVE_FIELD, 16)
293
464
  };
294
465
  }
295
466
 
@@ -343,7 +514,8 @@ function bookCounts(book) {
343
514
  return {
344
515
  categories: book.categories.length,
345
516
  prompts: prompts.length,
346
- always: prompts.filter((prompt) => prompt.always).length
517
+ always: prompts.filter((prompt) => insertModeOf(prompt) === "always").length,
518
+ first: prompts.filter((prompt) => insertModeOf(prompt) === "first").length
347
519
  };
348
520
  }
349
521
  function mapCategory(book, categoryId, edit) {
@@ -379,7 +551,16 @@ function withCategoryMoved(book, categoryId, delta) {
379
551
  function withPromptAdded(book, categoryId) {
380
552
  return mapCategory(book, categoryId, (category) => {
381
553
  if (category.prompts.length >= QUICK_PROMPT_MAX) return category;
382
- return { ...category, prompts: [...category.prompts, { id: newQuickPromptId(), label: "\u65B0\u6307\u4EE4", prompt: "", always: false }] };
554
+ return {
555
+ ...category,
556
+ prompts: [...category.prompts, {
557
+ id: newQuickPromptId(),
558
+ label: "\u65B0\u6307\u4EE4",
559
+ prompt: "\uFF08\u5F85\u586B\u5199\uFF09",
560
+ always: false,
561
+ firstOnly: false
562
+ }]
563
+ };
383
564
  });
384
565
  }
385
566
  function withPromptPatched(book, categoryId, promptId, patch) {
@@ -390,10 +571,20 @@ function withPromptPatched(book, categoryId, promptId, patch) {
390
571
  const label = patch.label === void 0 ? prompt.label : patch.label.slice(0, QUICK_LABEL_MAX);
391
572
  const text = patch.prompt === void 0 ? prompt.prompt : patch.prompt.slice(0, QUICK_TEXT_MAX);
392
573
  const always = patch.always === void 0 ? prompt.always : patch.always;
393
- return { id: prompt.id, label, prompt: text, always };
574
+ const firstOnly = patch.firstOnly === void 0 ? prompt.firstOnly : patch.firstOnly;
575
+ return { id: prompt.id, label, prompt: text, always, firstOnly };
394
576
  })
395
577
  }));
396
578
  }
579
+ function withInsertMode(book, promptId, mode) {
580
+ const hit = findPrompt(book, promptId);
581
+ if (hit === void 0) return book;
582
+ if (insertModeOf(hit.prompt) === mode) return book;
583
+ return withPromptPatched(book, hit.category.id, promptId, {
584
+ always: mode === "always",
585
+ firstOnly: mode === "first"
586
+ });
587
+ }
397
588
  function withPromptRemoved(book, categoryId, promptId) {
398
589
  return mapCategory(book, categoryId, (category) => ({
399
590
  ...category,
@@ -411,10 +602,30 @@ function withPromptMoved(book, categoryId, promptId, delta) {
411
602
  prompts.splice(next, 0, moved);
412
603
  return mapCategory(book, categoryId, (target) => ({ ...target, prompts }));
413
604
  }
414
- function withAlwaysToggled(book, promptId, value) {
605
+ function promptsElsewhere(book, categoryId) {
606
+ return book.categories.filter((category) => category.id !== categoryId).flatMap((category) => category.prompts.map((prompt) => ({
607
+ categoryId: category.id,
608
+ categoryName: category.name,
609
+ prompt
610
+ })));
611
+ }
612
+ function withPromptMovedToCategory(book, promptId, toCategoryId) {
415
613
  const hit = findPrompt(book, promptId);
416
- if (hit === void 0) return book;
417
- return withPromptPatched(book, hit.category.id, promptId, { always: value });
614
+ if (hit === void 0 || hit.category.id === toCategoryId) return book;
615
+ const target = categoryOf(book, toCategoryId);
616
+ if (target === void 0 || target.prompts.length >= QUICK_PROMPT_MAX) return book;
617
+ return {
618
+ version: book.version,
619
+ categories: book.categories.map((category) => {
620
+ if (category.id === hit.category.id) {
621
+ return { ...category, prompts: category.prompts.filter((prompt) => prompt.id !== promptId) };
622
+ }
623
+ if (category.id === toCategoryId) {
624
+ return { ...category, prompts: [...category.prompts, hit.prompt] };
625
+ }
626
+ return category;
627
+ })
628
+ };
418
629
  }
419
630
 
420
631
  // src/client/chords.ts
@@ -520,17 +731,22 @@ function displayChord(chord) {
520
731
  // src/client/quick-commands.ts
521
732
  var COMPOSER_SELECTOR = "[data-composer-input]";
522
733
  var CARD_SELECTOR = "[data-composer-card]";
523
- var state = { actions: null, draft: "", sessionId: "" };
734
+ var state = { actions: null, draft: "", sessionId: "", blank: false };
524
735
  function publishInputBridge(next) {
525
736
  state.actions = next.actions;
526
737
  state.draft = next.draft;
527
738
  state.sessionId = next.sessionId;
739
+ state.blank = next.blank;
528
740
  }
529
741
  function releaseInputBridge(sessionId) {
530
742
  if (state.sessionId !== sessionId) return;
531
743
  state.actions = null;
532
744
  state.draft = "";
533
745
  state.sessionId = "";
746
+ state.blank = false;
747
+ }
748
+ function currentBlankSession() {
749
+ return state.blank === true;
534
750
  }
535
751
  function draftFromDom() {
536
752
  const el = document.querySelector(COMPOSER_SELECTOR);
@@ -540,24 +756,21 @@ function draftFromDom() {
540
756
  function currentDraft() {
541
757
  return state.actions === null ? draftFromDom() : state.draft;
542
758
  }
543
- function alwaysPrompts(prompts) {
544
- return prompts.filter((item) => item.always === true && item.prompt.trim() !== "");
545
- }
546
- function withAlwaysPrompts(draft, prompts) {
547
- const picked = alwaysPrompts(prompts);
759
+ function withPromptsAppended(draft, prompts) {
760
+ const picked = prompts.filter((item) => item.prompt.trim() !== "");
548
761
  if (picked.length === 0) return null;
549
- const base = draft.replace(/\s+$/, "");
550
- if (base === "") return null;
762
+ const base2 = draft.replace(/\s+$/, "");
763
+ if (base2 === "") return null;
551
764
  const suffix = picked.map((item) => item.prompt.trim()).join("\n\n");
552
- if (base.endsWith(suffix)) return null;
553
- return `${base}
765
+ if (base2.endsWith(suffix)) return null;
766
+ return `${base2}
554
767
 
555
768
  ${suffix}`;
556
769
  }
557
- function applyAlwaysPrompts(prompts) {
770
+ function applyPromptsForSend(prompts) {
558
771
  const actions = state.actions;
559
772
  if (actions === null) return false;
560
- const next = withAlwaysPrompts(currentDraft(), prompts);
773
+ const next = withPromptsAppended(currentDraft(), prompts);
561
774
  if (next === null) return false;
562
775
  actions.setDraft(next);
563
776
  return true;
@@ -669,6 +882,7 @@ function composing(event) {
669
882
  function installInterceptors(deps) {
670
883
  const onKeyDown = (event) => {
671
884
  if (replaying) return;
885
+ if (!activeSections(deps.settings()).keys) return;
672
886
  const root = findComposerRoot(event.target);
673
887
  if (root === null) return;
674
888
  if (composing(event)) return;
@@ -681,7 +895,7 @@ function installInterceptors(deps) {
681
895
  event.stopPropagation();
682
896
  if (event.repeat) return;
683
897
  if (gesture === "send") {
684
- applyAlwaysPrompts(deps.alwaysPrompts());
898
+ applyPromptsForSend(deps.promptsForSend());
685
899
  dispatchKey(root, chordToInit("Enter"));
686
900
  } else if (gesture === "newline") {
687
901
  dispatchKey(root, chordToInit("Shift+Enter"));
@@ -692,13 +906,18 @@ function installInterceptors(deps) {
692
906
  const onContextMenu = (event) => {
693
907
  const root = findComposerRoot(event.target);
694
908
  if (root === null) return;
695
- if (deps.settings().menuNative) {
909
+ const settings = deps.settings();
910
+ if (!activeSections(settings).menu) return;
911
+ const mode = settings.menuMode;
912
+ if (mode === "official") return;
913
+ if (mode === "browser") {
696
914
  if (deps.menuOpen()) deps.setMenu(null);
697
915
  event.stopImmediatePropagation();
698
916
  event.stopPropagation();
699
917
  return;
700
918
  }
701
919
  event.preventDefault();
920
+ event.stopImmediatePropagation();
702
921
  event.stopPropagation();
703
922
  const selection = window.getSelection();
704
923
  const hasSelection = selection !== null && !selection.isCollapsed && selection.anchorNode !== null && root.contains(selection.anchorNode);
@@ -709,7 +928,7 @@ function installInterceptors(deps) {
709
928
  if (replayingSendClick) return;
710
929
  const button = sendButtonOf(event.target);
711
930
  if (button === null) return;
712
- if (!applyAlwaysPrompts(deps.alwaysPrompts())) return;
931
+ if (!applyPromptsForSend(deps.promptsForSend())) return;
713
932
  event.preventDefault();
714
933
  event.stopPropagation();
715
934
  replayingSendClick = true;
@@ -778,7 +997,7 @@ function isClipboardTimeout(error) {
778
997
  function isFirefox() {
779
998
  return typeof navigator !== "undefined" && /Firefox\//.test(navigator.userAgent);
780
999
  }
781
- var FIREFOX_TIP = "Firefox \u6BCF\u6B21\u8BFB\u526A\u8D34\u677F\u90FD\u8981\u70B9\u300C\u7C98\u8D34(P)\u300D\u786E\u8BA4\uFF1A\u5730\u5740\u680F\u8F93\u5165 about:config \u2192 \u63A5\u53D7\u98CE\u9669\u7EE7\u7EED \u2192 \u53F3\u952E\u65B0\u5EFA\u300C\u6574\u6570\u300D\u2192 \u540D\u79F0\u586B permissions.default.clipboard-read \u2192 \u503C\u586B 1 \u2192 \u91CD\u8FDB DSH\uFF1B\u4E4B\u540E\u70B9\u4E00\u6B21\u7C98\u8D34\u5373\u6210\u529F\uFF08\u6216\u76F4\u63A5 Ctrl+V\uFF09";
1000
+ var FIREFOX_TIP = "Firefox \u4E0D\u5141\u8BB8\u7F51\u9875\u9759\u9ED8\u8BFB\u526A\u8D34\u677F\uFF1A\u8BF7\u5728\u5F39\u51FA\u7684\u300C\u7C98\u8D34(P)\u300D\u5C0F\u7A97\u4E0A\u70B9\u4E00\u4E0B\uFF08\u7EA6 1 \u79D2\u540E\u624D\u53EF\u70B9\uFF0C\u8FD9\u662F Firefox \u7684\u5B89\u5168\u673A\u5236\uFF0C\u63D2\u4EF6\u5173\u4E0D\u6389\uFF09\uFF1B\u4E0D\u60F3\u591A\u8FD9\u4E00\u6B65\u5C31\u76F4\u63A5\u6309 Ctrl+V";
782
1001
  async function pasteText(root) {
783
1002
  const insertText = (text2) => {
784
1003
  if (!document.activeElement || !root.contains(document.activeElement)) {
@@ -954,7 +1173,8 @@ var CARD_CSS = `
954
1173
  .dsh-ux-cardHeader {
955
1174
  appearance: none;
956
1175
  box-sizing: border-box;
957
- width: 100%;
1176
+ flex: 1;
1177
+ min-width: 0;
958
1178
  font: inherit;
959
1179
  color: inherit;
960
1180
  text-align: left;
@@ -971,6 +1191,35 @@ var CARD_CSS = `
971
1191
  outline: 2px solid var(--dsw-alias-brand-primary);
972
1192
  outline-offset: -2px;
973
1193
  }
1194
+ /* \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
1195
+ \u4E0D\u80FD\u5728 <button> \u91CC\u585E\u6309\u94AE\uFF0C\u6240\u4EE5\u4E24\u8005\u662F\u5144\u5F1F\u8282\u70B9\u3002 */
1196
+ .dsh-ux-cardHeaderRow {
1197
+ display: flex;
1198
+ align-items: center;
1199
+ flex-wrap: wrap;
1200
+ gap: 6px;
1201
+ padding-right: 12px;
1202
+ }
1203
+ .dsh-ux-cardControls {
1204
+ align-items: center;
1205
+ display: inline-flex;
1206
+ flex: none;
1207
+ flex-wrap: wrap;
1208
+ gap: 8px;
1209
+ }
1210
+ /* \u6807\u9898\u884C\u91CC\u7684"\u6587\u5B57 + \u5C0F\u5F00\u5173"\uFF08\u5BFC\u822A\u6EDA\u52A8 / \u8FB9\u7F18\u7F29\u653E\uFF09\u3002 */
1211
+ .dsh-ux-miniToggle {
1212
+ align-items: center;
1213
+ color: var(--dsw-alias-label-secondary);
1214
+ display: inline-flex;
1215
+ flex: none;
1216
+ font-size: 11px;
1217
+ gap: 5px;
1218
+ white-space: nowrap;
1219
+ }
1220
+ /* \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 */
1221
+ .dsh-ux-cardOff { border-style: dashed; }
1222
+ .dsh-ux-cardOff .dsh-ux-cardBody { opacity: .6; }
974
1223
  .dsh-ux-cardHeaderStatic {
975
1224
  box-sizing: border-box;
976
1225
  display: flex;
@@ -998,6 +1247,109 @@ var CARD_CSS = `
998
1247
  line-height: 1.5;
999
1248
  margin: 0;
1000
1249
  }
1250
+ .dsh-ux-cardLink {
1251
+ align-items: center;
1252
+ color: var(--dsw-alias-label-secondary);
1253
+ display: inline-flex;
1254
+ flex: none;
1255
+ font-size: 12px;
1256
+ gap: 4px;
1257
+ text-decoration: none;
1258
+ white-space: nowrap;
1259
+ }
1260
+ .dsh-ux-cardLink:hover {
1261
+ color: var(--dsw-alias-brand-primary);
1262
+ text-decoration: underline;
1263
+ }
1264
+ /* \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 */
1265
+ .dsh-ux-cardActions {
1266
+ align-items: center;
1267
+ display: inline-flex;
1268
+ flex: none;
1269
+ gap: 10px;
1270
+ }
1271
+ .dsh-ux-restartButton {
1272
+ appearance: none;
1273
+ background: 0 0;
1274
+ border: 1px solid var(--dsw-alias-border-l2);
1275
+ border-radius: 999px;
1276
+ color: var(--dsw-alias-label-primary);
1277
+ cursor: pointer;
1278
+ flex: none;
1279
+ font: inherit;
1280
+ font-size: 12px;
1281
+ line-height: 1;
1282
+ padding: 6px 12px;
1283
+ transition: border-color .16s, color .16s, background .16s;
1284
+ white-space: nowrap;
1285
+ }
1286
+ .dsh-ux-restartButton:hover:not(:disabled) {
1287
+ background: var(--dsw-alias-interactive-bg-hover);
1288
+ border-color: var(--dsw-alias-brand-primary);
1289
+ color: var(--dsw-alias-brand-primary);
1290
+ }
1291
+ .dsh-ux-restartButton:disabled {
1292
+ color: var(--dsw-alias-label-tertiary);
1293
+ cursor: default;
1294
+ opacity: .7;
1295
+ }
1296
+ /* \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 */
1297
+ .dsh-ux-restartBanner {
1298
+ align-items: center;
1299
+ background: var(--dsw-alias-bg-layer-2);
1300
+ border: 1px solid var(--dsw-alias-border-l2);
1301
+ border-radius: 10px;
1302
+ display: flex;
1303
+ gap: 10px;
1304
+ margin: 0 16px 12px;
1305
+ padding: 10px 12px;
1306
+ }
1307
+ .dsh-ux-restartBannerFailed { border-color: var(--dsw-alias-state-error-primary); }
1308
+ .dsh-ux-restartBannerText {
1309
+ color: var(--dsw-alias-label-secondary);
1310
+ flex: 1;
1311
+ font-size: 12px;
1312
+ line-height: 1.5;
1313
+ min-width: 0;
1314
+ }
1315
+ .dsh-ux-restartBannerFailed .dsh-ux-restartBannerText { color: var(--dsw-alias-state-error-primary); }
1316
+ .dsh-ux-restartBannerActions {
1317
+ align-items: center;
1318
+ display: inline-flex;
1319
+ flex: none;
1320
+ gap: 8px;
1321
+ }
1322
+ .dsh-ux-restartGo {
1323
+ appearance: none;
1324
+ background: var(--dsw-alias-button-primary-fill);
1325
+ border: 0;
1326
+ border-radius: 999px;
1327
+ color: var(--dsw-alias-label-primary-foreground);
1328
+ cursor: pointer;
1329
+ font: inherit;
1330
+ font-size: 12px;
1331
+ line-height: 1;
1332
+ padding: 7px 14px;
1333
+ white-space: nowrap;
1334
+ }
1335
+ .dsh-ux-restartGo:hover { background: var(--dsw-alias-brand-primary); }
1336
+ .dsh-ux-restartCancel {
1337
+ appearance: none;
1338
+ background: 0 0;
1339
+ border: 1px solid var(--dsw-alias-border-l2);
1340
+ border-radius: 999px;
1341
+ color: var(--dsw-alias-label-secondary);
1342
+ cursor: pointer;
1343
+ font: inherit;
1344
+ font-size: 12px;
1345
+ line-height: 1;
1346
+ padding: 7px 14px;
1347
+ white-space: nowrap;
1348
+ }
1349
+ .dsh-ux-restartCancel:hover {
1350
+ border-color: var(--dsw-alias-label-dimmed);
1351
+ color: var(--dsw-alias-label-primary);
1352
+ }
1001
1353
  .dsh-ux-cardChevron {
1002
1354
  color: var(--dsw-alias-label-tertiary);
1003
1355
  flex: none;
@@ -1302,20 +1654,6 @@ var quickItemPreview = {
1302
1654
  textOverflow: "ellipsis",
1303
1655
  whiteSpace: "nowrap"
1304
1656
  };
1305
- var quickAlwaysLabel = {
1306
- display: "inline-flex",
1307
- alignItems: "center",
1308
- gap: 4,
1309
- flex: "0 0 auto",
1310
- color: "var(--dsw-alias-label-tertiary)",
1311
- fontSize: 11,
1312
- whiteSpace: "nowrap",
1313
- cursor: "pointer"
1314
- };
1315
- var quickAlwaysBox = {
1316
- margin: 0,
1317
- cursor: "pointer"
1318
- };
1319
1657
  var quickPanelFoot = {
1320
1658
  padding: "5px 12px 7px",
1321
1659
  borderTop: "0.5px solid var(--dsw-alias-border-l2)",
@@ -1518,14 +1856,15 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
1518
1856
  var EDGES = ["left", "right", "top", "bottom", "br"];
1519
1857
  function PanelResizeHandles({ useLive, actions }) {
1520
1858
  const settings = useLive((value) => ({
1521
- enabled: value.enabled,
1859
+ // 「设置面板」栏(或总开关)关着时整块停用 —— 与导航滚动那处用同一个判据。
1860
+ sectionOn: activeSections(value).panel,
1522
1861
  panelResize: value.panelResize,
1523
1862
  panelWidth: value.panelWidth,
1524
1863
  panelHeight: value.panelHeight
1525
1864
  }));
1526
- const enabled = settings.enabled === true && settings.panelResize === true;
1865
+ const enabled = settings.sectionOn === true && settings.panelResize === true;
1527
1866
  const [panel, setPanel] = (0, import_react2.useState)(null);
1528
- const [active, setActive] = (0, import_react2.useState)(null);
1867
+ const [active2, setActive] = (0, import_react2.useState)(null);
1529
1868
  const dragRef = (0, import_react2.useRef)(null);
1530
1869
  (0, import_react2.useEffect)(() => {
1531
1870
  if (!enabled) {
@@ -1621,7 +1960,7 @@ function PanelResizeHandles({ useLive, actions }) {
1621
1960
  "div",
1622
1961
  {
1623
1962
  className: edge === "br" ? RESIZE_GRIP_CLASS : RESIZE_EDGE_CLASS,
1624
- "data-active": active === edge ? "true" : void 0,
1963
+ "data-active": active2 === edge ? "true" : void 0,
1625
1964
  title: edge === "br" ? "\u62D6\u52A8\u6539\u9762\u677F\u5927\u5C0F" : void 0,
1626
1965
  style: handleBox(edge),
1627
1966
  onPointerDown: (event) => {
@@ -1645,196 +1984,481 @@ function PanelResizeHandles({ useLive, actions }) {
1645
1984
  }
1646
1985
 
1647
1986
  // src/client/SettingsSection.tsx
1987
+ var import_react4 = require("react");
1988
+
1989
+ // src/client/AddPromptRow.tsx
1648
1990
  var import_react3 = require("react");
1649
1991
  var import_jsx_runtime3 = require("react/jsx-runtime");
1650
- var bodyLead = { ...description, margin: "12px 0" };
1651
- function Chevron() {
1652
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1653
- "path",
1654
- {
1655
- d: "M3.25 5.5L7 9.25L10.75 5.5",
1656
- stroke: "currentColor",
1657
- strokeWidth: "1.4",
1658
- strokeLinecap: "round",
1659
- strokeLinejoin: "round"
1660
- }
1661
- ) });
1662
- }
1663
- function FoldCard(props) {
1664
- const [open, setOpen] = (0, import_react3.useState)(false);
1665
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: open ? "dsh-ux-card dsh-ux-cardOpen" : "dsh-ux-card", children: [
1992
+ var rowBase = {
1993
+ display: "flex",
1994
+ alignItems: "center",
1995
+ gap: 6,
1996
+ width: "100%",
1997
+ borderRadius: 8,
1998
+ border: "0.5px dashed var(--dsw-alias-border-l2)",
1999
+ background: "transparent",
2000
+ color: "var(--dsw-alias-label-tertiary)",
2001
+ cursor: "pointer",
2002
+ textAlign: "left"
2003
+ };
2004
+ var choiceBase = {
2005
+ padding: "4px 9px",
2006
+ borderRadius: 999,
2007
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2008
+ background: "transparent",
2009
+ color: "var(--dsw-alias-label-primary)",
2010
+ fontSize: 11,
2011
+ lineHeight: 1.2,
2012
+ cursor: "pointer"
2013
+ };
2014
+ var candidateBase = {
2015
+ display: "flex",
2016
+ alignItems: "center",
2017
+ gap: 6,
2018
+ width: "100%",
2019
+ padding: "4px 6px",
2020
+ borderRadius: 6,
2021
+ border: "none",
2022
+ background: "transparent",
2023
+ cursor: "pointer",
2024
+ textAlign: "left"
2025
+ };
2026
+ function AddPromptRow({
2027
+ book,
2028
+ categoryId,
2029
+ onAdd,
2030
+ onMove,
2031
+ variant = "settings"
2032
+ }) {
2033
+ const [mode, setMode] = (0, import_react3.useState)("closed");
2034
+ const ref = (0, import_react3.useRef)(null);
2035
+ (0, import_react3.useEffect)(() => {
2036
+ setMode("closed");
2037
+ }, [categoryId]);
2038
+ (0, import_react3.useEffect)(() => {
2039
+ if (mode === "closed") return;
2040
+ const onPointerDown = (event) => {
2041
+ if (ref.current !== null && event.target instanceof Node && ref.current.contains(event.target)) return;
2042
+ setMode("closed");
2043
+ };
2044
+ const onKeyDown = (event) => {
2045
+ if (event.key === "Escape") setMode("closed");
2046
+ };
2047
+ document.addEventListener("pointerdown", onPointerDown, true);
2048
+ document.addEventListener("keydown", onKeyDown, true);
2049
+ return () => {
2050
+ document.removeEventListener("pointerdown", onPointerDown, true);
2051
+ document.removeEventListener("keydown", onKeyDown, true);
2052
+ };
2053
+ }, [mode]);
2054
+ const compact = variant === "panel";
2055
+ const candidates = mode === "move" ? promptsElsewhere(book, categoryId) : [];
2056
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { ref, style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
1666
2057
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1667
2058
  "button",
1668
2059
  {
1669
2060
  type: "button",
1670
- className: "dsh-ux-cardHeader",
1671
- "aria-expanded": open,
2061
+ "aria-expanded": mode !== "closed",
2062
+ title: "\u65B0\u5EFA\u4E00\u6761\uFF0C\u6216\u628A\u522B\u7684\u5206\u7C7B\u91CC\u7684\u6761\u76EE\u79FB\u52A8\u5230\u8FD9\u91CC",
2063
+ style: {
2064
+ ...rowBase,
2065
+ padding: compact ? "4px 8px" : "7px 9px",
2066
+ fontSize: compact ? 11 : 12
2067
+ },
2068
+ onMouseDown: (event) => {
2069
+ event.preventDefault();
2070
+ },
1672
2071
  onClick: () => {
1673
- setOpen((current) => !current);
2072
+ setMode(mode === "closed" ? "choose" : "closed");
1674
2073
  },
1675
2074
  children: [
1676
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
1677
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-ux-cardName", children: props.name }),
1678
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-ux-cardDescription", children: props.summary })
1679
- ] }),
1680
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: open ? "dsh-ux-cardChevron dsh-ux-cardChevronOpen" : "dsh-ux-cardChevron", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Chevron, {}) })
2075
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { "aria-hidden": true, children: "\uFF0B" }),
2076
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: mode === "closed" ? "\u65B0\u5EFA / \u79FB\u52A8" : "\u6536\u8D77" })
1681
2077
  ]
1682
2078
  }
1683
2079
  ),
1684
- open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-ux-cardBody", children: props.children })
1685
- ] });
1686
- }
1687
- function KeyRow(props) {
1688
- const { title, desc, value, presets, conflict, onChange, first } = props;
1689
- const [recording, setRecording] = (0, import_react3.useState)(false);
1690
- const [error, setError] = (0, import_react3.useState)(null);
1691
- (0, import_react3.useEffect)(() => {
1692
- if (!recording) return;
1693
- const onKeyDown = (event) => {
1694
- event.preventDefault();
1695
- event.stopPropagation();
1696
- if (event.isComposing) return;
1697
- const result = evaluateRecordedKey(event);
1698
- if (result.kind === "ignore") return;
1699
- if (result.kind === "cancel") {
1700
- setRecording(false);
1701
- setError(null);
1702
- return;
1703
- }
1704
- if (result.kind === "clear") {
1705
- setRecording(false);
1706
- setError(null);
1707
- onChange("");
1708
- return;
1709
- }
1710
- if (result.kind === "reject") {
1711
- setError(result.message);
1712
- return;
1713
- }
1714
- if (conflict(result.chord)) {
1715
- setRecording(false);
1716
- setError("\u53D1\u9001\u4E0E\u6362\u884C\u4E0D\u80FD\u8BBE\u4E3A\u76F8\u540C\u6309\u952E\uFF08\u53EF\u5148\u7ED9\u53E6\u4E00\u4FA7\u6362\u952E\uFF0C\u518D\u7ED1\u5B9A\u8BE5\u952E\uFF09\u3002");
1717
- return;
1718
- }
1719
- setRecording(false);
1720
- setError(null);
1721
- onChange(result.chord);
1722
- };
1723
- window.addEventListener("keydown", onKeyDown, true);
1724
- return () => {
1725
- window.removeEventListener("keydown", onKeyDown, true);
1726
- };
1727
- }, [recording, conflict, onChange]);
1728
- const base = first === true ? { ...row, borderTop: "none" } : row;
1729
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...base, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
1730
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowText, children: [
1731
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowTitle, children: title }),
1732
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowDesc, children: desc })
1733
- ] }),
1734
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
1735
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: kbd, children: displayChord(value) }),
1736
- !recording && presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2080
+ mode !== "closed" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" }, children: [
2081
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1737
2082
  "button",
1738
2083
  {
1739
2084
  type: "button",
1740
- style: value === preset ? pillActive : pill,
2085
+ style: choiceBase,
2086
+ onMouseDown: (event) => {
2087
+ event.preventDefault();
2088
+ },
1741
2089
  onClick: () => {
1742
- setError(null);
1743
- onChange(preset);
2090
+ setMode("closed");
2091
+ onAdd();
1744
2092
  },
1745
- children: displayChord(preset)
1746
- },
1747
- preset
1748
- )),
1749
- !recording && value !== "" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: () => {
1750
- setError(null);
1751
- onChange("");
1752
- }, children: "\u6E05\u9664" }),
2093
+ children: "\uFF0B \u65B0\u5EFA\u4E00\u6761"
2094
+ }
2095
+ ),
1753
2096
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1754
2097
  "button",
1755
2098
  {
1756
2099
  type: "button",
1757
- style: recording ? pillActive : pill,
2100
+ style: mode === "move" ? { ...choiceBase, borderColor: "var(--dsw-alias-brand-primary)" } : choiceBase,
2101
+ onMouseDown: (event) => {
2102
+ event.preventDefault();
2103
+ },
1758
2104
  onClick: () => {
1759
- setRecording(true);
1760
- setError(null);
2105
+ setMode(mode === "move" ? "choose" : "move");
1761
2106
  },
1762
- children: recording ? "\u8BF7\u6309\u4E0B\u65B0\u7EC4\u5408\u952E\u2026" : "\u81EA\u5B9A\u4E49\u2026"
2107
+ children: "\u2192 \u628A\u522B\u7684\u5206\u7C7B\u7684\u6761\u76EE\u79FB\u52A8\u5230\u8FD9\u91CC"
1763
2108
  }
1764
- ),
1765
- recording && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: () => {
1766
- setRecording(false);
1767
- setError(null);
1768
- }, children: "Esc \u53D6\u6D88" }),
1769
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--dsw-alias-state-error-primary)", fontSize: 12 }, children: error })
1770
- ] })
1771
- ] });
1772
- }
1773
- function ToggleRow(props) {
1774
- const { label, desc, checked, onChange, first } = props;
1775
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: first === true ? { ...row, borderTop: "none" } : row, children: [
1776
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowText, children: [
1777
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowTitle, children: label }),
1778
- desc !== void 0 && desc !== "" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowDesc, children: desc })
2109
+ )
1779
2110
  ] }),
1780
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1781
- "button",
2111
+ mode === "move" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2112
+ "div",
1782
2113
  {
1783
- type: "button",
1784
- role: "switch",
1785
- "aria-checked": checked,
1786
- onClick: () => {
1787
- onChange(!checked);
1788
- },
1789
2114
  style: {
1790
- width: 36,
1791
- height: 20,
1792
- borderRadius: 999,
2115
+ display: "flex",
2116
+ flexDirection: "column",
2117
+ gap: 2,
2118
+ maxHeight: 190,
2119
+ overflowY: "auto",
1793
2120
  border: "0.5px solid var(--dsw-alias-border-l2)",
1794
- cursor: "pointer",
1795
- background: checked ? "var(--dsw-alias-button-primary-fill)" : "var(--dsw-alias-interactive-bg-hover)",
1796
- position: "relative",
1797
- flex: "0 0 auto",
1798
- padding: 0
2121
+ borderRadius: 8,
2122
+ padding: 4
2123
+ },
2124
+ children: [
2125
+ candidates.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)", fontSize: 11, padding: "4px 6px" }, children: "\u522B\u7684\u5206\u7C7B\u91CC\u8FD8\u6CA1\u6709\u6761\u76EE\u53EF\u4EE5\u79FB\u52A8\u3002" }),
2126
+ candidates.map((candidate) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2127
+ "button",
2128
+ {
2129
+ type: "button",
2130
+ title: `${candidate.categoryName} \xB7 ${candidate.prompt.prompt}`,
2131
+ style: candidateBase,
2132
+ onMouseDown: (event) => {
2133
+ event.preventDefault();
2134
+ },
2135
+ onClick: () => {
2136
+ setMode("closed");
2137
+ onMove(candidate.prompt.id);
2138
+ },
2139
+ children: [
2140
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)", fontSize: 11, flex: "0 0 auto" }, children: candidate.categoryName }),
2141
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)", flex: "0 0 auto" }, children: "\xB7" }),
2142
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2143
+ "span",
2144
+ {
2145
+ style: {
2146
+ color: "var(--dsw-alias-label-primary)",
2147
+ fontSize: 12,
2148
+ minWidth: 0,
2149
+ flex: "1 1 auto",
2150
+ overflow: "hidden",
2151
+ textOverflow: "ellipsis",
2152
+ whiteSpace: "nowrap"
2153
+ },
2154
+ children: candidate.prompt.label
2155
+ }
2156
+ ),
2157
+ candidate.prompt.always && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "var(--dsw-alias-label-tertiary)", fontSize: 10, flex: "0 0 auto" }, children: "\u9ED8\u8BA4\u63D2\u5165" })
2158
+ ]
2159
+ },
2160
+ candidate.prompt.id
2161
+ ))
2162
+ ]
2163
+ }
2164
+ )
2165
+ ] });
2166
+ }
2167
+
2168
+ // src/client/PillChoice.tsx
2169
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2170
+ var base = {
2171
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2172
+ background: "transparent",
2173
+ color: "var(--dsw-alias-label-tertiary)",
2174
+ borderRadius: 999,
2175
+ cursor: "pointer",
2176
+ lineHeight: 1,
2177
+ whiteSpace: "nowrap"
2178
+ };
2179
+ var active = {
2180
+ ...base,
2181
+ border: "0.5px solid var(--dsw-alias-brand-primary)",
2182
+ color: "var(--dsw-alias-label-primary)",
2183
+ fontWeight: 600
2184
+ };
2185
+ function PillChoice({
2186
+ items,
2187
+ value,
2188
+ onChange,
2189
+ ariaLabel,
2190
+ compact = false
2191
+ }) {
2192
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2193
+ "div",
2194
+ {
2195
+ role: "group",
2196
+ "aria-label": ariaLabel,
2197
+ style: { display: "inline-flex", alignItems: "center", gap: 2, flex: "0 0 auto" },
2198
+ children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2199
+ "button",
2200
+ {
2201
+ type: "button",
2202
+ title: item.hint,
2203
+ "aria-pressed": value === item.id,
2204
+ style: {
2205
+ ...value === item.id ? active : base,
2206
+ fontSize: compact ? 10 : 11,
2207
+ padding: compact ? "3px 5px" : "4px 7px"
2208
+ },
2209
+ onMouseDown: (event) => {
2210
+ event.preventDefault();
2211
+ },
2212
+ onClick: () => {
2213
+ onChange(item.id);
2214
+ },
2215
+ children: item.label
1799
2216
  },
1800
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1801
- "span",
2217
+ item.id
2218
+ ))
2219
+ }
2220
+ );
2221
+ }
2222
+
2223
+ // src/client/InsertModeControl.tsx
2224
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2225
+ function InsertModeControl({ mode, onChange, compact = false, label }) {
2226
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2227
+ PillChoice,
2228
+ {
2229
+ items: INSERT_MODES,
2230
+ value: mode,
2231
+ onChange,
2232
+ compact,
2233
+ ariaLabel: label === void 0 ? "\u53D1\u9001\u65F6\u63D2\u5165" : `\u53D1\u9001\u65F6\u63D2\u5165\uFF08${label}\uFF09`
2234
+ }
2235
+ );
2236
+ }
2237
+
2238
+ // src/client/SettingsSection.tsx
2239
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2240
+ var bodyLead = { ...description, margin: "12px 0" };
2241
+ function Chevron() {
2242
+ 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)(
2243
+ "path",
2244
+ {
2245
+ d: "M3.25 5.5L7 9.25L10.75 5.5",
2246
+ stroke: "currentColor",
2247
+ strokeWidth: "1.4",
2248
+ strokeLinecap: "round",
2249
+ strokeLinejoin: "round"
2250
+ }
2251
+ ) });
2252
+ }
2253
+ function FoldCard(props) {
2254
+ const [open, setOpen] = (0, import_react4.useState)(false);
2255
+ const off = props.toggle !== void 0 && props.toggle.checked === false;
2256
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: [
2257
+ "dsh-ux-card",
2258
+ open ? "dsh-ux-cardOpen" : "",
2259
+ off ? "dsh-ux-cardOff" : ""
2260
+ ].filter((part) => part !== "").join(" "), children: [
2261
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-ux-cardHeaderRow", children: [
2262
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2263
+ "button",
2264
+ {
2265
+ type: "button",
2266
+ className: "dsh-ux-cardHeader",
2267
+ "aria-expanded": open,
2268
+ onClick: () => {
2269
+ setOpen((current) => !current);
2270
+ },
2271
+ children: [
2272
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2273
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-cardName", children: props.name }),
2274
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-cardDescription", children: off ? `\u672A\u542F\u7528 \xB7 ${props.summary}` : props.summary })
2275
+ ] }),
2276
+ /* @__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, {}) })
2277
+ ]
2278
+ }
2279
+ ),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardControls", children: [
2281
+ props.controls,
2282
+ props.toggle !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2283
+ Switch,
1802
2284
  {
1803
- style: {
1804
- position: "absolute",
1805
- top: 2,
1806
- left: checked ? 18 : 2,
1807
- width: 14,
1808
- height: 14,
1809
- borderRadius: "50%",
1810
- background: checked ? "var(--dsw-alias-label-primary-foreground)" : "var(--dsw-alias-label-secondary)",
1811
- transition: "left 0.12s ease"
1812
- }
2285
+ small: true,
2286
+ label: `${props.name}\uFF1A\u542F\u7528\u8FD9\u4E00\u680F`,
2287
+ checked: props.toggle.checked,
2288
+ onChange: props.toggle.onChange
1813
2289
  }
1814
2290
  )
2291
+ ] })
2292
+ ] }),
2293
+ open && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-ux-cardBody", children: props.children })
2294
+ ] });
2295
+ }
2296
+ function KeyRow(props) {
2297
+ const { title, desc, value, presets, conflict, onChange, first } = props;
2298
+ const [recording, setRecording] = (0, import_react4.useState)(false);
2299
+ const [error, setError] = (0, import_react4.useState)(null);
2300
+ (0, import_react4.useEffect)(() => {
2301
+ if (!recording) return;
2302
+ const onKeyDown = (event) => {
2303
+ event.preventDefault();
2304
+ event.stopPropagation();
2305
+ if (event.isComposing) return;
2306
+ const result = evaluateRecordedKey(event);
2307
+ if (result.kind === "ignore") return;
2308
+ if (result.kind === "cancel") {
2309
+ setRecording(false);
2310
+ setError(null);
2311
+ return;
1815
2312
  }
1816
- )
2313
+ if (result.kind === "clear") {
2314
+ setRecording(false);
2315
+ setError(null);
2316
+ onChange("");
2317
+ return;
2318
+ }
2319
+ if (result.kind === "reject") {
2320
+ setError(result.message);
2321
+ return;
2322
+ }
2323
+ if (conflict(result.chord)) {
2324
+ setRecording(false);
2325
+ setError("\u53D1\u9001\u4E0E\u6362\u884C\u4E0D\u80FD\u8BBE\u4E3A\u76F8\u540C\u6309\u952E\uFF08\u53EF\u5148\u7ED9\u53E6\u4E00\u4FA7\u6362\u952E\uFF0C\u518D\u7ED1\u5B9A\u8BE5\u952E\uFF09\u3002");
2326
+ return;
2327
+ }
2328
+ setRecording(false);
2329
+ setError(null);
2330
+ onChange(result.chord);
2331
+ };
2332
+ window.addEventListener("keydown", onKeyDown, true);
2333
+ return () => {
2334
+ window.removeEventListener("keydown", onKeyDown, true);
2335
+ };
2336
+ }, [recording, conflict, onChange]);
2337
+ const base2 = first === true ? { ...row, borderTop: "none" } : row;
2338
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2339
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2340
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: title }),
2341
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
2342
+ ] }),
2343
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2344
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: kbd, children: displayChord(value) }),
2345
+ !recording && presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2346
+ "button",
2347
+ {
2348
+ type: "button",
2349
+ style: value === preset ? pillActive : pill,
2350
+ onClick: () => {
2351
+ setError(null);
2352
+ onChange(preset);
2353
+ },
2354
+ children: displayChord(preset)
2355
+ },
2356
+ preset
2357
+ )),
2358
+ !recording && value !== "" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2359
+ setError(null);
2360
+ onChange("");
2361
+ }, children: "\u6E05\u9664" }),
2362
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2363
+ "button",
2364
+ {
2365
+ type: "button",
2366
+ style: recording ? pillActive : pill,
2367
+ onClick: () => {
2368
+ setRecording(true);
2369
+ setError(null);
2370
+ },
2371
+ children: recording ? "\u8BF7\u6309\u4E0B\u65B0\u7EC4\u5408\u952E\u2026" : "\u81EA\u5B9A\u4E49\u2026"
2372
+ }
2373
+ ),
2374
+ recording && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2375
+ setRecording(false);
2376
+ setError(null);
2377
+ }, children: "Esc \u53D6\u6D88" }),
2378
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: "var(--dsw-alias-state-error-primary)", fontSize: 12 }, children: error })
2379
+ ] })
2380
+ ] });
2381
+ }
2382
+ function Switch(props) {
2383
+ const { checked, onChange, label, small = false } = props;
2384
+ const width = small ? 30 : 36;
2385
+ const height = small ? 16 : 20;
2386
+ const knob = small ? 12 : 14;
2387
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2388
+ "button",
2389
+ {
2390
+ type: "button",
2391
+ role: "switch",
2392
+ "aria-checked": checked,
2393
+ "aria-label": label,
2394
+ title: label,
2395
+ onClick: () => {
2396
+ onChange(!checked);
2397
+ },
2398
+ style: {
2399
+ width,
2400
+ height,
2401
+ borderRadius: 999,
2402
+ border: "0.5px solid var(--dsw-alias-border-l2)",
2403
+ cursor: "pointer",
2404
+ background: checked ? "var(--dsw-alias-button-primary-fill)" : "var(--dsw-alias-interactive-bg-hover)",
2405
+ position: "relative",
2406
+ flex: "0 0 auto",
2407
+ padding: 0
2408
+ },
2409
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2410
+ "span",
2411
+ {
2412
+ style: {
2413
+ position: "absolute",
2414
+ top: small ? 1 : 2,
2415
+ left: checked ? width - knob - (small ? 1 : 2) : small ? 1 : 2,
2416
+ width: knob,
2417
+ height: knob,
2418
+ borderRadius: "50%",
2419
+ background: checked ? "var(--dsw-alias-label-primary-foreground)" : "var(--dsw-alias-label-secondary)",
2420
+ transition: "left 0.12s ease"
2421
+ }
2422
+ }
2423
+ )
2424
+ }
2425
+ );
2426
+ }
2427
+ function MiniToggle(props) {
2428
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-miniToggle", children: [
2429
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-miniToggleLabel", children: props.label }),
2430
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Switch, { small: true, label: props.label, checked: props.checked, onChange: props.onChange })
2431
+ ] });
2432
+ }
2433
+ function ToggleRow(props) {
2434
+ const { label, desc, checked, onChange, first } = props;
2435
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: first === true ? { ...row, borderTop: "none" } : row, children: [
2436
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2437
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: label }),
2438
+ desc !== void 0 && desc !== "" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
2439
+ ] }),
2440
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Switch, { label, checked, onChange })
1817
2441
  ] });
1818
2442
  }
1819
2443
  function TextFieldRow(props) {
1820
2444
  const { title, desc, value, placeholder, maxLength, onChange, action, first } = props;
1821
- const [draft, setDraft] = (0, import_react3.useState)(value);
1822
- const focused = (0, import_react3.useRef)(false);
1823
- (0, import_react3.useEffect)(() => {
2445
+ const [draft, setDraft] = (0, import_react4.useState)(value);
2446
+ const focused = (0, import_react4.useRef)(false);
2447
+ (0, import_react4.useEffect)(() => {
1824
2448
  if (!focused.current) setDraft(value);
1825
2449
  }, [value]);
1826
2450
  const commit = () => {
1827
2451
  if (draft === value) return;
1828
2452
  onChange(draft.trim());
1829
2453
  };
1830
- const base = first === true ? { ...row, borderTop: "none" } : row;
1831
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...base, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
1832
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowText, children: [
1833
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowTitle, children: title }),
1834
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowDesc, children: desc })
2454
+ const base2 = first === true ? { ...row, borderTop: "none" } : row;
2455
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...base2, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2456
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2457
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: title }),
2458
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: desc })
1835
2459
  ] }),
1836
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1837
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2460
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
2461
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1838
2462
  "input",
1839
2463
  {
1840
2464
  type: "text",
@@ -1863,17 +2487,17 @@ function TextFieldRow(props) {
1863
2487
  style: textInput
1864
2488
  }
1865
2489
  ),
1866
- action !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: action.onClick, children: action.label })
2490
+ action !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: action.onClick, children: action.label })
1867
2491
  ] })
1868
2492
  ] });
1869
2493
  }
1870
2494
  function QuickPromptsEditor(props) {
1871
- const [draft, setDraft] = (0, import_react3.useState)(() => props.book);
1872
- const [activeId, setActiveId] = (0, import_react3.useState)(() => props.book.categories[0]?.id ?? "");
1873
- const [dirty, setDirty] = (0, import_react3.useState)(false);
1874
- const [newName, setNewName] = (0, import_react3.useState)("");
1875
- const [note, setNote] = (0, import_react3.useState)("");
1876
- (0, import_react3.useEffect)(() => {
2495
+ const [draft, setDraft] = (0, import_react4.useState)(() => props.book);
2496
+ const [activeId, setActiveId] = (0, import_react4.useState)(() => props.book.categories[0]?.id ?? "");
2497
+ const [dirty, setDirty] = (0, import_react4.useState)(false);
2498
+ const [newName, setNewName] = (0, import_react4.useState)("");
2499
+ const [note, setNote] = (0, import_react4.useState)("");
2500
+ (0, import_react4.useEffect)(() => {
1877
2501
  if (dirty) return;
1878
2502
  setDraft(props.book);
1879
2503
  if (!props.book.categories.some((category) => category.id === activeId)) {
@@ -1897,9 +2521,9 @@ function QuickPromptsEditor(props) {
1897
2521
  border: "0.5px solid var(--dsw-alias-border-l2)",
1898
2522
  background: "var(--dsw-alias-bg-layer-1)"
1899
2523
  };
1900
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1901
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap" }, children: [
1902
- draft.categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2524
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2525
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4, flexWrap: "wrap" }, children: [
2526
+ draft.categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1903
2527
  "button",
1904
2528
  {
1905
2529
  type: "button",
@@ -1916,7 +2540,7 @@ function QuickPromptsEditor(props) {
1916
2540
  },
1917
2541
  category.id
1918
2542
  )),
1919
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2543
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1920
2544
  "input",
1921
2545
  {
1922
2546
  type: "text",
@@ -1930,7 +2554,7 @@ function QuickPromptsEditor(props) {
1930
2554
  style: { ...textInput, flex: "0 0 110px" }
1931
2555
  }
1932
2556
  ),
1933
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2557
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1934
2558
  "button",
1935
2559
  {
1936
2560
  type: "button",
@@ -1944,10 +2568,10 @@ function QuickPromptsEditor(props) {
1944
2568
  }
1945
2569
  )
1946
2570
  ] }),
1947
- current === void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.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" }),
1948
- current !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1949
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
1950
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2571
+ 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" }),
2572
+ current !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2573
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2574
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1951
2575
  "input",
1952
2576
  {
1953
2577
  type: "text",
@@ -1961,13 +2585,13 @@ function QuickPromptsEditor(props) {
1961
2585
  style: { ...textInput, flex: "0 0 150px" }
1962
2586
  }
1963
2587
  ),
1964
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0A\u79FB", onClick: () => {
2588
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0A\u79FB", onClick: () => {
1965
2589
  edit(withCategoryMoved(draft, current.id, -1));
1966
2590
  }, children: "\u2191" }),
1967
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0B\u79FB", onClick: () => {
2591
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5206\u7C7B\u4E0B\u79FB", onClick: () => {
1968
2592
  edit(withCategoryMoved(draft, current.id, 1));
1969
2593
  }, children: "\u2193" }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2594
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1971
2595
  "button",
1972
2596
  {
1973
2597
  type: "button",
@@ -1979,16 +2603,16 @@ function QuickPromptsEditor(props) {
1979
2603
  children: "\u2715 \u5220\u9664\u5206\u7C7B"
1980
2604
  }
1981
2605
  ),
1982
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: rowDesc, children: [
2606
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: rowDesc, children: [
1983
2607
  current.prompts.length,
1984
2608
  " / ",
1985
2609
  QUICK_PROMPT_MAX,
1986
2610
  " \u6761"
1987
2611
  ] })
1988
2612
  ] }),
1989
- current.prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowBox, children: [
1990
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
1991
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2613
+ current.prompts.map((prompt) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowBox, children: [
2614
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }, children: [
2615
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1992
2616
  "input",
1993
2617
  {
1994
2618
  type: "text",
@@ -2002,32 +2626,28 @@ function QuickPromptsEditor(props) {
2002
2626
  style: { ...textInput, flex: "0 0 150px" }
2003
2627
  }
2004
2628
  ),
2005
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: 4, ...rowDesc, margin: 0, flex: "0 0 auto" }, children: [
2006
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2007
- "input",
2008
- {
2009
- type: "checkbox",
2010
- checked: prompt.always,
2011
- style: { margin: 0, cursor: "pointer" },
2012
- onChange: (event) => {
2013
- edit(withPromptPatched(draft, current.id, prompt.id, { always: event.target.checked }));
2014
- }
2629
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2630
+ InsertModeControl,
2631
+ {
2632
+ label: prompt.label,
2633
+ mode: insertModeOf(prompt),
2634
+ onChange: (mode) => {
2635
+ edit(withInsertMode(draft, prompt.id, mode));
2015
2636
  }
2016
- ),
2017
- "\u9ED8\u8BA4\u63D2\u5165"
2018
- ] }),
2019
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 } }),
2020
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, title: "\u4E0A\u79FB", onClick: () => {
2637
+ }
2638
+ ),
2639
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u4E0A\u79FB", onClick: () => {
2021
2641
  edit(withPromptMoved(draft, current.id, prompt.id, -1));
2022
2642
  }, children: "\u2191" }),
2023
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, title: "\u4E0B\u79FB", onClick: () => {
2643
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u4E0B\u79FB", onClick: () => {
2024
2644
  edit(withPromptMoved(draft, current.id, prompt.id, 1));
2025
2645
  }, children: "\u2193" }),
2026
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, title: "\u5220\u9664\u8FD9\u6761", onClick: () => {
2646
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, title: "\u5220\u9664\u8FD9\u6761", onClick: () => {
2027
2647
  edit(withPromptRemoved(draft, current.id, prompt.id));
2028
2648
  }, children: "\u2715" })
2029
2649
  ] }),
2030
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2650
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2031
2651
  "textarea",
2032
2652
  {
2033
2653
  value: prompt.prompt,
@@ -2042,12 +2662,22 @@ function QuickPromptsEditor(props) {
2042
2662
  }
2043
2663
  )
2044
2664
  ] }, prompt.id)),
2045
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: () => {
2046
- edit(withPromptAdded(draft, current.id));
2047
- }, children: "+ \u6DFB\u52A0\u4E00\u6761" }) })
2665
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2666
+ AddPromptRow,
2667
+ {
2668
+ book: draft,
2669
+ categoryId: current.id,
2670
+ onAdd: () => {
2671
+ edit(withPromptAdded(draft, current.id));
2672
+ },
2673
+ onMove: (promptId) => {
2674
+ edit(withPromptMovedToCategory(draft, promptId, current.id));
2675
+ }
2676
+ }
2677
+ )
2048
2678
  ] }),
2049
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2050
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2679
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: [
2680
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2051
2681
  "button",
2052
2682
  {
2053
2683
  type: "button",
@@ -2069,36 +2699,276 @@ function QuickPromptsEditor(props) {
2069
2699
  children: saving ? "\u4FDD\u5B58\u4E2D\u2026" : dirty ? "\u4FDD\u5B58\u4FEE\u6539" : "\u5DF2\u4FDD\u5B58"
2070
2700
  }
2071
2701
  ),
2072
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: () => {
2702
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2073
2703
  props.onReload();
2074
2704
  }, children: "\u91CD\u65B0\u8BFB\u53D6" }),
2075
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", style: pill, onClick: () => {
2705
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: pill, onClick: () => {
2076
2706
  props.onReset();
2077
2707
  }, children: "\u6062\u590D\u5185\u7F6E 9 \u6761" }),
2078
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: rowDesc, children: [
2708
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: rowDesc, children: [
2079
2709
  "\u5171 ",
2080
2710
  counts.categories,
2081
2711
  " \u4E2A\u5206\u7C7B \xB7 ",
2082
2712
  counts.prompts,
2083
- " \u6761 \xB7 \u9ED8\u8BA4\u63D2\u5165 ",
2713
+ " \u6761 \xB7 \u6BCF\u6B21 ",
2084
2714
  counts.always,
2715
+ " \u6761 \xB7 \u4EC5\u9996\u6B21 ",
2716
+ counts.first,
2085
2717
  " \u6761",
2086
2718
  note === "" ? "" : ` \xB7 ${note}`,
2087
2719
  failed ? ` \xB7 ${props.status}` : ""
2088
2720
  ] })
2089
2721
  ] }),
2090
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: rowDesc, children: [
2722
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: rowDesc, children: [
2091
2723
  "\u6570\u636E\u5B58\u5728 ",
2092
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("code", { children: "~/.dsh/quick-prompts.json" }),
2724
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("code", { children: "~/.dsh/quick-prompts.json" }),
2093
2725
  "\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"
2094
2726
  ] })
2095
2727
  ] });
2096
2728
  }
2729
+ var candidatePill = {
2730
+ ...pill,
2731
+ textAlign: "left",
2732
+ maxWidth: "100%",
2733
+ overflowWrap: "anywhere",
2734
+ lineHeight: 1.4
2735
+ };
2736
+ function DefaultTerminalBody(props) {
2737
+ const { settings, setField, hideMode = false } = props;
2738
+ const [note, setNote] = (0, import_react4.useState)("");
2739
+ const [busy, setBusy] = (0, import_react4.useState)(false);
2740
+ const candidates = settings.terminalCandidates;
2741
+ if (settings.terminalEffective === "unsupported") {
2742
+ return /* @__PURE__ */ (0, import_jsx_runtime6.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" });
2743
+ }
2744
+ const discover = async () => {
2745
+ setBusy(true);
2746
+ setNote("");
2747
+ try {
2748
+ const response = await fetch(TERMINAL_API_PATH, { method: "POST" });
2749
+ const parsed = await response.json();
2750
+ const found = sanitizeTerminalCandidates(parsed.candidates);
2751
+ 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`);
2752
+ } catch (error) {
2753
+ setNote(`\u81EA\u52A8\u53D1\u73B0\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`);
2754
+ } finally {
2755
+ setBusy(false);
2756
+ }
2757
+ };
2758
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2759
+ !hideMode && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2760
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
2761
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u7EC8\u7AEF\u5DE5\u5177" }),
2762
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: TERMINAL_MODES.find((item) => item.id === settings.terminalMode)?.hint ?? "" })
2763
+ ] }),
2764
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2765
+ PillChoice,
2766
+ {
2767
+ items: TERMINAL_MODES,
2768
+ value: settings.terminalMode,
2769
+ onChange: (mode) => {
2770
+ setField(TERMINAL_MODE_FIELD, mode);
2771
+ },
2772
+ ariaLabel: "\u7EC8\u7AEF\u5DE5\u5177"
2773
+ }
2774
+ )
2775
+ ] }),
2776
+ settings.terminalMode !== "pwsh" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
2777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2778
+ TextFieldRow,
2779
+ {
2780
+ title: "Git Bash \u8DEF\u5F84",
2781
+ 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",
2782
+ value: settings.terminalBashPath,
2783
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8",
2784
+ maxLength: 400,
2785
+ onChange: (next) => {
2786
+ setField(TERMINAL_BASH_PATH_FIELD, next);
2787
+ },
2788
+ action: { label: busy ? "\u63A2\u6D4B\u4E2D\u2026" : "\u81EA\u52A8\u53D1\u73B0", onClick: () => {
2789
+ void discover();
2790
+ } }
2791
+ }
2792
+ ),
2793
+ candidates.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 2 }, children: candidates.map((candidate) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2794
+ "button",
2795
+ {
2796
+ type: "button",
2797
+ title: candidate.path,
2798
+ style: candidate.path === settings.terminalBashPath ? { ...candidatePill, ...pillActive } : candidatePill,
2799
+ onClick: () => {
2800
+ setField(TERMINAL_BASH_PATH_FIELD, candidate.path);
2801
+ },
2802
+ children: [
2803
+ candidate.label,
2804
+ "\uFF1A",
2805
+ candidate.path,
2806
+ candidate.explicit ? "\uFF08\u4F60\u586B\u7684\uFF09" : ""
2807
+ ]
2808
+ },
2809
+ candidate.path
2810
+ )) }),
2811
+ note !== "" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintInfo, children: note })
2812
+ ] }),
2813
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
2814
+ "\u72B6\u6001\uFF1A",
2815
+ settings.terminalStatus === "" ? "\u7B49\u5F85\u5BBF\u4E3B\u534A\u63A2\u6D4B\u2026" : settings.terminalStatus
2816
+ ] }),
2817
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" }),
2818
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" }),
2819
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" })
2820
+ ] });
2821
+ }
2822
+ var RESTART_WAIT_MS = 6e4;
2823
+ var RESTART_POLL_MS = 1500;
2824
+ function blockedText(blocked) {
2825
+ if (blocked === "debugger") {
2826
+ 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";
2827
+ }
2828
+ if (blocked.startsWith("supervised:")) {
2829
+ 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`;
2830
+ }
2831
+ return `\u8FD9\u4E2A\u5BBF\u4E3B\u5F53\u524D\u4E0D\u5141\u8BB8\u4ECE\u754C\u9762\u91CD\u542F\uFF08${blocked}\uFF09\u3002`;
2832
+ }
2833
+ function useRestart() {
2834
+ const [stage, setStage] = (0, import_react4.useState)("idle");
2835
+ const [detail, setDetail] = (0, import_react4.useState)("");
2836
+ const [blocked, setBlocked] = (0, import_react4.useState)(null);
2837
+ const readFacts = async () => {
2838
+ const response = await fetch(RESTART_API_PATH, { cache: "no-store" });
2839
+ if (!response.ok) return { error: `HTTP ${String(response.status)}` };
2840
+ const parsed = await response.json();
2841
+ return {
2842
+ running: typeof parsed.running === "number" ? parsed.running : 0,
2843
+ command: typeof parsed.command === "string" ? parsed.command : "",
2844
+ logHint: typeof parsed.logHint === "string" ? parsed.logHint : "",
2845
+ blocked: typeof parsed.blocked === "string" ? parsed.blocked : null,
2846
+ boot: typeof parsed.boot === "string" ? parsed.boot : null
2847
+ };
2848
+ };
2849
+ const awaitNewBoot = async (previousBoot, logHint) => {
2850
+ const deadline = Date.now() + RESTART_WAIT_MS;
2851
+ while (Date.now() < deadline) {
2852
+ await new Promise((done) => {
2853
+ setTimeout(done, RESTART_POLL_MS);
2854
+ });
2855
+ try {
2856
+ const facts = await readFacts();
2857
+ if ("error" in facts) continue;
2858
+ if (facts.boot !== null && facts.boot !== previousBoot) {
2859
+ location.reload();
2860
+ return;
2861
+ }
2862
+ } catch {
2863
+ }
2864
+ }
2865
+ setStage("failed");
2866
+ 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`));
2867
+ };
2868
+ const ask = () => {
2869
+ setStage("asking");
2870
+ setDetail("\u6B63\u5728\u8BFB\u53D6\u91CD\u542F\u65B9\u5F0F\u2026");
2871
+ void (async () => {
2872
+ try {
2873
+ const facts = await readFacts();
2874
+ if ("error" in facts) {
2875
+ setStage("failed");
2876
+ 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`);
2877
+ return;
2878
+ }
2879
+ setBlocked(facts.blocked);
2880
+ if (facts.blocked !== null) {
2881
+ setStage("failed");
2882
+ setDetail(blockedText(facts.blocked));
2883
+ return;
2884
+ }
2885
+ setStage("asking");
2886
+ 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`);
2887
+ } catch (error) {
2888
+ setStage("failed");
2889
+ setDetail(`\u8BFB\u4E0D\u5230\u91CD\u542F\u72B6\u6001\uFF1A${error instanceof Error ? error.message : String(error)}`);
2890
+ }
2891
+ })();
2892
+ };
2893
+ const confirm = () => {
2894
+ setStage("restarting");
2895
+ 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");
2896
+ void (async () => {
2897
+ let previousBoot = null;
2898
+ let logHint = "";
2899
+ try {
2900
+ const before = await readFacts();
2901
+ if (!("error" in before)) {
2902
+ previousBoot = before.boot;
2903
+ logHint = before.logHint;
2904
+ }
2905
+ } catch {
2906
+ }
2907
+ try {
2908
+ const response = await fetch(RESTART_API_PATH, {
2909
+ method: "POST",
2910
+ headers: { "content-type": "application/json" },
2911
+ body: "{}"
2912
+ });
2913
+ const parsed = await response.json();
2914
+ if (response.status !== 202 && parsed.ok !== true) {
2915
+ setStage("failed");
2916
+ setDetail(`\u91CD\u542F\u6CA1\u6210\u529F\uFF1A${parsed.error ?? `HTTP ${String(response.status)}`} \u2014\u2014 \u8BF7\u624B\u52A8\u8FD0\u884C restart-webui.bat\u3002`);
2917
+ return;
2918
+ }
2919
+ } catch {
2920
+ }
2921
+ await awaitNewBoot(previousBoot, logHint);
2922
+ })();
2923
+ };
2924
+ const cancel = () => {
2925
+ setStage("idle");
2926
+ setDetail("");
2927
+ };
2928
+ return { stage, detail, blocked, ask, confirm, cancel };
2929
+ }
2930
+ function RestartButton({ restart }) {
2931
+ const busy = restart.stage === "restarting" || restart.stage === "asking";
2932
+ const blocked = restart.blocked;
2933
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2934
+ "button",
2935
+ {
2936
+ type: "button",
2937
+ className: "dsh-ux-restartButton",
2938
+ disabled: busy || blocked !== null,
2939
+ 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),
2940
+ onClick: () => {
2941
+ restart.ask();
2942
+ },
2943
+ children: restart.stage === "restarting" ? "\u91CD\u542F\u4E2D\u2026" : "\u91CD\u542F DSH"
2944
+ }
2945
+ );
2946
+ }
2947
+ function RestartBanner({ restart }) {
2948
+ if (restart.stage === "idle") return null;
2949
+ const failed = restart.stage === "failed";
2950
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: failed ? "dsh-ux-restartBanner dsh-ux-restartBannerFailed" : "dsh-ux-restartBanner", children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-restartBannerText", children: restart.detail }),
2952
+ restart.stage === "asking" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-restartBannerActions", children: [
2953
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-ux-restartGo", onClick: () => {
2954
+ restart.confirm();
2955
+ }, children: "\u786E\u8BA4\u91CD\u542F" }),
2956
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-ux-restartCancel", onClick: () => {
2957
+ restart.cancel();
2958
+ }, children: "\u53D6\u6D88" })
2959
+ ] }),
2960
+ failed && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-ux-restartBannerActions", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-ux-restartCancel", onClick: () => {
2961
+ restart.cancel();
2962
+ }, children: "\u77E5\u9053\u4E86" }) })
2963
+ ] });
2964
+ }
2097
2965
  function SettingsSection({ useLive, useBook, useBookStatus, actions }) {
2098
2966
  const settings = useLive((item) => item);
2099
2967
  const book = useBook((item) => item);
2100
2968
  const bookStatus = useBookStatus((item) => item);
2101
- const [conflict, setConflict] = (0, import_react3.useState)(null);
2969
+ const [conflict, setConflict] = (0, import_react4.useState)(null);
2970
+ const restart = useRestart();
2971
+ const sections = activeSections(settings);
2102
2972
  const setKey = (side, chord) => {
2103
2973
  const other = side === "send" ? settings.newlineKey : settings.sendKey;
2104
2974
  if (chord !== "" && chord === other) {
@@ -2111,20 +2981,41 @@ function SettingsSection({ useLive, useBook, useBookStatus, actions }) {
2111
2981
  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;
2112
2982
  const menuEnabled = MENU_ITEMS.filter((item) => settings[item.field]).length;
2113
2983
  const keySummary = `\u53D1\u9001 ${displayChord(settings.sendKey)} \xB7 \u6362\u884C ${displayChord(settings.newlineKey)}`;
2114
- const menuSummary = settings.menuNative ? "\u5F53\u524D\uFF1A\u7CFB\u7EDF\u539F\u751F\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`;
2984
+ 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`;
2115
2985
  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}`;
2116
2986
  const headerSummary = settings.headerEnabled ? settings.headerStatus === "" ? "\u5DF2\u542F\u7528" : settings.headerStatus : "\u672A\u542F\u7528";
2117
2987
  const quickCounts = bookCounts(book);
2118
- const quickSummary = `${quickCounts.categories} \u4E2A\u5206\u7C7B \xB7 ${quickCounts.prompts} \u6761 \xB7 \u9ED8\u8BA4\u63D2\u5165 ${quickCounts.always} \u6761 \xB7 \u4F18\u5316\u6863\u4F4D ${OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.label ?? "\u9AD8\u7EA7"}`;
2988
+ 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"}`;
2119
2989
  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";
2120
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { padding: "4px 2px" }, children: [
2121
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "dsh-ux-card", children: [
2122
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-ux-cardHeaderStatic", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2123
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: "dsh-ux-cardName", children: "\u8F93\u5165\u4F53\u9A8C" }),
2124
- /* @__PURE__ */ (0, import_jsx_runtime3.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" })
2125
- ] }) }),
2126
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-ux-cardBody", children: [
2127
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2990
+ 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";
2991
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { padding: "4px 2px" }, children: [
2992
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "dsh-ux-card", children: [
2993
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-ux-cardHeaderStatic", children: [
2994
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardHeadText", children: [
2995
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: "dsh-ux-cardName", children: "\u8F93\u5165\u4F53\u9A8C" }),
2996
+ /* @__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" })
2997
+ ] }),
2998
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-ux-cardActions", children: [
2999
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestartButton, { restart }),
3000
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3001
+ "a",
3002
+ {
3003
+ className: "dsh-ux-cardLink",
3004
+ href: REPO_URL,
3005
+ target: "_blank",
3006
+ rel: "noreferrer noopener",
3007
+ title: "\u5728 GitHub \u4E0A\u67E5\u770B\u8FD9\u4E2A\u63D2\u4EF6\uFF08\u65B0\u6807\u7B7E\u6253\u5F00\uFF09",
3008
+ children: [
3009
+ "GitHub ",
3010
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": "true", children: "\u2197" })
3011
+ ]
3012
+ }
3013
+ )
3014
+ ] })
3015
+ ] }),
3016
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RestartBanner, { restart }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-ux-cardBody", children: [
3018
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2128
3019
  ToggleRow,
2129
3020
  {
2130
3021
  first: true,
@@ -2136,277 +3027,390 @@ function SettingsSection({ useLive, useBook, useBookStatus, actions }) {
2136
3027
  }
2137
3028
  }
2138
3029
  ),
2139
- !settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime3.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" })
3030
+ !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" })
2140
3031
  ] })
2141
3032
  ] }),
2142
- settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2143
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FoldCard, { name: "\u952E\u4F4D", summary: keySummary, children: [
2144
- /* @__PURE__ */ (0, import_jsx_runtime3.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" }),
2145
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2146
- KeyRow,
2147
- {
2148
- first: true,
2149
- title: "\u53D1\u9001\u952E",
2150
- desc: "\u6309\u4E0B\u540E\u53D1\u9001\u5F53\u524D\u8F93\u5165",
2151
- value: settings.sendKey,
2152
- presets: SEND_PRESETS,
2153
- conflict: (chord) => chord !== "" && chord === settings.newlineKey,
2154
- onChange: (chord) => {
2155
- setKey("send", chord);
2156
- }
2157
- }
2158
- ),
2159
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2160
- KeyRow,
2161
- {
2162
- title: "\u6362\u884C\u952E",
2163
- desc: "\u6309\u4E0B\u540E\u5728\u8F93\u5165\u5185\u6362\u884C",
2164
- value: settings.newlineKey,
2165
- presets: NEWLINE_PRESETS,
2166
- conflict: (chord) => chord !== "" && chord === settings.sendKey,
2167
- onChange: (chord) => {
2168
- setKey("newline", chord);
2169
- }
2170
- }
2171
- ),
2172
- conflictHint !== null && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: hintError, children: conflictHint }),
2173
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2174
- "button",
2175
- {
2176
- type: "button",
2177
- style: pill,
2178
- onClick: () => {
2179
- setConflict(null);
2180
- actions.resetAll();
2181
- },
2182
- children: "\u6062\u590D\u9ED8\u8BA4"
2183
- }
2184
- ) })
2185
- ] }),
2186
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FoldCard, { name: "\u53F3\u952E\u83DC\u5355", summary: menuSummary, children: [
2187
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: bodyLead, children: "\u53F3\u952E\u70B9\u51FB\u8F93\u5165\u6846\u65F6\u7684\u884C\u4E3A\u3002\u7CFB\u7EDF\u539F\u751F\u6A21\u5F0F\u4E0B\u7531\u6D4F\u89C8\u5668\u5F39\u51FA\u81EA\u5DF1\u7684\u83DC\u5355\uFF08\u6837\u5F0F\u968F\u6D4F\u89C8\u5668\u800C\u53D8\u5316\uFF0C \u7C98\u8D34\u514D\u6388\u6743\u3001\u96F6\u914D\u7F6E\uFF09\uFF1B\u81EA\u5B9A\u4E49\u6A21\u5F0F\u4F7F\u7528\u56FA\u5B9A\u6837\u5F0F\u83DC\u5355\uFF08\u672A\u9009\u4E2D\u6587\u672C\u65F6\u300C\u526A\u5207 / \u590D\u5236 / \u5220\u9664\u300D\u7F6E\u7070\uFF0C \u7C98\u8D34\u9700\u8981\u6D4F\u89C8\u5668\u526A\u8D34\u677F\u6388\u6743\uFF0CFirefox \u8981\u5728 about:config \u4E2D\u8BBE\u7F6E permissions.default.clipboard-read = 1 \u624D\u80FD\u514D\u5F39\u7A97\uFF09\u3002" }),
2188
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2189
- ToggleRow,
2190
- {
2191
- first: true,
2192
- label: "\u4F7F\u7528\u7CFB\u7EDF\u539F\u751F\u83DC\u5355",
2193
- desc: "\u6253\u5F00\u540E\u53F3\u952E\u7C98\u8D34\u514D\u6388\u6743\uFF08\u70B9\u51FB\u6D4F\u89C8\u5668\u83DC\u5355\u7684\u7C98\u8D34\u76F4\u63A5\u6210\u529F\uFF09\uFF1B\u5173\u95ED\u540E\u6062\u590D\u81EA\u5B9A\u4E49\u83DC\u5355",
2194
- checked: settings.menuNative,
3033
+ settings.enabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3034
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3035
+ FoldCard,
3036
+ {
3037
+ name: "\u952E\u4F4D",
3038
+ summary: keySummary,
3039
+ toggle: {
3040
+ checked: sections.keys,
2195
3041
  onChange: (next) => {
2196
- actions.setField(MENU_NATIVE_FIELD, next);
3042
+ actions.setField(KEYS_ENABLED_FIELD, next);
2197
3043
  }
2198
- }
2199
- ),
2200
- !settings.menuNative && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
2201
- MENU_ITEMS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2202
- ToggleRow,
2203
- {
2204
- label: item.label,
2205
- desc: item.shortcut !== "" ? `\u5FEB\u6377\u952E ${item.shortcut}` : "",
2206
- checked: settings[item.field],
2207
- onChange: (next) => {
2208
- actions.setField(item.field, next);
3044
+ },
3045
+ children: [
3046
+ /* @__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" }),
3047
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3048
+ KeyRow,
3049
+ {
3050
+ first: true,
3051
+ title: "\u53D1\u9001\u952E",
3052
+ desc: "\u6309\u4E0B\u540E\u53D1\u9001\u5F53\u524D\u8F93\u5165",
3053
+ value: settings.sendKey,
3054
+ presets: SEND_PRESETS,
3055
+ conflict: (chord) => chord !== "" && chord === settings.newlineKey,
3056
+ onChange: (chord) => {
3057
+ setKey("send", chord);
3058
+ }
2209
3059
  }
2210
- },
2211
- item.field
2212
- )),
2213
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2214
- "button",
2215
- {
2216
- type: "button",
2217
- style: pill,
2218
- onClick: () => {
2219
- for (const item of MENU_ITEMS) actions.setField(item.field, true);
2220
- },
2221
- children: "\u5168\u90E8\u5F00\u542F"
2222
- }
2223
- ) })
2224
- ] })
2225
- ] }),
2226
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FoldCard, { name: "\u5FEB\u6377\u6307\u4EE4", summary: quickSummary, children: [
2227
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { style: bodyLead, children: "\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\uFF1B \u6761\u76EE\u53F3\u4FA7\u52FE\u4E0A\u300C\u9ED8\u8BA4\u63D2\u5165\u300D\uFF0C\u5219\u5728\u4F60**\u70B9\u53D1\u9001\u65F6**\u628A\u8FD9\u6761\u63D0\u793A\u8BCD\u81EA\u52A8\u9644\u52A0\u5230\u6D88\u606F**\u672B\u5C3E** \u4E00\u8D77\u53D1\u51FA\u53BB\uFF08\u591A\u6761\u6309\u5217\u8868\u987A\u5E8F\u62FC\u63A5\uFF0C\u8F93\u5165\u6846\u91CC\u4E0D\u63D0\u524D\u663E\u793A\uFF09\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" }),
2228
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2229
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowText, children: [
2230
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowTitle, children: "\u4F18\u5316\u5F3A\u5EA6" }),
2231
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowDesc, children: OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.hint ?? "" })
2232
- ] }),
2233
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }, children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2234
- "button",
2235
- {
2236
- type: "button",
2237
- title: item.hint,
2238
- style: settings.optimizerTier === item.id ? pillActive : pill,
2239
- onClick: () => {
2240
- actions.setField(OPTIMIZER_TIER_FIELD, item.id);
2241
- },
2242
- children: item.label
2243
- },
2244
- item.id
2245
- )) })
2246
- ] }),
2247
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
2248
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: rowText, children: [
2249
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rowTitle, children: "\u5FEB\u6377\u6307\u4EE4\u6E05\u5355" }),
2250
- /* @__PURE__ */ (0, import_jsx_runtime3.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" })
2251
- ] }),
2252
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2253
- QuickPromptsEditor,
2254
- {
2255
- book,
2256
- status: bookStatus,
2257
- onSave: (next) => {
2258
- actions.saveBook(next);
2259
- },
2260
- onReload: () => {
2261
- actions.reloadBook();
2262
- },
2263
- onReset: () => {
2264
- actions.resetBook();
3060
+ ),
3061
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3062
+ KeyRow,
3063
+ {
3064
+ title: "\u6362\u884C\u952E",
3065
+ desc: "\u6309\u4E0B\u540E\u5728\u8F93\u5165\u5185\u6362\u884C",
3066
+ value: settings.newlineKey,
3067
+ presets: NEWLINE_PRESETS,
3068
+ conflict: (chord) => chord !== "" && chord === settings.sendKey,
3069
+ onChange: (chord) => {
3070
+ setKey("newline", chord);
3071
+ }
2265
3072
  }
2266
- }
2267
- )
2268
- ] })
2269
- ] }),
2270
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FoldCard, { name: "\u8BBE\u7F6E\u9762\u677F", summary: panelSummary, children: [
2271
- /* @__PURE__ */ (0, import_jsx_runtime3.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" }),
2272
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2273
- ToggleRow,
2274
- {
2275
- first: true,
2276
- label: "\u5BFC\u822A\u53EF\u6EDA\u52A8",
2277
- desc: "\u8BBE\u7F6E\u6761\u76EE\u8D85\u51FA\u9762\u677F\u9AD8\u5EA6\u65F6\u663E\u793A\u6EDA\u52A8\u6761",
2278
- checked: settings.panelScroll,
3073
+ ),
3074
+ conflictHint !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { style: hintError, children: conflictHint }),
3075
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginTop: 10 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3076
+ "button",
3077
+ {
3078
+ type: "button",
3079
+ style: pill,
3080
+ onClick: () => {
3081
+ setConflict(null);
3082
+ actions.resetAll();
3083
+ },
3084
+ children: "\u6062\u590D\u9ED8\u8BA4"
3085
+ }
3086
+ ) })
3087
+ ]
3088
+ }
3089
+ ),
3090
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3091
+ FoldCard,
3092
+ {
3093
+ name: "\u53F3\u952E\u83DC\u5355",
3094
+ summary: menuSummary,
3095
+ toggle: {
3096
+ checked: sections.menu,
2279
3097
  onChange: (next) => {
2280
- actions.setField(PANEL_SCROLL_FIELD, next);
3098
+ actions.setField(MENU_ENABLED_FIELD, next);
2281
3099
  }
2282
- }
2283
- ),
2284
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2285
- ToggleRow,
2286
- {
2287
- label: "\u8FB9\u7F18\u8C03\u6574\u5927\u5C0F",
2288
- desc: "\u62D6\u52A8\u9762\u677F\u56DB\u8FB9 / \u56DB\u89D2\u6539\u53D8\u9762\u677F\u5C3A\u5BF8",
2289
- checked: settings.panelResize,
3100
+ },
3101
+ children: [
3102
+ /* @__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" }),
3103
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3104
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowText, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u83DC\u5355\u6765\u6E90" }) }),
3105
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3106
+ PillChoice,
3107
+ {
3108
+ items: MENU_MODES,
3109
+ value: settings.menuMode,
3110
+ onChange: (mode) => {
3111
+ actions.setField(MENU_MODE_FIELD, mode);
3112
+ },
3113
+ ariaLabel: "\u53F3\u952E\u83DC\u5355\u6765\u6E90"
3114
+ }
3115
+ )
3116
+ ] }),
3117
+ settings.menuMode === "official" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
3118
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u5B98\u65B9" }),
3119
+ "\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"
3120
+ ] }),
3121
+ settings.menuMode === "browser" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
3122
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u6D4F\u89C8\u5668" }),
3123
+ "\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"
3124
+ ] }),
3125
+ settings.menuMode === "custom" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3126
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
3127
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u81EA\u5B9A\u4E49" }),
3128
+ "\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"
3129
+ ] }),
3130
+ /* @__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" }),
3131
+ /* @__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" }),
3132
+ /* @__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" }),
3133
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { ...row, flexDirection: "column", alignItems: "stretch", gap: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
3134
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u83DC\u5355\u6761\u76EE" }),
3135
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" })
3136
+ ] }) }),
3137
+ MENU_ITEMS.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3138
+ ToggleRow,
3139
+ {
3140
+ first: index === 0,
3141
+ label: item.label,
3142
+ desc: item.shortcut !== "" ? `\u5FEB\u6377\u952E ${item.shortcut}` : "",
3143
+ checked: settings[item.field],
3144
+ onChange: (next) => {
3145
+ actions.setField(item.field, next);
3146
+ }
3147
+ },
3148
+ item.field
3149
+ )),
3150
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { padding: "8px 0 2px" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3151
+ "button",
3152
+ {
3153
+ type: "button",
3154
+ style: pill,
3155
+ onClick: () => {
3156
+ for (const item of MENU_ITEMS) actions.setField(item.field, true);
3157
+ },
3158
+ children: "\u5168\u90E8\u5F00\u542F"
3159
+ }
3160
+ ) })
3161
+ ] })
3162
+ ]
3163
+ }
3164
+ ),
3165
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3166
+ FoldCard,
3167
+ {
3168
+ name: "\u5FEB\u6377\u6307\u4EE4",
3169
+ summary: quickSummary,
3170
+ toggle: {
3171
+ checked: sections.quick,
2290
3172
  onChange: (next) => {
2291
- actions.setField(PANEL_RESIZE_FIELD, next);
3173
+ actions.setField(QUICK_ENABLED_FIELD, next);
2292
3174
  }
2293
- }
2294
- ),
2295
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginTop: 10 }, children: [
2296
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: rowDesc, children: "\u5C3A\u5BF8\u9884\u8BBE\uFF1A" }),
2297
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2298
- "button",
2299
- {
2300
- type: "button",
2301
- style: pill,
2302
- onClick: () => {
2303
- actions.clearField(PANEL_WIDTH_FIELD);
2304
- actions.clearField(PANEL_HEIGHT_FIELD);
2305
- },
2306
- children: "\u9ED8\u8BA4\uFF08800\uFF09"
2307
- }
2308
- ),
2309
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2310
- "button",
2311
- {
2312
- type: "button",
2313
- style: settings.panelWidth === 640 && settings.panelHeight === 600 ? pillActive : pill,
2314
- onClick: () => {
2315
- actions.setField(PANEL_WIDTH_FIELD, 640);
2316
- actions.setField(PANEL_HEIGHT_FIELD, 600);
2317
- },
2318
- children: "\u7D27\u51D1\uFF08640\xD7600\uFF09"
2319
- }
2320
- ),
2321
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2322
- "button",
2323
- {
2324
- type: "button",
2325
- style: settings.panelWidth === 1040 && settings.panelHeight === 760 ? pillActive : pill,
2326
- onClick: () => {
2327
- actions.setField(PANEL_WIDTH_FIELD, 1040);
2328
- actions.setField(PANEL_HEIGHT_FIELD, 760);
2329
- },
2330
- children: "\u5BBD\u655E\uFF081040\xD7760\uFF09"
2331
- }
2332
- )
2333
- ] })
2334
- ] }),
2335
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(FoldCard, { name: "OpenCode \u8BF7\u6C42\u5934", summary: headerSummary, children: [
2336
- /* @__PURE__ */ (0, import_jsx_runtime3.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" }),
2337
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2338
- ToggleRow,
2339
- {
2340
- first: true,
2341
- label: "\u9644\u52A0\u8BF7\u6C42\u5934",
2342
- desc: "\u6253\u5F00\u5373\u5199\u5165\uFF0C\u5E76\u5728\u6BCF\u6B21\u542F\u52A8\u65F6\u8865\u9F50\uFF1B\u5173\u95ED\u5373\u64A4\u9500",
2343
- checked: settings.headerEnabled,
3175
+ },
3176
+ children: [
3177
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: bodyLead, children: [
3178
+ "\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",
3179
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u53D1\u9001\u65F6\u600E\u4E48\u9644\u52A0" }),
3180
+ "\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",
3181
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u672B\u5C3E" }),
3182
+ "\uFF1B \u300C\u4EC5\u9996\u6B21\u300D= \u53EA\u5728",
3183
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("strong", { children: "\u8FD9\u4E2A\u4F1A\u8BDD\u7684\u7B2C\u4E00\u6761\u6D88\u606F" }),
3184
+ "\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"
3185
+ ] }),
3186
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3187
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
3188
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u4F18\u5316\u5F3A\u5EA6" }),
3189
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowDesc, children: OPTIMIZER_TIERS.find((item) => item.id === settings.optimizerTier)?.hint ?? "" })
3190
+ ] }),
3191
+ /* @__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)(
3192
+ "button",
3193
+ {
3194
+ type: "button",
3195
+ title: item.hint,
3196
+ style: settings.optimizerTier === item.id ? pillActive : pill,
3197
+ onClick: () => {
3198
+ actions.setField(OPTIMIZER_TIER_FIELD, item.id);
3199
+ },
3200
+ children: item.label
3201
+ },
3202
+ item.id
3203
+ )) })
3204
+ ] }),
3205
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { ...row, borderTop: "none", flexDirection: "column", alignItems: "stretch", gap: 8 }, children: [
3206
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: rowText, children: [
3207
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: rowTitle, children: "\u5FEB\u6377\u6307\u4EE4\u6E05\u5355" }),
3208
+ /* @__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" })
3209
+ ] }),
3210
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3211
+ QuickPromptsEditor,
3212
+ {
3213
+ book,
3214
+ status: bookStatus,
3215
+ onSave: (next) => {
3216
+ actions.saveBook(next);
3217
+ },
3218
+ onReload: () => {
3219
+ actions.reloadBook();
3220
+ },
3221
+ onReset: () => {
3222
+ actions.resetBook();
3223
+ }
3224
+ }
3225
+ )
3226
+ ] })
3227
+ ]
3228
+ }
3229
+ ),
3230
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3231
+ FoldCard,
3232
+ {
3233
+ name: "\u8BBE\u7F6E\u9762\u677F",
3234
+ summary: panelSummary,
3235
+ toggle: {
3236
+ checked: sections.panel,
2344
3237
  onChange: (next) => {
2345
- actions.setField(HEADER_ENABLED_FIELD, next);
3238
+ actions.setField(PANEL_ENABLED_FIELD, next);
2346
3239
  }
2347
- }
2348
- ),
2349
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2350
- TextFieldRow,
2351
- {
2352
- title: "\u5934\u540D",
2353
- desc: `\u9ED8\u8BA4 ${DEFAULT_HEADER_NAME}\uFF08OpenCode \u5B98\u65B9\u8981\u6C42\u7684\u90A3\u4E00\u4E2A\uFF09`,
2354
- value: settings.headerName,
2355
- placeholder: DEFAULT_HEADER_NAME,
2356
- maxLength: HEADER_NAME_MAX,
3240
+ },
3241
+ controls: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3242
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3243
+ MiniToggle,
3244
+ {
3245
+ label: "\u5BFC\u822A\u6EDA\u52A8",
3246
+ checked: settings.panelScroll,
3247
+ onChange: (next) => {
3248
+ actions.setField(PANEL_SCROLL_FIELD, next);
3249
+ }
3250
+ }
3251
+ ),
3252
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3253
+ MiniToggle,
3254
+ {
3255
+ label: "\u8FB9\u7F18\u7F29\u653E",
3256
+ checked: settings.panelResize,
3257
+ onChange: (next) => {
3258
+ actions.setField(PANEL_RESIZE_FIELD, next);
3259
+ }
3260
+ }
3261
+ )
3262
+ ] }),
3263
+ children: [
3264
+ /* @__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\uFF08\u8FD9\u4E24\u4E2A\u5F00\u5173\u5728\u6807\u9898\u884C\u4E0A\u3002\uFF09" }),
3265
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", marginTop: 10 }, children: [
3266
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: rowDesc, children: "\u5C3A\u5BF8\u9884\u8BBE\uFF1A" }),
3267
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3268
+ "button",
3269
+ {
3270
+ type: "button",
3271
+ style: pill,
3272
+ onClick: () => {
3273
+ actions.clearField(PANEL_WIDTH_FIELD);
3274
+ actions.clearField(PANEL_HEIGHT_FIELD);
3275
+ },
3276
+ children: "\u9ED8\u8BA4\uFF08800\uFF09"
3277
+ }
3278
+ ),
3279
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3280
+ "button",
3281
+ {
3282
+ type: "button",
3283
+ style: settings.panelWidth === 640 && settings.panelHeight === 600 ? pillActive : pill,
3284
+ onClick: () => {
3285
+ actions.setField(PANEL_WIDTH_FIELD, 640);
3286
+ actions.setField(PANEL_HEIGHT_FIELD, 600);
3287
+ },
3288
+ children: "\u7D27\u51D1\uFF08640\xD7600\uFF09"
3289
+ }
3290
+ ),
3291
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3292
+ "button",
3293
+ {
3294
+ type: "button",
3295
+ style: settings.panelWidth === 1040 && settings.panelHeight === 760 ? pillActive : pill,
3296
+ onClick: () => {
3297
+ actions.setField(PANEL_WIDTH_FIELD, 1040);
3298
+ actions.setField(PANEL_HEIGHT_FIELD, 760);
3299
+ },
3300
+ children: "\u5BBD\u655E\uFF081040\xD7760\uFF09"
3301
+ }
3302
+ )
3303
+ ] })
3304
+ ]
3305
+ }
3306
+ ),
3307
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3308
+ FoldCard,
3309
+ {
3310
+ name: "OpenCode \u8BF7\u6C42\u5934",
3311
+ summary: headerSummary,
3312
+ toggle: {
3313
+ checked: sections.header,
2357
3314
  onChange: (next) => {
2358
- actions.setField(HEADER_NAME_FIELD, next);
3315
+ actions.setField(HEADER_ENABLED_FIELD, next);
2359
3316
  }
2360
- }
2361
- ),
2362
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2363
- TextFieldRow,
2364
- {
2365
- title: "\u503C",
2366
- 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",
2367
- value: settings.headerValue,
2368
- placeholder: "\u7559\u7A7A = \u81EA\u52A8\u751F\u6210",
2369
- maxLength: HEADER_VALUE_MAX,
2370
- onChange: (next) => {
2371
- actions.setField(HEADER_VALUE_FIELD, next);
2372
- },
2373
- action: {
2374
- label: "\u91CD\u65B0\u751F\u6210",
2375
- onClick: () => {
2376
- actions.setField(HEADER_VALUE_FIELD, newSessionId());
3317
+ },
3318
+ children: [
3319
+ /* @__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" }),
3320
+ /* @__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" }),
3321
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3322
+ TextFieldRow,
3323
+ {
3324
+ title: "\u5934\u540D",
3325
+ desc: `\u9ED8\u8BA4 ${DEFAULT_HEADER_NAME}\uFF08OpenCode \u5B98\u65B9\u8981\u6C42\u7684\u90A3\u4E00\u4E2A\uFF09`,
3326
+ value: settings.headerName,
3327
+ placeholder: DEFAULT_HEADER_NAME,
3328
+ maxLength: HEADER_NAME_MAX,
3329
+ onChange: (next) => {
3330
+ actions.setField(HEADER_NAME_FIELD, next);
3331
+ }
2377
3332
  }
2378
- }
2379
- }
2380
- ),
2381
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2382
- TextFieldRow,
2383
- {
2384
- title: "\u4F5C\u7528\u8DEF\u7531",
2385
- 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",
2386
- value: settings.headerRoutes,
2387
- placeholder: "\u7559\u7A7A = \u81EA\u52A8\uFF08opencode* \u6216 opencode.ai \u7AEF\u70B9\uFF09",
2388
- maxLength: HEADER_VALUE_MAX,
3333
+ ),
3334
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3335
+ TextFieldRow,
3336
+ {
3337
+ title: "\u503C",
3338
+ 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",
3339
+ value: settings.headerValue,
3340
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8\u751F\u6210",
3341
+ maxLength: HEADER_VALUE_MAX,
3342
+ onChange: (next) => {
3343
+ actions.setField(HEADER_VALUE_FIELD, next);
3344
+ },
3345
+ action: {
3346
+ label: "\u91CD\u65B0\u751F\u6210",
3347
+ onClick: () => {
3348
+ actions.setField(HEADER_VALUE_FIELD, newSessionId());
3349
+ }
3350
+ }
3351
+ }
3352
+ ),
3353
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3354
+ TextFieldRow,
3355
+ {
3356
+ title: "\u4F5C\u7528\u8DEF\u7531",
3357
+ 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",
3358
+ value: settings.headerRoutes,
3359
+ placeholder: "\u7559\u7A7A = \u81EA\u52A8\uFF08opencode* \u6216 opencode.ai \u7AEF\u70B9\uFF09",
3360
+ maxLength: HEADER_VALUE_MAX,
3361
+ onChange: (next) => {
3362
+ actions.setField(HEADER_ROUTES_FIELD, next);
3363
+ }
3364
+ }
3365
+ ),
3366
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: hintInfo, children: [
3367
+ "\u72B6\u6001\uFF1A",
3368
+ headerStatusText
3369
+ ] })
3370
+ ]
3371
+ }
3372
+ ),
3373
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3374
+ FoldCard,
3375
+ {
3376
+ name: "\u9ED8\u8BA4\u7EC8\u7AEF",
3377
+ summary: terminalSummary,
3378
+ toggle: {
3379
+ checked: sections.terminal,
2389
3380
  onChange: (next) => {
2390
- actions.setField(HEADER_ROUTES_FIELD, next);
3381
+ actions.setField(TERMINAL_ENABLED_FIELD, next);
2391
3382
  }
2392
- }
2393
- ),
2394
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { style: hintInfo, children: [
2395
- "\u72B6\u6001\uFF1A",
2396
- headerStatusText
2397
- ] })
2398
- ] })
3383
+ },
3384
+ controls: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3385
+ PillChoice,
3386
+ {
3387
+ compact: true,
3388
+ items: TERMINAL_MODES,
3389
+ value: settings.terminalMode,
3390
+ onChange: (mode) => {
3391
+ actions.setField(TERMINAL_MODE_FIELD, mode);
3392
+ },
3393
+ ariaLabel: "\u7EC8\u7AEF\u5DE5\u5177"
3394
+ }
3395
+ ),
3396
+ children: [
3397
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" }),
3398
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DefaultTerminalBody, { settings, setField: actions.setField, hideMode: true })
3399
+ ]
3400
+ }
3401
+ )
2399
3402
  ] })
2400
3403
  ] });
2401
3404
  }
2402
3405
 
2403
3406
  // src/client/QuickCommandsButton.tsx
2404
- var import_react4 = require("react");
2405
- var import_jsx_runtime4 = require("react/jsx-runtime");
3407
+ var import_react5 = require("react");
3408
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2406
3409
  function QuickCommandsButton({
2407
3410
  useInput,
2408
3411
  inputActions,
2409
3412
  sessionId,
3413
+ useSession,
2410
3414
  useLive,
2411
3415
  usePanel,
2412
3416
  actions
@@ -2414,21 +3418,23 @@ function QuickCommandsButton({
2414
3418
  const settings = useLive((item) => item);
2415
3419
  const anchor = usePanel((item) => item);
2416
3420
  const draft = useInput((state2) => state2.draft);
2417
- const ref = (0, import_react4.useRef)(null);
2418
- (0, import_react4.useEffect)(() => {
3421
+ const blank = useSession((state2) => state2?.blank === true);
3422
+ const ref = (0, import_react5.useRef)(null);
3423
+ (0, import_react5.useEffect)(() => {
2419
3424
  const sid = typeof sessionId === "string" ? sessionId : "";
2420
3425
  publishInputBridge({
2421
3426
  actions: inputActions ?? null,
2422
3427
  draft: typeof draft === "string" ? draft : "",
2423
- sessionId: sid
3428
+ sessionId: sid,
3429
+ blank: blank === true
2424
3430
  });
2425
3431
  return () => {
2426
3432
  releaseInputBridge(sid);
2427
3433
  };
2428
- }, [inputActions, draft, sessionId]);
2429
- if (settings.enabled !== true) return null;
3434
+ }, [inputActions, draft, sessionId, blank]);
3435
+ if (!activeSections(settings).quick) return null;
2430
3436
  const open = anchor !== null;
2431
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3437
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2432
3438
  "button",
2433
3439
  {
2434
3440
  ref,
@@ -2449,14 +3455,14 @@ function QuickCommandsButton({
2449
3455
  });
2450
3456
  },
2451
3457
  children: [
2452
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3458
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2453
3459
  "svg",
2454
3460
  {
2455
3461
  viewBox: "0 0 16 16",
2456
3462
  width: "12",
2457
3463
  height: "12",
2458
3464
  "aria-hidden": true,
2459
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3465
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2460
3466
  "path",
2461
3467
  {
2462
3468
  d: "M9.2 1.2 3.4 9.1h3.5l-0.9 5.7 6-8.1H8.4l0.8-5.5Z",
@@ -2465,15 +3471,15 @@ function QuickCommandsButton({
2465
3471
  )
2466
3472
  }
2467
3473
  ),
2468
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "\u5FEB\u6377\u6307\u4EE4" })
3474
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: "\u5FEB\u6377\u6307\u4EE4" })
2469
3475
  ]
2470
3476
  }
2471
3477
  );
2472
3478
  }
2473
3479
 
2474
3480
  // src/client/QuickCommandsPanel.tsx
2475
- var import_react5 = require("react");
2476
- var import_jsx_runtime5 = require("react/jsx-runtime");
3481
+ var import_react6 = require("react");
3482
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2477
3483
  var MARGIN = 8;
2478
3484
  var GAP = 8;
2479
3485
  function QuickCommandsPanel({
@@ -2491,13 +3497,13 @@ function QuickCommandsPanel({
2491
3497
  const notice = useNotice((item) => item);
2492
3498
  const book = useBook((item) => item);
2493
3499
  const status = useBookStatus((item) => item);
2494
- const ref = (0, import_react5.useRef)(null);
2495
- const [position, setPosition] = (0, import_react5.useState)(null);
2496
- const [activeId, setActiveId] = (0, import_react5.useState)("");
3500
+ const ref = (0, import_react6.useRef)(null);
3501
+ const [position, setPosition] = (0, import_react6.useState)(null);
3502
+ const [activeId, setActiveId] = (0, import_react6.useState)("");
2497
3503
  const counts = bookCounts(book);
2498
3504
  const categories = book.categories;
2499
- const active = categories.find((category) => category.id === activeId) ?? categories[0];
2500
- (0, import_react5.useLayoutEffect)(() => {
3505
+ const active2 = categories.find((category) => category.id === activeId) ?? categories[0];
3506
+ (0, import_react6.useLayoutEffect)(() => {
2501
3507
  if (anchor === null) {
2502
3508
  setPosition(null);
2503
3509
  return;
@@ -2510,7 +3516,7 @@ function QuickCommandsPanel({
2510
3516
  const top = above >= MARGIN ? above : Math.min(anchor.bottom + GAP, window.innerHeight - height - MARGIN);
2511
3517
  setPosition({ left, top: Math.max(MARGIN, top) });
2512
3518
  }, [anchor?.left, anchor?.bottom, counts.prompts, categories.length, busy]);
2513
- (0, import_react5.useEffect)(() => {
3519
+ (0, import_react6.useEffect)(() => {
2514
3520
  if (anchor === null) return;
2515
3521
  const onPointerDown = (event) => {
2516
3522
  if (ref.current !== null && event.target instanceof Node && ref.current.contains(event.target)) return;
@@ -2534,9 +3540,9 @@ function QuickCommandsPanel({
2534
3540
  }, [anchor === null, actions]);
2535
3541
  if (anchor === null) return null;
2536
3542
  const tier = settings.optimizerTier;
2537
- const items = active?.prompts ?? [];
3543
+ const items = active2?.prompts ?? [];
2538
3544
  const failure = status !== "" && status !== "saving" ? status : "";
2539
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3545
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2540
3546
  "div",
2541
3547
  {
2542
3548
  ref,
@@ -2544,10 +3550,10 @@ function QuickCommandsPanel({
2544
3550
  "aria-label": "\u5FEB\u6377\u6307\u4EE4",
2545
3551
  style: { ...quickPanel, left: position?.left ?? anchor.left, top: position?.top ?? anchor.bottom },
2546
3552
  children: [
2547
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickPanelHead, children: [
2548
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickPanelTitleRow, children: [
2549
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: quickPanelTitle, children: "\u5FEB\u6377\u6307\u4EE4" }),
2550
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: quickTierRow, role: "group", "aria-label": "\u4F18\u5316\u5F3A\u5EA6", children: OPTIMIZER_TIERS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3553
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelHead, children: [
3554
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelTitleRow, children: [
3555
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickPanelTitle, children: "\u5FEB\u6377\u6307\u4EE4" }),
3556
+ /* @__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)(
2551
3557
  "button",
2552
3558
  {
2553
3559
  type: "button",
@@ -2565,7 +3571,7 @@ function QuickCommandsPanel({
2565
3571
  item.id
2566
3572
  )) })
2567
3573
  ] }),
2568
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3574
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2569
3575
  "button",
2570
3576
  {
2571
3577
  type: "button",
@@ -2579,19 +3585,19 @@ function QuickCommandsPanel({
2579
3585
  actions.optimize();
2580
3586
  },
2581
3587
  children: [
2582
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "aria-hidden": true, children: "\u2728" }),
2583
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: busy ? "\u4F18\u5316\u4E2D\u2026" : "\u4F18\u5316\u63D0\u793A\u8BCD" })
3588
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": true, children: "\u2728" }),
3589
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: busy ? "\u4F18\u5316\u4E2D\u2026" : "\u4F18\u5316\u63D0\u793A\u8BCD" })
2584
3590
  ]
2585
3591
  }
2586
3592
  ),
2587
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickCategoryRow, children: [
2588
- categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3593
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickCategoryRow, children: [
3594
+ categories.map((category) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2589
3595
  "button",
2590
3596
  {
2591
3597
  type: "button",
2592
3598
  title: `${category.name}\uFF08${String(category.prompts.length)} \u6761\uFF09`,
2593
- "aria-pressed": category.id === active?.id,
2594
- style: category.id === active?.id ? quickCategoryTabActive : quickCategoryTab,
3599
+ "aria-pressed": category.id === active2?.id,
3600
+ style: category.id === active2?.id ? quickCategoryTabActive : quickCategoryTab,
2595
3601
  onMouseDown: (event) => {
2596
3602
  event.preventDefault();
2597
3603
  },
@@ -2602,7 +3608,7 @@ function QuickCommandsPanel({
2602
3608
  },
2603
3609
  category.id
2604
3610
  )),
2605
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3611
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2606
3612
  "button",
2607
3613
  {
2608
3614
  type: "button",
@@ -2620,14 +3626,14 @@ function QuickCommandsPanel({
2620
3626
  )
2621
3627
  ] })
2622
3628
  ] }),
2623
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickList, children: [
2624
- items.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickEmpty, children: [
3629
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickList, children: [
3630
+ items.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickEmpty, children: [
2625
3631
  "\u8FD9\u4E2A\u5206\u7C7B\u91CC\u8FD8\u6CA1\u6709\u6761\u76EE\u3002",
2626
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("br", {}),
3632
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("br", {}),
2627
3633
  "\u5728\u300C\u8BBE\u7F6E \u2192 \u8F93\u5165\u4F53\u9A8C \u2192 \u5FEB\u6377\u6307\u4EE4\u6E05\u5355\u300D\u91CC\u6DFB\u52A0\u3002"
2628
3634
  ] }),
2629
- items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
2630
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3635
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
3636
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2631
3637
  "button",
2632
3638
  {
2633
3639
  type: "button",
@@ -2640,30 +3646,41 @@ function QuickCommandsPanel({
2640
3646
  actions.insert(item.prompt);
2641
3647
  },
2642
3648
  children: [
2643
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: quickItemLabel, children: item.label }),
2644
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: quickItemPreview, children: item.prompt.replace(/\s+/g, " ") })
3649
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickItemLabel, children: item.label }),
3650
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickItemPreview, children: item.prompt.replace(/\s+/g, " ") })
2645
3651
  ]
2646
3652
  }
2647
3653
  ),
2648
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: quickAlwaysLabel, title: "\u52FE\u4E0A\u540E\uFF0C\u70B9\u53D1\u9001\u65F6\u8FD9\u6761\u63D0\u793A\u8BCD\u4F1A\u81EA\u52A8\u9644\u52A0\u5230\u4F60\u7684\u6D88\u606F\u672B\u5C3E\uFF08\u5BF9\u6240\u6709\u5206\u7C7B\u751F\u6548\uFF09", children: [
2649
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2650
- "input",
2651
- {
2652
- type: "checkbox",
2653
- style: quickAlwaysBox,
2654
- checked: item.always,
2655
- onChange: (event) => {
2656
- actions.setAlways(item.id, event.target.checked);
2657
- }
3654
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3655
+ InsertModeControl,
3656
+ {
3657
+ compact: true,
3658
+ label: item.label,
3659
+ mode: insertModeOf(item),
3660
+ onChange: (mode) => {
3661
+ actions.setInsertMode(item.id, mode);
2658
3662
  }
2659
- ),
2660
- "\u9ED8\u8BA4\u63D2\u5165"
2661
- ] })
2662
- ] }, item.id))
3663
+ }
3664
+ )
3665
+ ] }, item.id)),
3666
+ active2 !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3667
+ AddPromptRow,
3668
+ {
3669
+ variant: "panel",
3670
+ book,
3671
+ categoryId: active2.id,
3672
+ onAdd: () => {
3673
+ actions.addPrompt(active2.id);
3674
+ },
3675
+ onMove: (promptId) => {
3676
+ actions.movePrompt(promptId, active2.id);
3677
+ }
3678
+ }
3679
+ )
2663
3680
  ] }),
2664
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: quickPanelFoot, children: [
2665
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: quickNotice, role: "status", children: notice !== "" ? notice : failure }),
2666
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
3681
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: quickPanelFoot, children: [
3682
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: quickNotice, role: "status", children: notice !== "" ? notice : failure }),
3683
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2667
3684
  "span",
2668
3685
  {
2669
3686
  style: quickFootHint,
@@ -2771,6 +3788,10 @@ function apply(ctx) {
2771
3788
  resetBook: () => {
2772
3789
  commitBook(defaultQuickBook());
2773
3790
  },
3791
+ /** 把某条从它所在分类移到目标分类(「移动到这里」:追加到目标末尾)。 */
3792
+ movePromptToCategory: (promptId, toCategoryId) => {
3793
+ commitBook(withPromptMovedToCategory(book.getSnapshot(), promptId, toCategoryId));
3794
+ },
2774
3795
  /** 设置页「保存」:把编辑器里的整本一次写回(而不是每敲一个字就写盘)。 */
2775
3796
  saveBook: (next) => {
2776
3797
  commitBook(next);
@@ -2783,6 +3804,8 @@ function apply(ctx) {
2783
3804
  SEND_KEY_FIELD,
2784
3805
  NEWLINE_KEY_FIELD,
2785
3806
  ...MENU_FIELDS,
3807
+ MENU_MODE_FIELD,
3808
+ // 旧的布尔字段也一并清掉:它只是迁移线索,留着会把「恢复默认」后的档位又拉回旧值。
2786
3809
  MENU_NATIVE_FIELD,
2787
3810
  PANEL_SCROLL_FIELD,
2788
3811
  PANEL_RESIZE_FIELD,
@@ -2792,7 +3815,20 @@ function apply(ctx) {
2792
3815
  HEADER_NAME_FIELD,
2793
3816
  HEADER_VALUE_FIELD,
2794
3817
  HEADER_ROUTES_FIELD,
2795
- OPTIMIZER_TIER_FIELD
3818
+ OPTIMIZER_TIER_FIELD,
3819
+ // 0.5.0 新增的用户配置:终端档位/路径(「恢复默认」也该把它们恢复)。
3820
+ TERMINAL_MODE_FIELD,
3821
+ TERMINAL_BASH_PATH_FIELD,
3822
+ // 五栏开关也清掉:清掉 = 回到"从没碰过这一栏"⇒ 全关(新装默认的样子)。
3823
+ // 若不清,恢复默认之后六栏还会保持之前打开的状态,与"默认关"的语义不符。
3824
+ KEYS_ENABLED_FIELD,
3825
+ MENU_ENABLED_FIELD,
3826
+ QUICK_ENABLED_FIELD,
3827
+ PANEL_ENABLED_FIELD,
3828
+ TERMINAL_ENABLED_FIELD,
3829
+ // 0.5.0 里那个「可选重启命令」字段已经删掉,但老文档里可能还留着值:
3830
+ // 顺手清掉,免得它永远躺在设置文件里没人认识。
3831
+ "restartCommand"
2796
3832
  ].map((field) => ({ op: "unset", path: [field] }))
2797
3833
  ).catch((error) => {
2798
3834
  console.error("[composer-ux] settings reset failed", error);
@@ -2858,11 +3894,13 @@ function apply(ctx) {
2858
3894
  setField(OPTIMIZER_TIER_FIELD, tier);
2859
3895
  },
2860
3896
  /**
2861
- * 「默认插入」勾选:按 id 跨分类找那一条,直接写盘。
2862
- * 这个标记就是「点发送时自动附加到消息末尾」的依据(见 interceptors.ts)。
3897
+ * 设置某条的插入模式(关 / 每次 / 仅首次)。
3898
+ *
3899
+ * 界面上只有这一个入口:两个互斥标志由 `withInsertMode` **一次写对**,
3900
+ * 不给「又每次又仅首次」留缝。
2863
3901
  */
2864
- setAlways: (id, value) => {
2865
- commitBook(withAlwaysToggled(book.getSnapshot(), id, value));
3902
+ setInsertMode: (promptId, mode) => {
3903
+ commitBook(withInsertMode(book.getSnapshot(), promptId, mode));
2866
3904
  }
2867
3905
  };
2868
3906
  slots.inject("settings.section", () => slots.register({
@@ -2926,12 +3964,13 @@ function apply(ctx) {
2926
3964
  insert: quickActions.insert,
2927
3965
  optimize: quickActions.optimize,
2928
3966
  setTier: quickActions.setTier,
2929
- setAlways: quickActions.setAlways,
2930
- toggleAlways: quickActions.setAlways,
3967
+ setInsertMode: quickActions.setInsertMode,
2931
3968
  addCategory: bookActions.addCategory,
2932
3969
  renameCategory: bookActions.renameCategory,
2933
3970
  removeCategory: bookActions.removeCategory,
2934
3971
  moveCategory: bookActions.moveCategory,
3972
+ addPrompt: bookActions.addPrompt,
3973
+ movePrompt: bookActions.movePromptToCategory,
2935
3974
  reloadBook: bookActions.reload
2936
3975
  }
2937
3976
  })
@@ -2942,7 +3981,7 @@ function apply(ctx) {
2942
3981
  () => installPanelStyle(
2943
3982
  () => {
2944
3983
  const settings = live.getSnapshot();
2945
- return settings.enabled && settings.panelScroll;
3984
+ return activeSections(settings).panel && settings.panelScroll;
2946
3985
  },
2947
3986
  (listener) => live.subscribe(listener)
2948
3987
  ),
@@ -2951,24 +3990,27 @@ function apply(ctx) {
2951
3990
  ctx.effect(() => {
2952
3991
  let dispose = null;
2953
3992
  const syncInterceptors = () => {
2954
- const enabled = live.getSnapshot().enabled;
2955
- if (enabled && dispose === null) {
3993
+ const settings = live.getSnapshot();
3994
+ const sections = activeSections(settings);
3995
+ const wanted = sections.keys || sections.menu || sections.quick;
3996
+ if (wanted && dispose === null) {
2956
3997
  dispose = installInterceptors({
2957
3998
  settings: () => live.getSnapshot(),
2958
- alwaysPrompts: () => alwaysQuickPrompts(book.getSnapshot()),
3999
+ // 「仅首次」由这里决定是否算进这一批:会话还是空的(blank)才带上。
4000
+ // 「快捷指令」栏关掉时这里直接给空批次 —— 这是唯一一处"关掉就不附加"的闸,
4001
+ // 键位发送与官方按钮两条路都从这里取批次,不需要各写一遍。
4002
+ promptsForSend: () => activeSections(live.getSnapshot()).quick ? appendBatchForSend(book.getSnapshot(), currentBlankSession()) : [],
2959
4003
  setMenu: (state2) => {
2960
4004
  menu2.set(state2);
2961
4005
  },
2962
4006
  menuOpen: () => menu2.getSnapshot() !== null
2963
4007
  });
2964
- } else if (!enabled) {
4008
+ } else if (!wanted) {
2965
4009
  dispose?.();
2966
4010
  dispose = null;
2967
- menu2.set(null);
2968
- panel.set(null);
2969
4011
  }
2970
- if (live.getSnapshot().menuNative) menu2.set(null);
2971
- if (!live.getSnapshot().enabled) panel.set(null);
4012
+ if (settings.menuMode !== "custom" || !sections.menu) menu2.set(null);
4013
+ if (!sections.quick) panel.set(null);
2972
4014
  };
2973
4015
  syncInterceptors();
2974
4016
  const unsubscribe = live.subscribe(syncInterceptors);