dsh-ccgui 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +327 -2
  3. package/THIRD_PARTY_NOTICES.md +64 -0
  4. package/assets/logo.png +0 -0
  5. package/cordis.patch.yml +32 -0
  6. package/lib/abortable.d.ts +12 -0
  7. package/lib/abortable.js +27 -0
  8. package/lib/adapter.d.ts +39 -0
  9. package/lib/adapter.js +64 -0
  10. package/lib/async-queue.d.ts +26 -0
  11. package/lib/async-queue.js +55 -0
  12. package/lib/cli-session.d.ts +99 -0
  13. package/lib/cli-session.js +384 -0
  14. package/lib/cli-tool.d.ts +18 -0
  15. package/lib/cli-tool.js +101 -0
  16. package/lib/client.js +4039 -0
  17. package/lib/constants.d.ts +22 -0
  18. package/lib/constants.js +22 -0
  19. package/lib/git/git-read.d.ts +65 -0
  20. package/lib/git/git-read.js +139 -0
  21. package/lib/git/git-requests.d.ts +44 -0
  22. package/lib/git/git-requests.js +153 -0
  23. package/lib/git/git-routes.d.ts +38 -0
  24. package/lib/git/git-routes.js +78 -0
  25. package/lib/git/git-run.d.ts +58 -0
  26. package/lib/git/git-run.js +97 -0
  27. package/lib/git/git-status.d.ts +51 -0
  28. package/lib/git/git-status.js +122 -0
  29. package/lib/git/git-write.d.ts +75 -0
  30. package/lib/git/git-write.js +134 -0
  31. package/lib/index.d.ts +78 -0
  32. package/lib/index.js +229 -0
  33. package/lib/model-cache.d.ts +33 -0
  34. package/lib/model-cache.js +101 -0
  35. package/lib/model-catalog.d.ts +63 -0
  36. package/lib/model-catalog.js +107 -0
  37. package/lib/model-options.d.ts +26 -0
  38. package/lib/model-options.js +46 -0
  39. package/lib/model-probe.d.ts +16 -0
  40. package/lib/model-probe.js +91 -0
  41. package/lib/npx-cache.d.ts +39 -0
  42. package/lib/npx-cache.js +97 -0
  43. package/lib/permission.d.ts +17 -0
  44. package/lib/permission.js +34 -0
  45. package/lib/prompt-images.d.ts +44 -0
  46. package/lib/prompt-images.js +46 -0
  47. package/lib/request-input.d.ts +42 -0
  48. package/lib/request-input.js +113 -0
  49. package/lib/session/connect.d.ts +41 -0
  50. package/lib/session/connect.js +68 -0
  51. package/lib/session/drive-tool.d.ts +39 -0
  52. package/lib/session/drive-tool.js +37 -0
  53. package/lib/session/model-state.d.ts +40 -0
  54. package/lib/session/model-state.js +68 -0
  55. package/lib/session/outcomes.d.ts +31 -0
  56. package/lib/session/outcomes.js +67 -0
  57. package/lib/session/permission-queue.d.ts +24 -0
  58. package/lib/session/permission-queue.js +33 -0
  59. package/lib/session/read-step.d.ts +31 -0
  60. package/lib/session/read-step.js +53 -0
  61. package/lib/session/tool-mirror.d.ts +65 -0
  62. package/lib/session/tool-mirror.js +131 -0
  63. package/lib/session/turn-queue.d.ts +76 -0
  64. package/lib/session/turn-queue.js +102 -0
  65. package/lib/session/types.d.ts +58 -0
  66. package/lib/session/types.js +6 -0
  67. package/lib/session-registry.d.ts +124 -0
  68. package/lib/session-registry.js +189 -0
  69. package/lib/stdio-transport.d.ts +28 -0
  70. package/lib/stdio-transport.js +164 -0
  71. package/lib/stream-blocks.d.ts +52 -0
  72. package/lib/stream-blocks.js +95 -0
  73. package/lib/tool-record.d.ts +100 -0
  74. package/lib/tool-record.js +167 -0
  75. package/lib/transport.d.ts +35 -0
  76. package/lib/transport.js +5 -0
  77. package/package.json +136 -4
package/lib/client.js ADDED
@@ -0,0 +1,4039 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-ccgui", factory: (require) => { var module = { exports: {} }; var exports = module.exports;
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/client/index.tsx
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ apply: () => apply,
25
+ inject: () => inject
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+ var import_react17 = require("react");
29
+ var import_dsh_client_ui_primitives14 = require("@deepseek-ai/dsh-client-ui-primitives");
30
+
31
+ // src/client/add-to-chat.tsx
32
+ var import_react = require("react");
33
+
34
+ // src/client/path-mention.ts
35
+ function mentionToken(path) {
36
+ const slashed = path.trim().replace(/\\/gu, "/");
37
+ return /\s/u.test(slashed) ? `@"${slashed}" ` : `@${slashed} `;
38
+ }
39
+
40
+ // src/client/add-to-chat.tsx
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var LABEL = "\u6DFB\u52A0\u5230\u5BF9\u8BDD";
43
+ var FAILURE_LABEL = "\u6CA1\u80FD\u6DFB\u52A0\u5230\u5BF9\u8BDD\uFF1A\u8F93\u5165\u6846\u6B63\u5728\u53D1\u9001\u6216\u5DF2\u5173\u95ED\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5";
44
+ var NO_COMPOSER = "\u8FD9\u4E2A\u4F1A\u8BDD\u7684\u8F93\u5165\u6846\u6CA1\u6709\u6253\u5F00";
45
+ var REFUSED = "\u8F93\u5165\u6846\u6682\u65F6\u4E0D\u63A5\u53D7\u8F93\u5165";
46
+ var ICON_KEY = "dsh-ccgui.add-to-chat";
47
+ var ICON_SLOT = "contextMenu.icon";
48
+ var BRIDGE_SLOT = "conversation.input.left";
49
+ var MENU_ORDER = 50;
50
+ function composerRegistry() {
51
+ let composers = /* @__PURE__ */ new Map();
52
+ const attach = (sessionId, actions) => {
53
+ composers = new Map(composers).set(sessionId, actions);
54
+ return () => {
55
+ if (composers.get(sessionId) !== actions) return;
56
+ composers = new Map([...composers].filter(([id]) => id !== sessionId));
57
+ };
58
+ };
59
+ const insert = (sessionId, text) => {
60
+ const composer = composers.get(sessionId);
61
+ if (composer === void 0) throw new Error(NO_COMPOSER);
62
+ if (!composer.insertText(text, composer.captureInsertion())) throw new Error(REFUSED);
63
+ };
64
+ return { attach, insert };
65
+ }
66
+ function ComposerBridge(props) {
67
+ const { sessionId, inputActions, attach } = props;
68
+ (0, import_react.useEffect)(() => attach(sessionId, inputActions), [attach, sessionId, inputActions]);
69
+ return null;
70
+ }
71
+ function PlusIcon() {
72
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 3.5V12.5M3.5 8H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) });
73
+ }
74
+ function contribution(kind, insert) {
75
+ return {
76
+ id: `${ICON_KEY}.${kind}`,
77
+ target: kind,
78
+ order: MENU_ORDER,
79
+ resolve: ({ sessionId, path }) => [
80
+ {
81
+ id: "add-to-chat",
82
+ label: LABEL,
83
+ icon: { key: ICON_KEY },
84
+ failureLabel: FAILURE_LABEL,
85
+ run: () => {
86
+ insert(sessionId, mentionToken(path));
87
+ }
88
+ }
89
+ ]
90
+ };
91
+ }
92
+ function registerAddToChat(ctx) {
93
+ ctx.inject(["contextMenus"], (child) => {
94
+ const { attach, insert } = composerRegistry();
95
+ child.slots.inject(
96
+ BRIDGE_SLOT,
97
+ () => child.slots.register(
98
+ { name: BRIDGE_SLOT, id: "dsh-ccgui.composer-bridge", inject: () => ({ attach }) },
99
+ ComposerBridge
100
+ )
101
+ );
102
+ child.slots.inject(ICON_SLOT, () => child.slots.register({ name: ICON_SLOT, key: ICON_KEY }, PlusIcon));
103
+ child.effect(() => child.contextMenus.register(contribution("file", insert)), "ccgui: add file to chat");
104
+ child.effect(() => child.contextMenus.register(contribution("directory", insert)), "ccgui: add folder to chat");
105
+ });
106
+ }
107
+
108
+ // src/constants.ts
109
+ var CLI_ROUTE_PREFIX = "cli-";
110
+ var cliRoute = (id) => `${CLI_ROUTE_PREFIX}${id}`;
111
+ var DEFAULT_MODEL_ID = "default";
112
+ var GIT_ROUTE_PREFIX = "/dsh-ccgui/git";
113
+
114
+ // src/client/choices.ts
115
+ function cliModels({ groups, current }) {
116
+ const group = groups.find((candidate) => candidate.id === current?.provider);
117
+ if (!group?.id.startsWith(CLI_ROUTE_PREFIX)) return void 0;
118
+ const selected = group.models.find((model) => model.id === current?.model);
119
+ return {
120
+ provider: group.id,
121
+ name: group.name,
122
+ rows: group.models,
123
+ currentId: selected?.id,
124
+ currentName: selected?.name,
125
+ listed: group.models.some((model) => model.name !== group.name)
126
+ };
127
+ }
128
+ function cliChoices({ groups, current }) {
129
+ const selected = groups.find((group) => group.id === current?.provider);
130
+ return {
131
+ visible: groups.some((group) => group.id.startsWith(CLI_ROUTE_PREFIX)),
132
+ items: groups.map((group) => ({ id: group.id, label: group.name })),
133
+ currentId: selected?.id,
134
+ currentLabel: selected?.name
135
+ };
136
+ }
137
+ function selectionForChoice({ groups, current }, provider) {
138
+ if (current?.provider === provider) return void 0;
139
+ const first = groups.find((group) => group.id === provider)?.models[0];
140
+ if (first === void 0) return void 0;
141
+ return { provider, model: provider.startsWith(CLI_ROUTE_PREFIX) ? DEFAULT_MODEL_ID : first.id };
142
+ }
143
+
144
+ // src/client/cli-prefs.ts
145
+ var CLI_PREFS_STORAGE_KEY = "dsh-ccgui.cli-prefs";
146
+ var OFFICIAL_PROVIDER_ID = "deepseek-official";
147
+ var HIDDEN_BY_DEFAULT = /* @__PURE__ */ new Set([cliRoute("codebuddy")]);
148
+ var EMPTY = { known: [], order: [], hidden: [] };
149
+ function isRecord(value) {
150
+ return typeof value === "object" && value !== null && !Array.isArray(value);
151
+ }
152
+ function strings(value) {
153
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
154
+ }
155
+ function choices(value) {
156
+ if (!Array.isArray(value)) return [];
157
+ return value.flatMap(
158
+ (item) => isRecord(item) && typeof item.id === "string" && typeof item.label === "string" ? [{ id: item.id, label: item.label }] : []
159
+ );
160
+ }
161
+ function parseCliPrefs(raw) {
162
+ if (raw === null) return EMPTY;
163
+ let value;
164
+ try {
165
+ value = JSON.parse(raw);
166
+ } catch (_error) {
167
+ return EMPTY;
168
+ }
169
+ if (!isRecord(value)) return EMPTY;
170
+ return {
171
+ known: choices(value.known),
172
+ order: strings(value.order),
173
+ hidden: strings(value.hidden).filter((id) => id !== OFFICIAL_PROVIDER_ID)
174
+ };
175
+ }
176
+ function sortByOrder(items, order) {
177
+ const rank = (id) => {
178
+ const index = order.indexOf(id);
179
+ return index === -1 ? order.length : index;
180
+ };
181
+ return [...items].sort((a, b) => rank(a.id) - rank(b.id));
182
+ }
183
+ function arrangeChoices(items, prefs) {
184
+ return sortByOrder(
185
+ items.filter((item) => item.id === OFFICIAL_PROVIDER_ID || !prefs.hidden.includes(item.id)),
186
+ prefs.order
187
+ );
188
+ }
189
+ function listedEntries(prefs) {
190
+ return sortByOrder(prefs.known, prefs.order).map((choice) => ({
191
+ ...choice,
192
+ enabled: choice.id === OFFICIAL_PROVIDER_ID || !prefs.hidden.includes(choice.id)
193
+ }));
194
+ }
195
+ function rememberChoices(prefs, seen) {
196
+ const renamed = prefs.known.map((known) => seen.find((choice) => choice.id === known.id) ?? known);
197
+ const added = seen.filter((choice) => !prefs.known.some((known) => known.id === choice.id));
198
+ const changed = added.length > 0 || renamed.some((choice, index) => choice.label !== prefs.known[index]?.label);
199
+ if (!changed) return prefs;
200
+ const startHidden = added.map((choice) => choice.id).filter((id) => HIDDEN_BY_DEFAULT.has(id));
201
+ const hidden = [...prefs.hidden, ...startHidden.filter((id) => !prefs.hidden.includes(id))];
202
+ return { ...prefs, known: [...renamed, ...added], hidden };
203
+ }
204
+ function moveChoice(prefs, id, delta) {
205
+ const ids = listedEntries(prefs).map((entry) => entry.id);
206
+ const from = ids.indexOf(id);
207
+ const to = from + delta;
208
+ if (from === -1 || to < 0 || to >= ids.length) return prefs;
209
+ const other = ids[to] ?? id;
210
+ return { ...prefs, order: ids.map((candidate, index) => index === from ? other : index === to ? id : candidate) };
211
+ }
212
+ function enableChoice(prefs, id, enabled) {
213
+ if (id === OFFICIAL_PROVIDER_ID) return prefs;
214
+ const hidden = prefs.hidden.includes(id);
215
+ if (enabled) return hidden ? { ...prefs, hidden: prefs.hidden.filter((candidate) => candidate !== id) } : prefs;
216
+ return hidden ? prefs : { ...prefs, hidden: [...prefs.hidden, id] };
217
+ }
218
+ function readPrefs(storage) {
219
+ try {
220
+ return parseCliPrefs(storage.getItem(CLI_PREFS_STORAGE_KEY));
221
+ } catch (_error) {
222
+ return EMPTY;
223
+ }
224
+ }
225
+ function createCliPrefs(storage) {
226
+ let prefs = readPrefs(storage);
227
+ let listeners = [];
228
+ const update = (next) => {
229
+ if (next === prefs) return;
230
+ prefs = next;
231
+ try {
232
+ storage.setItem(CLI_PREFS_STORAGE_KEY, JSON.stringify(prefs));
233
+ } catch (_error) {
234
+ }
235
+ for (const listener of listeners) listener();
236
+ };
237
+ return {
238
+ getSnapshot: () => prefs,
239
+ subscribe(listener) {
240
+ listeners = [...listeners, listener];
241
+ return () => {
242
+ listeners = listeners.filter((candidate) => candidate !== listener);
243
+ };
244
+ },
245
+ remember: (seen) => {
246
+ update(rememberChoices(prefs, seen));
247
+ },
248
+ move: (id, delta) => {
249
+ update(moveChoice(prefs, id, delta));
250
+ },
251
+ setEnabled: (id, enabled) => {
252
+ update(enableChoice(prefs, id, enabled));
253
+ }
254
+ };
255
+ }
256
+
257
+ // src/client/marks.tsx
258
+ var import_react2 = require("react");
259
+
260
+ // src/client/provider-marks.ts
261
+ var OWN_MARKS = /* @__PURE__ */ new Map([
262
+ [cliRoute("opencode"), "opencode"],
263
+ [cliRoute("omp"), "omp"],
264
+ [cliRoute("codex"), "codex"],
265
+ [cliRoute("pi"), "pi"],
266
+ [cliRoute("claude"), "claude"],
267
+ [cliRoute("codebuddy"), "codebuddy"]
268
+ ]);
269
+ function markOf(provider) {
270
+ const own = OWN_MARKS.get(provider);
271
+ if (own !== void 0) return own;
272
+ if (provider.startsWith(CLI_ROUTE_PREFIX)) return "cli";
273
+ return /deepseek/i.test(provider) ? "deepseek" : void 0;
274
+ }
275
+ function providerIn(selection) {
276
+ const provider = selection?.provider;
277
+ return typeof provider === "string" ? provider : void 0;
278
+ }
279
+ function providerOfSession(row) {
280
+ const selection = row?.projectionValues?.modelSelection;
281
+ return providerIn(selection?.next) ?? providerIn(selection?.lastUsed);
282
+ }
283
+
284
+ // src/client/marks.tsx
285
+ var import_jsx_runtime2 = require("react/jsx-runtime");
286
+ var MONOCHROME = {
287
+ codex: [
288
+ "M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 0 0-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 0 1 .476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 0 1 4.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 0 1-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 0 0 5.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0 0 10.205 0a5.947 5.947 0 0 0-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 0 0 4.162 1.713z"
289
+ ],
290
+ pi: ["M1 1h16.5v11H12v5.5H6.5V23H1V1zm5.5 5.5V12H12V6.5H6.5z", "M17.5 12H23v11h-5.5V12z"],
291
+ opencode: ["M16 6H8v12h8V6zm4 16H4V2h16v20z"]
292
+ };
293
+ var DEEPSEEK_PATH = "M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z";
294
+ var DEEPSEEK_COLOR = "#4D6BFE";
295
+ var CLAUDE_PATH = "M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z";
296
+ var CLAUDE_COLOR = "#D97757";
297
+ var OMP_PATH = "M10 14h44v9H43v33h-9V23h-9v22h-9V23H10z";
298
+ var CODEBUDDY_BACKGROUND_PATH = "M18.821 0H5.18A5.179 5.179 0 000 5.179V18.82A5.179 5.179 0 005.179 24H18.82A5.179 5.179 0 0024 18.821V5.18A5.179 5.179 0 0018.821 0z";
299
+ var CODEBUDDY_FACE_PATHS = [
300
+ "M18.777 1.647c.28-.02.536.114.972.51 1.018.926 2.437 2.828 3.318 4.452l.34.631.482.24.11.06v3.638a5.206 5.206 0 00-5.32-1.23c-.491.166-1.021.471-2.08 1.082l-6.09 3.516c-1.057.61-1.586.916-1.975 1.259a5.208 5.208 0 00-1.493 5.572c.165.49.471 1.02 1.082 2.08l.315.543h-3.26c-.685 0-1.34-.135-1.939-.377-.169-.956-.009-1.789.469-2.335.158-.18.164-.189.13-.493a11.846 11.846 0 01-.057-1.711l.02-.444-.667-1.18C2.1 15.622 1.445 14.078 1.192 12.9c-.133-.647-.125-.934.04-1.146.1-.128.427-.261.822-.334.994-.175 3.162-.017 5.575.41l.25.043.551-.487c.915-.81 1.522-1.264 2.641-1.962 1.167-.73 2.484-1.331 3.967-1.807l.476-.152.261-.688c.937-2.471 1.896-4.293 2.58-4.9.235-.21.25-.22.422-.23z",
301
+ "M12.139 18.2a1.203 1.203 0 011.642.44l1.296 2.243a1.204 1.204 0 01-2.083 1.203l-1.296-2.243a1.203 1.203 0 01.44-1.644zM18.629 14.452a1.203 1.203 0 011.642.44l1.295 2.244a1.203 1.203 0 11-2.083 1.203l-1.295-2.243a1.203 1.203 0 01.44-1.644z"
302
+ ];
303
+ var COLORED = {
304
+ deepseek: { path: DEEPSEEK_PATH, color: DEEPSEEK_COLOR },
305
+ claude: { path: CLAUDE_PATH, color: CLAUDE_COLOR }
306
+ };
307
+ function svgProps({ id, size }, viewBox) {
308
+ return {
309
+ width: size,
310
+ height: size,
311
+ viewBox,
312
+ "aria-hidden": true,
313
+ "data-cli-mark": id,
314
+ style: { flex: "none" }
315
+ };
316
+ }
317
+ function OmpMark(props) {
318
+ const gradient = (0, import_react2.useId)().replace(/:/g, "");
319
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...svgProps(props, "0 0 64 64"), children: [
320
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("linearGradient", { id: gradient, x1: "0", y1: "0", x2: "1", y2: "1", children: [
321
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "0", stopColor: "oklch(0.7 0.24 340)" }),
322
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: ".5", stopColor: "oklch(0.62 0.21 295)" }),
323
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "1", stopColor: "oklch(0.81 0.14 200)" })
324
+ ] }) }),
325
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: `url(#${gradient})`, d: OMP_PATH })
326
+ ] });
327
+ }
328
+ function CodeBuddyMark(props) {
329
+ const gradient = (0, import_react2.useId)().replace(/:/g, "");
330
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...svgProps(props, "0 0 24 24"), children: [
331
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
332
+ "radialGradient",
333
+ {
334
+ id: gradient,
335
+ cx: "0",
336
+ cy: "0",
337
+ r: "1",
338
+ gradientUnits: "userSpaceOnUse",
339
+ gradientTransform: "matrix(-9.00009 -16 16 -9.00009 21 24.5)",
340
+ children: [
341
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { stopColor: "#2EA99D" }),
342
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("stop", { offset: "1", stopColor: "#6C4DFF" })
343
+ ]
344
+ }
345
+ ) }),
346
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: `url(#${gradient})`, d: CODEBUDDY_BACKGROUND_PATH }),
347
+ CODEBUDDY_FACE_PATHS.map((path) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: "#fff", d: path }, path))
348
+ ] });
349
+ }
350
+ function ColoredMark(props) {
351
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...svgProps(props, "0 0 24 24"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: props.color, d: props.path }) });
352
+ }
353
+ function MonochromeMark(props) {
354
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...svgProps(props, "0 0 24 24"), fill: "currentColor", fillRule: "evenodd", children: props.paths.map((path) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: path }, path)) });
355
+ }
356
+ function GenericCliMark(props) {
357
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
358
+ "svg",
359
+ {
360
+ ...svgProps(props, "0 0 24 24"),
361
+ fill: "none",
362
+ stroke: "currentColor",
363
+ strokeWidth: "2.2",
364
+ strokeLinecap: "round",
365
+ strokeLinejoin: "round",
366
+ children: [
367
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 7l6 5-6 5" }),
368
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 19h8" })
369
+ ]
370
+ }
371
+ );
372
+ }
373
+ function ProviderMark({
374
+ provider,
375
+ size
376
+ }) {
377
+ const id = markOf(provider);
378
+ if (id === void 0) return null;
379
+ if (id === "omp") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(OmpMark, { id, size });
380
+ if (id === "codebuddy") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CodeBuddyMark, { id, size });
381
+ const colored = COLORED[id];
382
+ if (colored !== void 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ColoredMark, { id, size, ...colored });
383
+ const paths = MONOCHROME[id];
384
+ if (paths !== void 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MonochromeMark, { id, size, paths });
385
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GenericCliMark, { id, size });
386
+ }
387
+
388
+ // src/client/model-menu.tsx
389
+ var import_react5 = require("react");
390
+ var import_react_dom = require("react-dom");
391
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
392
+
393
+ // src/client/model-card.tsx
394
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
395
+
396
+ // src/client/model-menu-styles.ts
397
+ var ROOT_CLASS = "dsh-cli-model";
398
+ var TRIGGER_CLASS = "dsh-cli-model-trigger";
399
+ var ICON_CLASS = "dsh-cli-model-icon";
400
+ var LABEL_CLASS = "dsh-cli-model-label";
401
+ var CHEVRON_CLASS = "dsh-cli-model-chevron";
402
+ var MENU_CLASS = "dsh-cli-model-menu";
403
+ var SEARCH_CLASS = "dsh-cli-model-search";
404
+ var SEARCH_INPUT_CLASS = "dsh-cli-model-search-input";
405
+ var ROWS_CLASS = "dsh-cli-model-rows";
406
+ var ROW_CLASS = "dsh-cli-model-row";
407
+ var ROW_ACTIVE_CLASS = "dsh-cli-model-row-active";
408
+ var ROW_NAME_CLASS = "dsh-cli-model-row-name";
409
+ var ROW_CHECK_CLASS = "dsh-cli-model-row-check";
410
+ var HINT_CLASS = "dsh-cli-model-hint";
411
+ var MODEL_MENU_STYLES = `
412
+ [data-slot="conversation.input.right"]:has(.${ROOT_CLASS}) + [data-slot="conversation.input.model"] { display: none !important; }
413
+ .${ROOT_CLASS} { position: relative; min-width: 0; }
414
+ .${TRIGGER_CLASS} {
415
+ anchor-name: var(--dsh-cli-model-anchor);
416
+ display: flex;
417
+ align-items: center;
418
+ gap: 4px;
419
+ min-width: 0;
420
+ max-width: 360px;
421
+ height: 28px;
422
+ padding: 0 4px 0 8px;
423
+ border: none;
424
+ border-radius: var(--dsw-radius-sm);
425
+ outline: none;
426
+ background: transparent;
427
+ color: var(--dsw-alias-label-secondary);
428
+ font-size: 13px;
429
+ line-height: 20px;
430
+ font-weight: 400;
431
+ cursor: pointer;
432
+ }
433
+ .${TRIGGER_CLASS}:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
434
+ .${TRIGGER_CLASS}:focus-visible:not([data-selection-focus]) {
435
+ box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
436
+ }
437
+ .${TRIGGER_CLASS}:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
438
+ .${ICON_CLASS} { display: var(--dsh-composer-model-icon-display, none); flex: 0 0 auto; }
439
+ .${LABEL_CLASS} {
440
+ display: var(--dsh-composer-model-text-display, block);
441
+ min-width: 0;
442
+ overflow: hidden;
443
+ text-overflow: ellipsis;
444
+ white-space: nowrap;
445
+ }
446
+ .${CHEVRON_CLASS} { flex: 0 0 auto; color: var(--dsw-alias-label-caption); transition: transform 120ms ease; }
447
+ .${TRIGGER_CLASS}[aria-expanded="true"] .${CHEVRON_CLASS} { transform: rotate(180deg); }
448
+ .${MENU_CLASS} {
449
+ box-sizing: border-box;
450
+ position: fixed;
451
+ position-anchor: var(--dsh-cli-model-anchor);
452
+ top: max(12px, var(--dsh-frame-overlay-top, 12px));
453
+ left: 12px;
454
+ right: anchor(right);
455
+ bottom: calc(anchor(top) + 8px);
456
+ align-self: safe end;
457
+ justify-self: safe end;
458
+ margin: 0;
459
+ z-index: 1100;
460
+ display: flex;
461
+ flex-direction: column;
462
+ width: fit-content;
463
+ height: fit-content;
464
+ min-width: min(240px, calc(100vw - 24px));
465
+ max-width: min(420px, calc(100vw - 24px));
466
+ max-height: min(360px, calc(100dvh - 96px));
467
+ overflow: hidden;
468
+ padding: 4px;
469
+ border: 0;
470
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
471
+ box-shadow: var(--dsw-elevation-prominent);
472
+ color: var(--dsw-alias-label-primary);
473
+ --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
474
+ --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
475
+ }
476
+ .${SEARCH_CLASS} { flex-shrink: 0; margin: 2px 0 3px; }
477
+ .${SEARCH_CLASS} .${SEARCH_INPUT_CLASS} {
478
+ display: flex;
479
+ height: auto;
480
+ padding: 5px 7px;
481
+ border: 0 solid transparent;
482
+ border-radius: var(--dsw-radius-md);
483
+ background: transparent;
484
+ }
485
+ .${SEARCH_CLASS} .${SEARCH_INPUT_CLASS}:focus-within { border-color: transparent; }
486
+ .${SEARCH_CLASS} .${SEARCH_INPUT_CLASS} input { padding: 0; font-size: 12px; line-height: normal; }
487
+ .${SEARCH_CLASS} .${SEARCH_INPUT_CLASS} input::placeholder { color: var(--dsw-alias-label-caption); }
488
+ @media (pointer: coarse) {
489
+ .${SEARCH_CLASS} .${SEARCH_INPUT_CLASS} input { font-size: 16px; }
490
+ }
491
+ .${ROWS_CLASS} { min-height: 0; overflow-x: hidden; overflow-y: auto; }
492
+ .${ROW_CLASS} {
493
+ box-sizing: border-box;
494
+ display: flex;
495
+ align-items: center;
496
+ gap: 6px;
497
+ width: 100%;
498
+ min-height: 34px;
499
+ padding: 5px 7px;
500
+ border: none;
501
+ border-radius: var(--dsw-radius-md);
502
+ outline: none;
503
+ background: transparent;
504
+ color: inherit;
505
+ text-align: left;
506
+ cursor: pointer;
507
+ }
508
+ .${ROW_ACTIVE_CLASS}:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
509
+ .${ROW_CLASS}:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; pointer-events: none; }
510
+ .${ROW_NAME_CLASS} {
511
+ flex: 1;
512
+ min-width: 0;
513
+ overflow: hidden;
514
+ font-size: 13px;
515
+ line-height: 18px;
516
+ text-overflow: ellipsis;
517
+ white-space: nowrap;
518
+ }
519
+ .${ROW_CHECK_CLASS} { display: grid; place-items: center; flex: 0 0 14px; color: var(--dsw-alias-label-primary); }
520
+ .${ROW_CHECK_CLASS} svg { width: 14px; height: 14px; }
521
+ .${HINT_CLASS} { padding: 8px; color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 18px; }
522
+ `;
523
+
524
+ // src/client/model-card.tsx
525
+ var import_jsx_runtime3 = require("react/jsx-runtime");
526
+ var SEARCH_ABOVE = 4;
527
+ var MENU_LABEL = "\u6A21\u578B";
528
+ var SEARCH_LABEL = "\u641C\u7D22\u6A21\u578B\u2026";
529
+ var NO_MATCH_LABEL = "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002";
530
+ function ModelRow({ domId, model, selected, settling, active, busy, onHover, onChoose }) {
531
+ const check = selected ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives.IconCheckOutlineRegular, {}) : null;
532
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
533
+ "button",
534
+ {
535
+ type: "button",
536
+ role: "menuitemradio",
537
+ "aria-checked": selected,
538
+ id: domId,
539
+ tabIndex: -1,
540
+ title: model.name,
541
+ className: active ? `${ROW_CLASS} ${ROW_ACTIVE_CLASS}` : ROW_CLASS,
542
+ disabled: busy,
543
+ onMouseMove: active || busy ? void 0 : onHover,
544
+ onClick: onChoose,
545
+ children: [
546
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: ROW_NAME_CLASS, children: model.name }),
547
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: ROW_CHECK_CLASS, children: settling ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives.StateDot, { state: "ongoing" }) : check })
548
+ ]
549
+ }
550
+ );
551
+ }
552
+ function ModelSearch({ id, active, query, busy, searchRef, onQuery }) {
553
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: SEARCH_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
554
+ import_dsh_client_ui_primitives.Input,
555
+ {
556
+ ref: searchRef,
557
+ className: SEARCH_INPUT_CLASS,
558
+ type: "text",
559
+ role: "searchbox",
560
+ "aria-label": SEARCH_LABEL,
561
+ "aria-controls": `${id}-rows`,
562
+ "aria-activedescendant": active < 0 ? void 0 : `${id}-model-${active}`,
563
+ placeholder: SEARCH_LABEL,
564
+ value: query,
565
+ readOnly: busy,
566
+ onChange: (event) => {
567
+ onQuery(event.target.value);
568
+ }
569
+ }
570
+ ) });
571
+ }
572
+ function ModelRows({ id, models, visible, active, pending, onHighlight, onChoose }) {
573
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { id: `${id}-rows`, className: `${ROWS_CLASS} scrollable`, role: "menu", "aria-label": MENU_LABEL, children: visible.map((model, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
574
+ ModelRow,
575
+ {
576
+ domId: `${id}-model-${index}`,
577
+ model,
578
+ selected: model.id === models.currentId,
579
+ settling: pending?.provider === models.provider && pending.model === model.id,
580
+ active: index === active,
581
+ busy: pending !== null,
582
+ onHover: () => {
583
+ onHighlight(index);
584
+ },
585
+ onChoose: () => {
586
+ onChoose(model.id);
587
+ }
588
+ },
589
+ model.id
590
+ )) });
591
+ }
592
+ function ModelCard(props) {
593
+ const {
594
+ id,
595
+ models,
596
+ visible,
597
+ active,
598
+ pending,
599
+ query,
600
+ anchorStyle,
601
+ cardRef,
602
+ searchRef,
603
+ onQuery,
604
+ onHighlight,
605
+ onChoose
606
+ } = props;
607
+ const busy = pending !== null;
608
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
609
+ import_dsh_client_ui_primitives.MenuSurface,
610
+ {
611
+ ref: cardRef,
612
+ id: `${id}-menu`,
613
+ className: MENU_CLASS,
614
+ style: anchorStyle,
615
+ role: "group",
616
+ "aria-label": models.name,
617
+ children: [
618
+ models.rows.length > SEARCH_ABOVE && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModelSearch, { id, active, query, busy, searchRef, onQuery }),
619
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModelRows, { ...{ id, models, visible, active, pending, onHighlight, onChoose } }),
620
+ visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: HINT_CLASS, role: "status", children: NO_MATCH_LABEL }),
621
+ !models.listed && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: HINT_CLASS, role: "status", children: `\u8FD8\u6CA1\u6709\u8BFB\u5230 ${models.name} \u7684\u6A21\u578B\u5217\u8868` })
622
+ ]
623
+ }
624
+ );
625
+ }
626
+
627
+ // src/client/model-seat.ts
628
+ var import_react3 = require("react");
629
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
630
+ var UNKNOWN_ERROR_LABEL = "\u672A\u77E5\u9519\u8BEF";
631
+ function keyAction({ key, shiftKey }) {
632
+ if (key === "Escape" || key === "Tab" && shiftKey) return "close";
633
+ if (key === "Enter" || key === "Tab") return "choose";
634
+ if (key === "ArrowDown") return 1;
635
+ return key === "ArrowUp" ? -1 : void 0;
636
+ }
637
+ function useCloseOnOutsidePress(open, inside, close) {
638
+ (0, import_react3.useEffect)(() => {
639
+ if (!open) return void 0;
640
+ const onPress = (event) => {
641
+ if (!inside.some((ref) => ref.current?.contains(event.target) === true)) close();
642
+ };
643
+ document.addEventListener("mousedown", onPress);
644
+ return () => {
645
+ document.removeEventListener("mousedown", onPress);
646
+ };
647
+ }, [open]);
648
+ }
649
+ function useMatchingRows(models, query, highlight) {
650
+ const searchable = models.rows.length > SEARCH_ABOVE;
651
+ const visible = (0, import_react3.useMemo)(
652
+ () => (0, import_dsh_client_ui_primitives2.rankByName)(models.rows, searchable ? query.trim() : ""),
653
+ [models.rows, searchable, query]
654
+ );
655
+ const currentIndex = visible.findIndex((model) => model.id === models.currentId);
656
+ const active = Math.min(highlight ?? Math.max(0, currentIndex), visible.length - 1);
657
+ return { searchable, visible, active };
658
+ }
659
+ function useMenuFocus(open, searchable, activeRowId, searchRef) {
660
+ (0, import_react3.useEffect)(() => {
661
+ if (open && searchable && !(0, import_dsh_client_ui_primitives2.isMobileDevice)()) searchRef.current?.focus();
662
+ }, [open, searchable, searchRef]);
663
+ (0, import_react3.useLayoutEffect)(() => {
664
+ if (open) document.getElementById(activeRowId)?.scrollIntoView({ block: "nearest" });
665
+ }, [open, activeRowId]);
666
+ }
667
+ function useCompositionGuard() {
668
+ const composition = (0, import_react3.useRef)();
669
+ (0, import_react3.useEffect)(() => {
670
+ const observed = (0, import_dsh_client_ui_primitives2.observeComposition)(document);
671
+ composition.current = observed;
672
+ return () => {
673
+ observed.dispose();
674
+ };
675
+ }, []);
676
+ return (event) => composition.current?.guards(event) ?? false;
677
+ }
678
+ function useChooseModel({ models, select, triggerRef, searchRef, closings, close }) {
679
+ const [failure, setFailure] = (0, import_react3.useState)();
680
+ const [settled, setSettled] = (0, import_react3.useState)(false);
681
+ const fail = (text) => {
682
+ setFailure((previous) => ({ seq: (previous?.seq ?? 0) + 1, text }));
683
+ if (!(0, import_dsh_client_ui_primitives2.isMobileDevice)()) searchRef.current?.focus();
684
+ };
685
+ const choose = (modelId) => {
686
+ setSettled(true);
687
+ if (modelId === models.currentId) {
688
+ close(true);
689
+ return;
690
+ }
691
+ const asked = closings.current;
692
+ triggerRef.current?.focus();
693
+ select({ provider: models.provider, model: modelId }).then(
694
+ (result) => {
695
+ if (result.error !== void 0) fail(result.error.message ?? UNKNOWN_ERROR_LABEL);
696
+ else if (closings.current === asked) close(true);
697
+ },
698
+ (reason) => {
699
+ fail(String(reason));
700
+ }
701
+ );
702
+ };
703
+ return {
704
+ failure,
705
+ clearFailure: () => {
706
+ setFailure(void 0);
707
+ },
708
+ settled,
709
+ setSettled,
710
+ choose
711
+ };
712
+ }
713
+ function closeOnBlurOutside(inside, close) {
714
+ return ({ relatedTarget }) => {
715
+ const staysInside = relatedTarget instanceof Node && inside.some((ref) => ref.current?.contains(relatedTarget) === true);
716
+ if (!staysInside) close();
717
+ };
718
+ }
719
+ function useMenuState(triggerRef) {
720
+ const [open, setOpen] = (0, import_react3.useState)(false);
721
+ const [query, setQuery] = (0, import_react3.useState)("");
722
+ const [highlight, setHighlight] = (0, import_react3.useState)(null);
723
+ const closings = (0, import_react3.useRef)(0);
724
+ const close = (restoreFocus = false) => {
725
+ closings.current += 1;
726
+ setOpen(false);
727
+ setQuery("");
728
+ setHighlight(null);
729
+ if (restoreFocus)
730
+ queueMicrotask(() => {
731
+ triggerRef.current?.focus();
732
+ });
733
+ };
734
+ return { open, setOpen, query, setQuery, highlight, setHighlight, closings, close };
735
+ }
736
+ function useSeatRefs() {
737
+ return {
738
+ rootRef: (0, import_react3.useRef)(null),
739
+ triggerRef: (0, import_react3.useRef)(null),
740
+ cardRef: (0, import_react3.useRef)(null),
741
+ searchRef: (0, import_react3.useRef)(null)
742
+ };
743
+ }
744
+ function useModelSeat({ models, pending, locked, load, select }) {
745
+ const refs = useSeatRefs();
746
+ const { rootRef, triggerRef, cardRef, searchRef } = refs;
747
+ const { open, setOpen, query, setQuery, highlight, setHighlight, closings, close } = useMenuState(triggerRef);
748
+ const id = (0, import_react3.useId)();
749
+ const showing = open && !locked;
750
+ const { searchable, visible, active } = useMatchingRows(models, query, highlight);
751
+ const composing = useCompositionGuard();
752
+ const choosing = useChooseModel({ models, select, triggerRef, searchRef, closings, close });
753
+ useCloseOnOutsidePress(showing, [rootRef, cardRef], close);
754
+ useMenuFocus(showing, searchable, `${id}-model-${active}`, searchRef);
755
+ const onKeyDown = (event) => {
756
+ if (!showing || composing(event.nativeEvent)) return;
757
+ const action = keyAction(event);
758
+ if (action === void 0) return;
759
+ event.preventDefault();
760
+ if (action === "close") close(true);
761
+ else if (pending !== null || visible.length === 0) return;
762
+ else if (action === "choose") choosing.choose(visible[active]?.id ?? "");
763
+ else setHighlight((active + action + visible.length) % visible.length);
764
+ };
765
+ const onBlur = closeOnBlurOutside([rootRef, cardRef], () => {
766
+ close();
767
+ });
768
+ const toggle = () => {
769
+ if (open) {
770
+ close(true);
771
+ return;
772
+ }
773
+ choosing.setSettled(false);
774
+ triggerRef.current?.focus();
775
+ setOpen(true);
776
+ load();
777
+ };
778
+ return {
779
+ id,
780
+ showing,
781
+ query,
782
+ setQuery,
783
+ setHighlight,
784
+ visible,
785
+ active,
786
+ ...refs,
787
+ onKeyDown,
788
+ onBlur,
789
+ toggle,
790
+ ...choosing
791
+ };
792
+ }
793
+
794
+ // src/client/store.ts
795
+ var import_react4 = require("react");
796
+ function useStore(store) {
797
+ return (0, import_react4.useSyncExternalStore)(
798
+ (listener) => store.subscribe(listener),
799
+ () => store.getSnapshot()
800
+ );
801
+ }
802
+
803
+ // src/client/model-menu.tsx
804
+ var import_jsx_runtime4 = require("react/jsx-runtime");
805
+ var NO_MODEL_LABEL = "\u8BF7\u9009\u62E9\u6A21\u578B";
806
+ function keepFocus(event) {
807
+ if (!(event.target instanceof HTMLInputElement)) event.preventDefault();
808
+ }
809
+ function ModelTrigger({ seat, models, pending, locked, label, anchorStyle }) {
810
+ const { id, showing } = seat;
811
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
812
+ "button",
813
+ {
814
+ ref: seat.triggerRef,
815
+ type: "button",
816
+ className: TRIGGER_CLASS,
817
+ style: anchorStyle,
818
+ "aria-label": models.currentName === void 0 ? NO_MODEL_LABEL : `\u9009\u62E9\u6A21\u578B\uFF0C\u5F53\u524D ${label}`,
819
+ "aria-haspopup": "menu",
820
+ "aria-expanded": showing,
821
+ "aria-controls": showing ? `${id}-menu` : void 0,
822
+ "aria-busy": pending !== null,
823
+ title: label,
824
+ "data-selection-focus": seat.settled ? "" : void 0,
825
+ disabled: locked,
826
+ onBlur: () => {
827
+ seat.setSettled(false);
828
+ },
829
+ onClick: seat.toggle,
830
+ children: [
831
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.IconDataOutlineRegular, { className: ICON_CLASS, size: 16 }),
832
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: LABEL_CLASS, children: label }),
833
+ pending === null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.IconChevronDownOutlineRegular, { className: CHEVRON_CLASS, size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "ongoing" })
834
+ ]
835
+ }
836
+ );
837
+ }
838
+ function ModelSeat(props) {
839
+ const { models, pending, locked } = props;
840
+ const seat = useModelSeat(props);
841
+ const { id, showing, rootRef } = seat;
842
+ const anchorStyle = { "--dsh-cli-model-anchor": `--dsh-cli-model-${id.replaceAll(":", "")}` };
843
+ const label = models.currentName ?? NO_MODEL_LABEL;
844
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { ref: rootRef, className: ROOT_CLASS, onKeyDown: seat.onKeyDown, onBlur: seat.onBlur, onMouseDown: keepFocus, children: [
845
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
846
+ ModelTrigger,
847
+ {
848
+ seat,
849
+ models,
850
+ pending,
851
+ locked,
852
+ label,
853
+ anchorStyle
854
+ }
855
+ ),
856
+ showing && (0, import_react_dom.createPortal)(
857
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
858
+ ModelCard,
859
+ {
860
+ id,
861
+ models,
862
+ visible: seat.visible,
863
+ active: seat.active,
864
+ pending,
865
+ query: seat.query,
866
+ anchorStyle,
867
+ cardRef: seat.cardRef,
868
+ searchRef: seat.searchRef,
869
+ onQuery: (next) => {
870
+ seat.setQuery(next);
871
+ seat.setHighlight(0);
872
+ },
873
+ onHighlight: seat.setHighlight,
874
+ onChoose: seat.choose
875
+ }
876
+ ),
877
+ document.body
878
+ ),
879
+ seat.failure !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
880
+ import_dsh_client_ui_primitives3.Toast,
881
+ {
882
+ text: `\u5207\u6362\u6A21\u578B\u5931\u8D25\uFF1A${seat.failure.text}`,
883
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.IconWarningOutlineRegular, {}),
884
+ anchor: rootRef.current?.closest("[data-composer-card]") ?? null,
885
+ onDone: seat.clearFailure
886
+ },
887
+ seat.failure.seq
888
+ )
889
+ ] });
890
+ }
891
+ function useRemoved(session) {
892
+ return (0, import_react5.useSyncExternalStore)(
893
+ (listener) => session?.subscribe(listener) ?? (() => {
894
+ }),
895
+ () => session?.getSnapshot().removed === true
896
+ );
897
+ }
898
+ function CliModelMenu({ available, directory, load, select, session }) {
899
+ const state = useStore(directory);
900
+ const locked = useRemoved(session);
901
+ const models = available ? cliModels(state) : void 0;
902
+ if (models === void 0) return null;
903
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ModelSeat, { models, pending: state.pending ?? null, locked, load, select });
904
+ }
905
+
906
+ // src/client/session-status-mark.tsx
907
+ var import_react6 = require("react");
908
+ var import_react_dom2 = require("react-dom");
909
+ var import_jsx_runtime5 = require("react/jsx-runtime");
910
+ var SESSION_STATUS_SLOT = "sidebar.session.row.trailing";
911
+ var SESSION_STATUS_MARK_CLASS = "dsh-cli-status-mark";
912
+ var ROW = '[data-row-key^="session:"]';
913
+ var LEADING_CELL = ':scope > [class*="_slot"]';
914
+ var MARK_SIZE = 14;
915
+ var STREAMING_COLOR = "#2f80ed";
916
+ var DOT_SIZE = "6px";
917
+ var MARK_GAP = "6px";
918
+ var HEARTBEAT = "dsh-cli-status-heartbeat";
919
+ var HEARTBEAT_PERIOD = "0.92s";
920
+ function useSessionProvider(list, sessionId) {
921
+ const subscribe = (0, import_react6.useCallback)((listener) => list.subscribe(listener), [list]);
922
+ return (0, import_react6.useSyncExternalStore)(subscribe, () => providerOfSession(list.getSnapshot().byId[sessionId]));
923
+ }
924
+ function leadingCellOf(anchor) {
925
+ return anchor?.closest(ROW)?.querySelector(LEADING_CELL) ?? null;
926
+ }
927
+ function SessionStatusMark({
928
+ sessionId,
929
+ list
930
+ }) {
931
+ const provider = useSessionProvider(list, sessionId);
932
+ const [cell, setCell] = (0, import_react6.useState)(null);
933
+ const anchor = (0, import_react6.useCallback)((node) => {
934
+ setCell(leadingCellOf(node));
935
+ }, []);
936
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { ref: anchor, hidden: true }),
938
+ cell === null || provider === void 0 ? null : (0, import_react_dom2.createPortal)(
939
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: SESSION_STATUS_MARK_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ProviderMark, { provider, size: MARK_SIZE }) }),
940
+ cell
941
+ )
942
+ ] });
943
+ }
944
+ var CELL = `${ROW} > :has(> .${SESSION_STATUS_MARK_CLASS})`;
945
+ var STATUS_CELL = `${CELL}:has(> [data-state])`;
946
+ var SESSION_STATUS_STYLES = `
947
+ .${SESSION_STATUS_MARK_CLASS} { display: none; order: -1; color: var(--dsw-alias-label-secondary); }
948
+ ${STATUS_CELL} { width: auto; gap: ${MARK_GAP}; }
949
+ ${STATUS_CELL} > .${SESSION_STATUS_MARK_CLASS} { display: inline-flex; }
950
+ ${STATUS_CELL} > [data-state] { width: ${DOT_SIZE} !important; height: ${DOT_SIZE} !important; }
951
+ ${STATUS_CELL} > svg[data-state="ongoing"] {
952
+ border-radius: 50%;
953
+ background: ${STREAMING_COLOR};
954
+ box-shadow: 0 0 0 4px color-mix(in srgb, ${STREAMING_COLOR} 18%, transparent);
955
+ overflow: visible;
956
+ animation: ${HEARTBEAT} ${HEARTBEAT_PERIOD} ease-in-out infinite;
957
+ }
958
+ ${STATUS_CELL} > svg[data-state="ongoing"] > * { display: none; }
959
+ @keyframes ${HEARTBEAT} {
960
+ 0%, 100% { transform: scale(1); opacity: 1; }
961
+ 50% { transform: scale(1.35); opacity: 0.65; }
962
+ }
963
+ @media (prefers-reduced-motion: reduce) {
964
+ ${STATUS_CELL} > svg[data-state="ongoing"] { animation: none; }
965
+ }
966
+ `;
967
+
968
+ // src/client/terminal-entry.tsx
969
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
970
+ var import_jsx_runtime6 = require("react/jsx-runtime");
971
+ var TERMINAL_KIND = "terminal";
972
+ var SLOT = "conversation.session.header.utilities";
973
+ var ENTRY_ORDER = -1;
974
+ var ENTRY_CLASS = "dsh-cli-terminal-entry";
975
+ var TOOLTIP_LABEL = "\u7EC8\u7AEF";
976
+ var ARIA_LABEL = "\u5207\u6362\u7EC8\u7AEF";
977
+ var TOOLTIP_DELAY_MS = 500;
978
+ var TERMINAL_ENTRY_STYLES = `
979
+ .${ENTRY_CLASS} { flex: none; width: 28px; padding: 0; color: var(--dsw-alias-label-secondary); }
980
+ .${ENTRY_CLASS} svg { width: 15px; height: 15px; }
981
+ `;
982
+ function toggleTerminal(sidebar, sessionId) {
983
+ const expanded = sidebar.isExpanded();
984
+ if (expanded && sidebar.active()?.kind === TERMINAL_KIND) {
985
+ sidebar.toggleExpanded();
986
+ return;
987
+ }
988
+ const existing = sidebar.tabsIn(sessionId).find((tab) => tab.kind === TERMINAL_KIND);
989
+ if (existing === void 0) {
990
+ sidebar.openTab(TERMINAL_KIND);
991
+ return;
992
+ }
993
+ sidebar.focus(existing.id);
994
+ if (!expanded) sidebar.toggleExpanded();
995
+ }
996
+ function TerminalGlyph() {
997
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: [
998
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3 4L7 8L3 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }),
999
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M9 12H13", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" })
1000
+ ] });
1001
+ }
1002
+ function TerminalEntry({ sessionId, sidebar }) {
1003
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: TOOLTIP_LABEL, side: "bottom", delayMs: TOOLTIP_DELAY_MS, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1004
+ import_dsh_client_ui_primitives4.Button,
1005
+ {
1006
+ size: "sm",
1007
+ className: ENTRY_CLASS,
1008
+ "aria-label": ARIA_LABEL,
1009
+ onClick: () => {
1010
+ toggleTerminal(sidebar, sessionId);
1011
+ },
1012
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TerminalGlyph, {})
1013
+ }
1014
+ ) });
1015
+ }
1016
+ function registerTerminalEntry(ctx) {
1017
+ ctx.inject(["sidebarRight"], (child) => {
1018
+ child.slots.inject(
1019
+ SLOT,
1020
+ () => child.slots.register(
1021
+ {
1022
+ name: SLOT,
1023
+ id: "dsh-ccgui.terminal-entry",
1024
+ order: ENTRY_ORDER,
1025
+ inject: () => ({ sidebar: child.sidebarRight })
1026
+ },
1027
+ TerminalEntry
1028
+ )
1029
+ );
1030
+ });
1031
+ }
1032
+
1033
+ // src/client/changes/changes-kind.ts
1034
+ var CHANGES_KIND = "ccgui-changes";
1035
+
1036
+ // src/client/files-default.ts
1037
+ var GUIDE_KIND = "guide";
1038
+ var FILES_KIND = "files";
1039
+ function replaceSoleGuide(sidebar, kinds) {
1040
+ const sessionId = sidebar.mounted.getSnapshot();
1041
+ if (sessionId === void 0 || !sidebar.isExpanded()) return;
1042
+ const [only, ...others] = sidebar.tabsIn(sessionId);
1043
+ if (only?.kind !== GUIDE_KIND || others.length > 0) return;
1044
+ if (kinds.get(FILES_KIND) === void 0) return;
1045
+ sidebar.openTab(FILES_KIND, { replaceTab: only.id });
1046
+ if (kinds.get(CHANGES_KIND) === void 0) return;
1047
+ sidebar.openTab(CHANGES_KIND);
1048
+ const files = sidebar.tabsIn(sessionId).find((tab) => tab.kind === FILES_KIND);
1049
+ if (files !== void 0) sidebar.focus(files.id);
1050
+ }
1051
+ function registerFilesDefault(ctx) {
1052
+ ctx.inject(["sidebarRight", "sidebarRightTabs"], (child) => {
1053
+ const check = () => {
1054
+ queueMicrotask(() => {
1055
+ replaceSoleGuide(child.sidebarRight, child.sidebarRightTabs);
1056
+ });
1057
+ };
1058
+ child.effect(() => child.sidebarRight.openTabs.subscribe(check), "ccgui: files by default (tabs)");
1059
+ child.effect(() => child.sidebarRight.mounted.subscribe(check), "ccgui: files by default (session)");
1060
+ });
1061
+ }
1062
+
1063
+ // src/client/changes/changes-panel.tsx
1064
+ var import_react11 = require("react");
1065
+ var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
1066
+
1067
+ // src/client/changes/changes-api.ts
1068
+ var NETWORK_FAILED = "\u65E0\u6CD5\u8FDE\u63A5\u5230 DSH \u670D\u52A1";
1069
+ async function answerOf(response) {
1070
+ try {
1071
+ const body = await response.json();
1072
+ return typeof body === "object" && body !== null ? body : {};
1073
+ } catch (_error) {
1074
+ return {};
1075
+ }
1076
+ }
1077
+ function createGitApi(fetchFn, cwd) {
1078
+ const post = async (operation, body = {}) => {
1079
+ let response;
1080
+ try {
1081
+ response = await fetchFn(`${GIT_ROUTE_PREFIX}/${operation}`, {
1082
+ method: "POST",
1083
+ headers: { "content-type": "application/json" },
1084
+ credentials: "same-origin",
1085
+ body: JSON.stringify({ ...body, cwd })
1086
+ });
1087
+ } catch (error) {
1088
+ throw new Error(NETWORK_FAILED, { cause: error });
1089
+ }
1090
+ const answer = await answerOf(response);
1091
+ if (!response.ok || answer.success !== true) {
1092
+ throw new Error(typeof answer.error === "string" ? answer.error : `\u8BF7\u6C42\u5931\u8D25\uFF08${String(response.status)}\uFF09`);
1093
+ }
1094
+ return answer.data;
1095
+ };
1096
+ return {
1097
+ status: () => post("status"),
1098
+ branches: () => post("branches"),
1099
+ diff: (target) => post("diff", target),
1100
+ stage: (paths) => post("stage", { paths }),
1101
+ unstage: (paths) => post("unstage", { paths }),
1102
+ discard: (target) => post("discard", target),
1103
+ commit: (change) => post("commit", change),
1104
+ push: () => post("push"),
1105
+ pull: () => post("pull"),
1106
+ checkout: (branch) => post("checkout", branch),
1107
+ createBranch: (branch) => post("create-branch", { branch })
1108
+ };
1109
+ }
1110
+
1111
+ // src/client/changes/changes-diff.tsx
1112
+ var import_react7 = require("react");
1113
+
1114
+ // src/client/changes/changes-icons.tsx
1115
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1116
+ var DEFAULT_SIZE = 16;
1117
+ function Stroke({
1118
+ size = DEFAULT_SIZE,
1119
+ className,
1120
+ children
1121
+ }) {
1122
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1123
+ "svg",
1124
+ {
1125
+ width: size,
1126
+ height: size,
1127
+ viewBox: "0 0 24 24",
1128
+ fill: "none",
1129
+ stroke: "currentColor",
1130
+ strokeWidth: 2,
1131
+ strokeLinecap: "round",
1132
+ strokeLinejoin: "round",
1133
+ className,
1134
+ "aria-hidden": "true",
1135
+ children
1136
+ }
1137
+ );
1138
+ }
1139
+ function BranchIcon(props) {
1140
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1141
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "6", cy: "5", r: "2" }),
1142
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "6", cy: "19", r: "2" }),
1143
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "18", cy: "7", r: "2" }),
1144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M6 7v10M18 9c0 5-6 4-11.4 8.6" })
1145
+ ] });
1146
+ }
1147
+ function RefreshIcon(props) {
1148
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1149
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M20 11a8 8 0 0 0-14.3-4.9L4 8" }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 4v4h4" }),
1151
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 13a8 8 0 0 0 14.3 4.9L20 16" }),
1152
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M20 20v-4h-4" })
1153
+ ] });
1154
+ }
1155
+ function Cloud({ arrow, ...props }) {
1156
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1157
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M7 18a4.5 4.5 0 0 1-.6-9A6 6 0 0 1 18 9.5a4 4 0 0 1 0 8.5" }),
1158
+ arrow
1159
+ ] });
1160
+ }
1161
+ function PullIcon(props) {
1162
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Cloud, { ...props, arrow: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 12v9M9 18l3 3 3-3" }) });
1163
+ }
1164
+ function PushIcon(props) {
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Cloud, { ...props, arrow: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 21v-9M9 15l3-3 3 3" }) });
1166
+ }
1167
+ function ChevronIcon(props) {
1168
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Stroke, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M6 9l6 6 6-6" }) });
1169
+ }
1170
+ function UndoIcon(props) {
1171
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1172
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M9 14L4 9l5-5" }),
1173
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 9h10.5a5.5 5.5 0 0 1 0 11H11" })
1174
+ ] });
1175
+ }
1176
+ function PlusIcon2(props) {
1177
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Stroke, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 5v14M5 12h14" }) });
1178
+ }
1179
+ function MinusIcon(props) {
1180
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Stroke, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M5 12h14" }) });
1181
+ }
1182
+ function BackIcon(props) {
1183
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Stroke, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M19 12H5M11 18l-6-6 6-6" }) });
1184
+ }
1185
+ function ChangesIcon(props) {
1186
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1187
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" }),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M12 8v6M9 11h6M9 17h6" })
1189
+ ] });
1190
+ }
1191
+ function SparkleIcon(props) {
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Stroke, { ...props, children: [
1193
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M10 4l1.6 4.4L16 10l-4.4 1.6L10 16l-1.6-4.4L4 10l4.4-1.6z" }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M17.5 14l.8 2.2 2.2.8-2.2.8-.8 2.2-.8-2.2-2.2-.8 2.2-.8z" })
1195
+ ] });
1196
+ }
1197
+
1198
+ // src/client/changes/diff-rows.ts
1199
+ var MAX_DIFF_ROWS = 2e3;
1200
+ var HUNK = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
1201
+ function rowOf(line, cursor) {
1202
+ const hunk = HUNK.exec(line);
1203
+ if (hunk !== null) {
1204
+ return {
1205
+ row: { kind: "hunk", text: line },
1206
+ next: { oldLine: Number(hunk[1]), newLine: Number(hunk[2]), inHunk: true }
1207
+ };
1208
+ }
1209
+ if (!cursor.inHunk) {
1210
+ const row = line.startsWith("Binary files") ? { kind: "note", text: "\u4E8C\u8FDB\u5236\u6587\u4EF6\uFF0C\u65E0\u6CD5\u663E\u793A\u5DEE\u5F02" } : void 0;
1211
+ return { row, next: cursor };
1212
+ }
1213
+ const text = line.slice(1);
1214
+ if (line.startsWith("+")) {
1215
+ return { row: { kind: "add", newLine: cursor.newLine, text }, next: { ...cursor, newLine: cursor.newLine + 1 } };
1216
+ }
1217
+ if (line.startsWith("-")) {
1218
+ return { row: { kind: "del", oldLine: cursor.oldLine, text }, next: { ...cursor, oldLine: cursor.oldLine + 1 } };
1219
+ }
1220
+ if (line.startsWith("\\")) return { row: { kind: "note", text: line.slice(2) }, next: cursor };
1221
+ if (line.startsWith("diff --git")) return { row: void 0, next: { ...cursor, inHunk: false } };
1222
+ return {
1223
+ row: { kind: "context", oldLine: cursor.oldLine, newLine: cursor.newLine, text },
1224
+ next: { ...cursor, oldLine: cursor.oldLine + 1, newLine: cursor.newLine + 1 }
1225
+ };
1226
+ }
1227
+ function diffRows(patch, maxRows = MAX_DIFF_ROWS) {
1228
+ const lines = patch.endsWith("\n") ? patch.slice(0, -1).split("\n") : patch.split("\n");
1229
+ const rows = [];
1230
+ let cursor = { oldLine: 0, newLine: 0, inHunk: false };
1231
+ for (const line of lines) {
1232
+ if (line === "" && !cursor.inHunk) continue;
1233
+ const { row, next } = rowOf(line, cursor);
1234
+ cursor = next;
1235
+ if (row === void 0) continue;
1236
+ if (rows.length >= maxRows) return { rows, truncated: true };
1237
+ rows.push(row);
1238
+ }
1239
+ return { rows, truncated: false };
1240
+ }
1241
+
1242
+ // src/client/changes/changes-styles.ts
1243
+ var P = "dsh-ccgui-changes";
1244
+ var CLS = {
1245
+ panel: P,
1246
+ header: `${P}-header`,
1247
+ headerRow: `${P}-header-row`,
1248
+ title: `${P}-title`,
1249
+ distance: `${P}-distance`,
1250
+ headerButtons: `${P}-header-buttons`,
1251
+ headerButton: `${P}-header-button`,
1252
+ spinning: `${P}-spinning`,
1253
+ branchMenu: `${P}-branch-menu`,
1254
+ branchButton: `${P}-branch-button`,
1255
+ branchName: `${P}-branch-name`,
1256
+ branchForm: `${P}-branch-form`,
1257
+ branchInput: `${P}-branch-input`,
1258
+ remoteItem: `${P}-remote-item`,
1259
+ remoteTag: `${P}-remote-tag`,
1260
+ summary: `${P}-summary`,
1261
+ summaryTitle: `${P}-summary-title`,
1262
+ summarySelected: `${P}-summary-selected`,
1263
+ scroll: `${P}-scroll`,
1264
+ list: `${P}-list`,
1265
+ group: `${P}-group`,
1266
+ groupHeader: `${P}-group-header`,
1267
+ groupTitle: `${P}-group-title`,
1268
+ groupCount: `${P}-group-count`,
1269
+ groupActions: `${P}-group-actions`,
1270
+ groupAction: `${P}-group-action`,
1271
+ danger: `${P}-danger`,
1272
+ collapsed: `${P}-collapsed`,
1273
+ row: `${P}-row`,
1274
+ checkbox: `${P}-checkbox`,
1275
+ letter: `${P}-letter`,
1276
+ badge: `${P}-badge`,
1277
+ path: `${P}-path`,
1278
+ dir: `${P}-dir`,
1279
+ name: `${P}-name`,
1280
+ stats: `${P}-stats`,
1281
+ add: `${P}-add`,
1282
+ del: `${P}-del`,
1283
+ rowActions: `${P}-row-actions`,
1284
+ iconButton: `${P}-icon-button`,
1285
+ empty: `${P}-empty`,
1286
+ error: `${P}-error`,
1287
+ commit: `${P}-commit`,
1288
+ commitInput: `${P}-commit-input`,
1289
+ commitRow: `${P}-commit-row`,
1290
+ commitButton: `${P}-commit-button`,
1291
+ aiButton: `${P}-ai-button`,
1292
+ diff: `${P}-diff`,
1293
+ diffHeader: `${P}-diff-header`,
1294
+ diffPath: `${P}-diff-path`,
1295
+ diffSide: `${P}-diff-side`,
1296
+ diffBody: `${P}-diff-body`,
1297
+ diffHunk: `${P}-diff-hunk`,
1298
+ diffNote: `${P}-diff-note`,
1299
+ diffLine: `${P}-diff-line`,
1300
+ diffNumber: `${P}-diff-number`,
1301
+ diffText: `${P}-diff-text`
1302
+ };
1303
+ var DARK = "body[data-ds-dark-theme]";
1304
+ var LAYOUT = `
1305
+ .${CLS.panel} { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow: hidden;
1306
+ color: var(--dsw-alias-label-primary); font-size: 14px; }
1307
+ .${CLS.header} { display: flex; flex-direction: column; gap: 10px; padding: 10px 12px;
1308
+ border-bottom: 1px solid var(--dsw-alias-border-l2); }
1309
+ .${CLS.headerRow} { display: flex; align-items: center; gap: 8px; }
1310
+ .${CLS.title} { font-weight: 500; }
1311
+ .${CLS.distance} { font-size: 12px; color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; }
1312
+ .${CLS.headerButtons} { margin-left: auto; display: flex; gap: 6px; }
1313
+ .${CLS.headerButton}, .${CLS.branchButton} { display: inline-flex; align-items: center; justify-content: center;
1314
+ border: 1px solid var(--dsw-alias-border-l2); border-radius: var(--dsw-radius-md); background: transparent;
1315
+ color: var(--dsw-alias-label-secondary); cursor: pointer; }
1316
+ .${CLS.headerButton} { width: 30px; height: 30px; padding: 0; }
1317
+ .${CLS.headerButton}:hover:not(:disabled), .${CLS.branchButton}:hover:not(:disabled),
1318
+ .${CLS.iconButton}:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
1319
+ .${CLS.headerButton}:disabled, .${CLS.branchButton}:disabled { cursor: default; opacity: 0.5; }
1320
+ .${CLS.spinning} { animation: ${P}-spin 0.8s linear infinite; }
1321
+ @keyframes ${P}-spin { to { transform: rotate(360deg); } }
1322
+ .${CLS.branchMenu} { display: block; }
1323
+ .${CLS.branchButton} { width: 100%; height: 32px; gap: 8px; padding: 0 10px; justify-content: flex-start; }
1324
+ .${CLS.branchName} { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1325
+ text-align: left; color: var(--dsw-alias-label-primary); }
1326
+ .${CLS.branchForm} { display: flex; gap: 6px; }
1327
+ .${CLS.branchInput} { flex: 1; min-width: 0; height: 30px; padding: 0 8px; border-radius: var(--dsw-radius-md);
1328
+ border: 1px solid var(--dsw-alias-border-l3); background: transparent; color: inherit; font: inherit; font-size: 13px; }
1329
+ .${CLS.remoteItem} { display: inline-flex; gap: 6px; align-items: baseline; }
1330
+ .${CLS.remoteTag} { font-size: 11px; color: var(--dsw-alias-label-tertiary); }
1331
+ .${CLS.summary} { display: flex; align-items: baseline; gap: 6px; padding: 8px 12px; }
1332
+ .${CLS.summaryTitle} { font-weight: 500; }
1333
+ .${CLS.summarySelected} { margin-left: auto; font-size: 13px; color: var(--dsw-alias-label-tertiary); }
1334
+ .${CLS.scroll} { flex: 1; min-height: 0; overflow-y: auto; }
1335
+ .${CLS.groupHeader} { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: 6px;
1336
+ padding: 6px 12px 6px 8px; background: var(--dsw-alias-bg-layer-2); cursor: pointer; user-select: none; }
1337
+ .${CLS.groupTitle} { font-weight: 500; }
1338
+ .${CLS.groupCount} { font-size: 12px; color: var(--dsw-alias-label-tertiary); }
1339
+ .${CLS.groupActions} { margin-left: auto; display: flex; gap: 8px; }
1340
+ .${CLS.groupAction} { border: none; background: transparent; padding: 2px 4px; border-radius: var(--dsw-radius-sm);
1341
+ font-size: 12px; color: var(--dsw-alias-label-secondary); cursor: pointer; }
1342
+ .${CLS.groupAction}:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
1343
+ .${CLS.groupAction}:disabled { cursor: default; opacity: 0.5; }
1344
+ .${CLS.danger} { color: var(--dsw-alias-state-error-primary); }
1345
+ .${CLS.iconButton} { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px;
1346
+ padding: 0; border: none; border-radius: var(--dsw-radius-sm); background: transparent;
1347
+ color: var(--dsw-alias-label-secondary); cursor: pointer; }
1348
+ .${CLS.collapsed} { transform: rotate(-90deg); }
1349
+ .${CLS.checkbox} { width: 14px; height: 14px; margin: 0; flex: none; accent-color: var(--dsw-alias-state-business-primary); }
1350
+ .${CLS.empty} { padding: 24px 12px; text-align: center; color: var(--dsw-alias-label-tertiary); font-size: 13px; }
1351
+ .${CLS.error} { display: flex; align-items: flex-start; gap: 8px; margin: 8px 12px 0; padding: 6px 8px;
1352
+ border-radius: var(--dsw-radius-md); color: var(--dsw-alias-state-error-primary); font-size: 12px;
1353
+ white-space: pre-wrap; word-break: break-word; background: var(--dsw-alias-interactive-bg-hover); }
1354
+ .${CLS.error} > span { flex: 1; }
1355
+ .${CLS.commit} { display: flex; flex-direction: column; gap: 8px; padding: 10px 12px 12px;
1356
+ border-top: 1px solid var(--dsw-alias-border-l2); }
1357
+ .${CLS.commitInput} { resize: vertical; min-height: 52px; padding: 8px 10px; border-radius: 8px;
1358
+ border: 1px solid var(--dsw-alias-border-l3); background: transparent; color: inherit; font: inherit; font-size: 14px; }
1359
+ .${CLS.commitRow} { display: flex; gap: 8px; }
1360
+ .${CLS.commitButton} { flex: 1; height: 34px; border: none; border-radius: 8px; cursor: pointer; font-size: 14px;
1361
+ background: var(--dsw-alias-state-business-primary); color: #fff; }
1362
+ .${CLS.commitButton}:disabled { cursor: default; background: var(--dsw-alias-interactive-bg-hover);
1363
+ color: var(--dsw-alias-label-tertiary); }
1364
+ .${CLS.aiButton} { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 34px;
1365
+ height: 34px; padding: 0; border: 1px solid var(--dsw-alias-border-l3); border-radius: 8px;
1366
+ background: transparent; color: var(--dsw-alias-label-secondary); cursor: pointer; }
1367
+ .${CLS.aiButton}:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
1368
+ `;
1369
+ var ROWS = `
1370
+ .${CLS.row} { position: relative; display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px;
1371
+ font-size: 12px; }
1372
+ .${CLS.row}:hover { background: var(--dsw-alias-interactive-bg-hover); }
1373
+ .${CLS.letter} { width: 16px; flex: none; text-align: center; font-family: var(--dsw-font-mono, monospace); font-weight: 600; }
1374
+ .${CLS.badge} { flex: none; display: inline-flex; align-items: center; justify-content: center; min-width: 16px;
1375
+ height: 14px; padding: 0 2px; border-radius: 3px; font-size: 8px; font-weight: 700; line-height: 1; color: #fff; }
1376
+ .${CLS.badge}[data-tone="blue"] { background: #3178c6; }
1377
+ .${CLS.badge}[data-tone="yellow"] { background: #c9a400; }
1378
+ .${CLS.badge}[data-tone="dark"] { background: #555; }
1379
+ .${CLS.badge}[data-tone="orange"] { background: transparent; color: #e44d26; font-size: 11px; }
1380
+ .${CLS.badge}[data-tone="plain"] { background: transparent; color: var(--dsw-alias-label-tertiary); font-size: 12px; }
1381
+ .${CLS.path} { flex: 1; min-width: 0; display: flex; padding: 0; border: none; background: transparent; color: inherit;
1382
+ font-family: var(--dsw-font-mono, monospace); font-size: 12px; cursor: pointer; text-align: left; }
1383
+ .${CLS.dir} { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left;
1384
+ color: var(--dsw-alias-label-tertiary); }
1385
+ .${CLS.name} { flex: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
1386
+ .${CLS.stats} { flex: none; display: flex; gap: 6px; font-variant-numeric: tabular-nums; }
1387
+ .${CLS.add} { color: var(--dsw-alias-state-success-primary); }
1388
+ .${CLS.del} { color: var(--dsw-alias-state-error-primary); }
1389
+ .${CLS.rowActions} { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); display: none; gap: 2px;
1390
+ padding-left: 8px; background: var(--dsw-alias-bg-layer-1); }
1391
+ .${CLS.row}:hover .${CLS.rowActions}, .${CLS.row}:focus-within .${CLS.rowActions} { display: flex; }
1392
+ .${CLS.row}[data-status="M"], .${CLS.row}[data-status="C"], .${CLS.row}[data-status="T"] { --${P}-tone: #0088d2; }
1393
+ .${CLS.row}[data-status="R"] { --${P}-tone: #0088d2; }
1394
+ .${CLS.row}[data-status="A"] { --${P}-tone: #208a3c; }
1395
+ .${CLS.row}[data-status="untracked"] { --${P}-tone: #b00020; }
1396
+ .${CLS.row}[data-status="U"] { --${P}-tone: #e5534b; }
1397
+ .${CLS.row}[data-status="D"] { --${P}-tone: var(--dsw-alias-label-tertiary); }
1398
+ ${DARK} .${CLS.row}[data-status="M"], ${DARK} .${CLS.row}[data-status="C"], ${DARK} .${CLS.row}[data-status="T"] { --${P}-tone: #589df6; }
1399
+ ${DARK} .${CLS.row}[data-status="R"] { --${P}-tone: #389fd6; }
1400
+ ${DARK} .${CLS.row}[data-status="A"] { --${P}-tone: #59a869; }
1401
+ ${DARK} .${CLS.row}[data-status="untracked"] { --${P}-tone: #e05555; }
1402
+ .${CLS.letter}, .${CLS.name} { color: var(--${P}-tone); }
1403
+ .${CLS.row}[data-status="D"] .${CLS.name} { text-decoration: line-through; opacity: 0.75; }
1404
+ `;
1405
+ var DIFF = `
1406
+ .${CLS.diff} { display: flex; flex-direction: column; height: 100%; min-height: 0; }
1407
+ .${CLS.diffHeader} { display: flex; align-items: center; gap: 8px; padding: 8px 12px;
1408
+ border-bottom: 1px solid var(--dsw-alias-border-l2); }
1409
+ .${CLS.diffPath} { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
1410
+ font-family: var(--dsw-font-mono, monospace); font-size: 12px; }
1411
+ .${CLS.diffSide} { font-size: 12px; color: var(--dsw-alias-label-tertiary); }
1412
+ .${CLS.diffBody} { flex: 1; min-height: 0; overflow: auto; font-family: var(--dsw-font-mono, monospace);
1413
+ font-size: 12px; line-height: 18px; }
1414
+ .${CLS.diffHunk} { padding: 2px 8px; color: var(--dsw-alias-state-business-primary); background: var(--dsw-alias-bg-layer-2); }
1415
+ .${CLS.diffNote} { padding: 4px 8px; color: var(--dsw-alias-label-tertiary); }
1416
+ .${CLS.diffLine} { display: flex; min-width: max-content; }
1417
+ .${CLS.diffLine}[data-kind="add"] { background: rgba(34, 197, 94, 0.1); }
1418
+ .${CLS.diffLine}[data-kind="del"] { background: rgba(239, 68, 68, 0.1); }
1419
+ .${CLS.diffNumber} { flex: none; width: 36px; padding-right: 6px; text-align: right; user-select: none;
1420
+ color: var(--dsw-alias-label-tertiary); }
1421
+ .${CLS.diffText} { padding: 0 8px; white-space: pre; }
1422
+ `;
1423
+ var CHANGES_STYLES = `${LAYOUT}${ROWS}${DIFF}`;
1424
+
1425
+ // src/client/changes/changes-diff.tsx
1426
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1427
+ var SIDE_LABELS = { staged: "\u5DF2\u6682\u5B58", unstaged: "\u672A\u6682\u5B58", untracked: "\u672A\u8DDF\u8E2A" };
1428
+ var TRUNCATED = "Diff \u8FC7\u5927\uFF0C\u5DF2\u622A\u65AD";
1429
+ var NO_CHANGES = "\u6CA1\u6709\u53EF\u663E\u793A\u7684\u5DEE\u5F02";
1430
+ function Line({ row }) {
1431
+ if (row.kind === "hunk" || row.kind === "note") {
1432
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: row.kind === "hunk" ? CLS.diffHunk : CLS.diffNote, children: row.text });
1433
+ }
1434
+ const oldLine = row.kind === "add" ? "" : String(row.oldLine);
1435
+ const newLine = row.kind === "del" ? "" : String(row.newLine);
1436
+ const sign = row.kind === "add" ? "+" : row.kind === "del" ? "-" : " ";
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: CLS.diffLine, "data-kind": row.kind, children: [
1438
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: CLS.diffNumber, children: oldLine }),
1439
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: CLS.diffNumber, children: newLine }),
1440
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: CLS.diffText, children: [
1441
+ sign,
1442
+ row.text
1443
+ ] })
1444
+ ] });
1445
+ }
1446
+ function useDiff(api, diff) {
1447
+ const [loaded, setLoaded] = (0, import_react7.useState)({ kind: "loading" });
1448
+ const { entry, side } = diff;
1449
+ (0, import_react7.useEffect)(() => {
1450
+ let live = true;
1451
+ setLoaded({ kind: "loading" });
1452
+ api.diff({ path: entry.path, side, origPath: entry.origPath }).then(
1453
+ (file) => {
1454
+ if (!live) return;
1455
+ setLoaded(
1456
+ file.truncated ? { kind: "rows", rows: [], truncated: true } : { kind: "rows", ...diffRows(file.patch) }
1457
+ );
1458
+ },
1459
+ (error) => {
1460
+ if (live) setLoaded({ kind: "error", message: error instanceof Error ? error.message : String(error) });
1461
+ }
1462
+ );
1463
+ return () => {
1464
+ live = false;
1465
+ };
1466
+ }, [api, entry.path, entry.origPath, side]);
1467
+ return loaded;
1468
+ }
1469
+ function Body({ loaded }) {
1470
+ if (loaded.kind === "loading") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: CLS.empty, children: "\u52A0\u8F7D\u4E2D\u2026" });
1471
+ if (loaded.kind === "error") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: CLS.error, children: loaded.message });
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: CLS.diffBody, children: [
1473
+ loaded.rows.length === 0 && !loaded.truncated ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: CLS.empty, children: NO_CHANGES }) : null,
1474
+ loaded.rows.map((row, index) => (
1475
+ // Rows have no identity of their own, and one patch's rows never reorder.
1476
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Line, { row }, index)
1477
+ )),
1478
+ loaded.truncated ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: CLS.diffNote, children: TRUNCATED }) : null
1479
+ ] });
1480
+ }
1481
+ function ChangesDiff({
1482
+ api,
1483
+ diff,
1484
+ onBack
1485
+ }) {
1486
+ const loaded = useDiff(api, diff);
1487
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: CLS.diff, children: [
1488
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: CLS.diffHeader, children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: CLS.headerButton, title: "\u8FD4\u56DE", "aria-label": "\u8FD4\u56DE", onClick: onBack, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BackIcon, { size: 16 }) }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: CLS.diffPath, title: diff.entry.path, children: diff.entry.path }),
1491
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: CLS.diffSide, children: SIDE_LABELS[diff.side] })
1492
+ ] }),
1493
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Body, { loaded })
1494
+ ] });
1495
+ }
1496
+
1497
+ // src/client/changes/changes-header.tsx
1498
+ var import_react8 = require("react");
1499
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
1500
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1501
+ var NEW_BRANCH_ID = "\0new";
1502
+ var REMOTE_PREFIX = "remote:";
1503
+ var LOCAL_PREFIX = "local:";
1504
+ var DETACHED_LABEL = "\u6E38\u79BB HEAD";
1505
+ var LOADING_ITEM = { id: "\0loading", label: "\u52A0\u8F7D\u4E2D\u2026" };
1506
+ function HeaderButton({
1507
+ label,
1508
+ disabled,
1509
+ onClick,
1510
+ children
1511
+ }) {
1512
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1513
+ "button",
1514
+ {
1515
+ type: "button",
1516
+ className: CLS.headerButton,
1517
+ title: label,
1518
+ "aria-label": label,
1519
+ disabled,
1520
+ onClick,
1521
+ children
1522
+ }
1523
+ );
1524
+ }
1525
+ function branchItems(list) {
1526
+ if (list === void 0) return [LOADING_ITEM];
1527
+ return [
1528
+ ...list.local.map((name) => ({ id: `${LOCAL_PREFIX}${name}`, label: name })),
1529
+ ...list.remote.map((name) => ({
1530
+ id: `${REMOTE_PREFIX}${name}`,
1531
+ label: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: CLS.remoteItem, children: [
1532
+ name,
1533
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: CLS.remoteTag, children: "\u8FDC\u7A0B\u5206\u652F" })
1534
+ ] })
1535
+ })),
1536
+ { id: NEW_BRANCH_ID, label: "\u65B0\u5EFA\u5206\u652F\u2026" }
1537
+ ];
1538
+ }
1539
+ function NewBranchForm({
1540
+ onCreate,
1541
+ onCancel
1542
+ }) {
1543
+ const [name, setName] = (0, import_react8.useState)("");
1544
+ const trimmed = name.trim();
1545
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1546
+ "form",
1547
+ {
1548
+ className: CLS.branchForm,
1549
+ onSubmit: (event) => {
1550
+ event.preventDefault();
1551
+ if (trimmed !== "") onCreate(trimmed);
1552
+ },
1553
+ children: [
1554
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1555
+ "input",
1556
+ {
1557
+ className: CLS.branchInput,
1558
+ autoFocus: true,
1559
+ placeholder: "\u5206\u652F\u540D\u79F0",
1560
+ "aria-label": "\u5206\u652F\u540D\u79F0",
1561
+ value: name,
1562
+ onChange: (event) => {
1563
+ setName(event.target.value);
1564
+ },
1565
+ onKeyDown: (event) => {
1566
+ if (event.key === "Escape") onCancel();
1567
+ }
1568
+ }
1569
+ ),
1570
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "submit", className: CLS.groupAction, disabled: trimmed === "", children: "\u65B0\u5EFA" }),
1571
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: CLS.groupAction, onClick: onCancel, children: "\u8FD4\u56DE" })
1572
+ ]
1573
+ }
1574
+ );
1575
+ }
1576
+ var NO_BRANCHES = { current: void 0, local: [], remote: [] };
1577
+ function useBranchList(api) {
1578
+ const [list, setList] = (0, import_react8.useState)();
1579
+ const load = () => {
1580
+ setList(void 0);
1581
+ api.branches().then(
1582
+ (answer) => {
1583
+ setList("local" in answer ? answer : NO_BRANCHES);
1584
+ },
1585
+ () => {
1586
+ setList(NO_BRANCHES);
1587
+ }
1588
+ );
1589
+ };
1590
+ return { list, load };
1591
+ }
1592
+ function pickBranch(id, actions, startCreating) {
1593
+ if (id === NEW_BRANCH_ID) startCreating();
1594
+ else if (id.startsWith(LOCAL_PREFIX)) actions.checkout(id.slice(LOCAL_PREFIX.length), false);
1595
+ else if (id.startsWith(REMOTE_PREFIX)) actions.checkout(id.slice(REMOTE_PREFIX.length), true);
1596
+ }
1597
+ function BranchButton({
1598
+ branch,
1599
+ busy,
1600
+ onClick
1601
+ }) {
1602
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "button", className: CLS.branchButton, "aria-label": "\u5206\u652F", disabled: busy, onClick, children: [
1603
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BranchIcon, { size: 16 }),
1604
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: CLS.branchName, children: branch ?? DETACHED_LABEL }),
1605
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ChevronIcon, { size: 16 })
1606
+ ] });
1607
+ }
1608
+ function BranchPicker({ status, api, busy, actions }) {
1609
+ const [open, setOpen] = (0, import_react8.useState)(false);
1610
+ const [creating, setCreating] = (0, import_react8.useState)(false);
1611
+ const { list, load } = useBranchList(api);
1612
+ if (creating) {
1613
+ const finish = (name) => {
1614
+ setCreating(false);
1615
+ if (name !== void 0) actions.createBranch(name);
1616
+ };
1617
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1618
+ NewBranchForm,
1619
+ {
1620
+ onCreate: finish,
1621
+ onCancel: () => {
1622
+ finish();
1623
+ }
1624
+ }
1625
+ );
1626
+ }
1627
+ const anchor = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1628
+ BranchButton,
1629
+ {
1630
+ branch: status.branch,
1631
+ busy,
1632
+ onClick: () => {
1633
+ if (!open) load();
1634
+ setOpen(!open);
1635
+ }
1636
+ }
1637
+ );
1638
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1639
+ import_dsh_client_ui_primitives5.Menu,
1640
+ {
1641
+ open,
1642
+ className: CLS.branchMenu,
1643
+ items: branchItems(list),
1644
+ selectedId: status.branch === void 0 ? void 0 : `${LOCAL_PREFIX}${status.branch}`,
1645
+ onSelect: (id) => {
1646
+ setOpen(false);
1647
+ pickBranch(id, actions, () => {
1648
+ setCreating(true);
1649
+ });
1650
+ },
1651
+ onClose: () => {
1652
+ setOpen(false);
1653
+ },
1654
+ portal: true,
1655
+ anchor
1656
+ }
1657
+ );
1658
+ }
1659
+ function ChangesHeader({ status, api, busy, refreshing, actions }) {
1660
+ const tracked = status.ahead !== void 0 && status.behind !== void 0;
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: CLS.header, children: [
1662
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: CLS.headerRow, children: [
1663
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: CLS.title, children: "\u53D8\u66F4" }),
1664
+ tracked ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: CLS.distance, title: "\u9886\u5148 / \u843D\u540E\u4E0A\u6E38\u7684\u63D0\u4EA4\u6570", children: [
1665
+ "\u2191",
1666
+ status.ahead,
1667
+ " \u2193",
1668
+ status.behind
1669
+ ] }) : null,
1670
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: CLS.headerButtons, children: [
1671
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(HeaderButton, { label: "\u5237\u65B0", disabled: refreshing, onClick: actions.refresh, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RefreshIcon, { size: 16, className: refreshing ? CLS.spinning : void 0 }) }),
1672
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(HeaderButton, { label: "\u62C9\u53D6", disabled: busy, onClick: actions.pull, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PullIcon, { size: 16 }) }),
1673
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(HeaderButton, { label: "\u63A8\u9001", disabled: busy, onClick: actions.push, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PushIcon, { size: 16 }) })
1674
+ ] })
1675
+ ] }),
1676
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(BranchPicker, { status, api, busy, actions })
1677
+ ] });
1678
+ }
1679
+
1680
+ // src/client/changes/changes-list.tsx
1681
+ var import_react9 = require("react");
1682
+
1683
+ // src/client/changes/changes-model.ts
1684
+ var GROUP_IDS = ["staged", "unstaged", "untracked"];
1685
+ var GROUP_TITLES = {
1686
+ staged: "\u5DF2\u6682\u5B58",
1687
+ unstaged: "\u672A\u6682\u5B58",
1688
+ untracked: "\u672A\u8DDF\u8E2A"
1689
+ };
1690
+ function sum(entries, key) {
1691
+ return entries.reduce((total, entry) => total + (entry[key] ?? 0), 0);
1692
+ }
1693
+ function changedPaths(status) {
1694
+ return new Set(GROUP_IDS.flatMap((group) => status[group].map((entry) => entry.path)));
1695
+ }
1696
+ function summarize(status) {
1697
+ const entries = GROUP_IDS.flatMap((group) => status[group]);
1698
+ return {
1699
+ files: changedPaths(status).size,
1700
+ additions: sum(entries, "additions"),
1701
+ deletions: sum(entries, "deletions")
1702
+ };
1703
+ }
1704
+ function reconcileSelection(selection, before, after) {
1705
+ const present = changedPaths(after);
1706
+ const wasStaged = new Set(before?.staged.map((entry) => entry.path) ?? []);
1707
+ const kept = [...selection].filter((path) => present.has(path));
1708
+ const newlyStaged = after.staged.map((entry) => entry.path).filter((path) => !wasStaged.has(path));
1709
+ return /* @__PURE__ */ new Set([...kept, ...newlyStaged]);
1710
+ }
1711
+ function toggleSelection(selection, paths, selected) {
1712
+ if (selected) return /* @__PURE__ */ new Set([...selection, ...paths]);
1713
+ const removed = new Set(paths);
1714
+ return new Set([...selection].filter((path) => !removed.has(path)));
1715
+ }
1716
+ function commitPaths(selection, status) {
1717
+ const present = changedPaths(status);
1718
+ return [...selection].filter((path) => present.has(path));
1719
+ }
1720
+ function groupCheck(selection, entries) {
1721
+ const count = entries.filter((entry) => selection.has(entry.path)).length;
1722
+ if (count === 0) return "none";
1723
+ return count === entries.length ? "all" : "some";
1724
+ }
1725
+ function splitPath(path) {
1726
+ const cut = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
1727
+ return { dir: path.slice(0, cut + 1), name: path.slice(cut + 1) };
1728
+ }
1729
+ var STATUS_LABELS = {
1730
+ M: "\u5DF2\u4FEE\u6539",
1731
+ A: "\u65B0\u6587\u4EF6",
1732
+ D: "\u5DF2\u5220\u9664",
1733
+ R: "\u5DF2\u91CD\u547D\u540D",
1734
+ C: "\u5DF2\u590D\u5236",
1735
+ T: "\u7C7B\u578B\u5DF2\u53D8",
1736
+ U: "\u6709\u51B2\u7A81",
1737
+ "?": "\u672A\u8DDF\u8E2A"
1738
+ };
1739
+
1740
+ // src/client/changes/changes-row.tsx
1741
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1742
+ var BADGES = {
1743
+ ts: { text: "TS", tone: "blue" },
1744
+ tsx: { text: "TSX", tone: "blue" },
1745
+ js: { text: "JS", tone: "yellow" },
1746
+ jsx: { text: "JSX", tone: "yellow" },
1747
+ mjs: { text: "JS", tone: "yellow" },
1748
+ json: { text: "{}", tone: "yellow" },
1749
+ md: { text: "M\u2193", tone: "dark" },
1750
+ html: { text: "<>", tone: "orange" },
1751
+ css: { text: "#", tone: "blue" },
1752
+ py: { text: "PY", tone: "blue" },
1753
+ rs: { text: "RS", tone: "orange" },
1754
+ go: { text: "GO", tone: "blue" }
1755
+ };
1756
+ var DEFAULT_BADGE = { text: "\xB7", tone: "plain" };
1757
+ var SIDE_OF = { staged: "staged", unstaged: "unstaged", untracked: "untracked" };
1758
+ function badgeOf(path) {
1759
+ const name = splitPath(path).name;
1760
+ const dot = name.lastIndexOf(".");
1761
+ return dot <= 0 ? DEFAULT_BADGE : BADGES[name.slice(dot + 1).toLowerCase()] ?? DEFAULT_BADGE;
1762
+ }
1763
+ function RowActions({ group, entry, busy, actions }) {
1764
+ const staged = group === "staged";
1765
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: CLS.rowActions, children: [
1766
+ staged ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1767
+ "button",
1768
+ {
1769
+ type: "button",
1770
+ className: CLS.iconButton,
1771
+ title: "\u64A4\u9500\u66F4\u6539",
1772
+ "aria-label": "\u64A4\u9500\u66F4\u6539",
1773
+ disabled: busy,
1774
+ onClick: () => {
1775
+ actions.discard(group, [entry]);
1776
+ },
1777
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(UndoIcon, { size: 14 })
1778
+ }
1779
+ ),
1780
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1781
+ "button",
1782
+ {
1783
+ type: "button",
1784
+ className: CLS.iconButton,
1785
+ title: staged ? "\u53D6\u6D88\u6682\u5B58" : "\u6682\u5B58",
1786
+ "aria-label": staged ? "\u53D6\u6D88\u6682\u5B58" : "\u6682\u5B58",
1787
+ disabled: busy,
1788
+ onClick: () => {
1789
+ if (staged) actions.unstage([entry.path]);
1790
+ else actions.stage([entry.path]);
1791
+ },
1792
+ children: staged ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MinusIcon, { size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PlusIcon2, { size: 14 })
1793
+ }
1794
+ )
1795
+ ] });
1796
+ }
1797
+ function PathButton({ group, entry, actions }) {
1798
+ const { dir, name } = splitPath(entry.path);
1799
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1800
+ "button",
1801
+ {
1802
+ type: "button",
1803
+ className: CLS.path,
1804
+ title: entry.origPath === void 0 ? entry.path : `${entry.origPath} \u2192 ${entry.path}`,
1805
+ onClick: () => {
1806
+ actions.open(entry, SIDE_OF[group]);
1807
+ },
1808
+ children: [
1809
+ dir === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: CLS.dir, dir: "rtl", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("bdo", { dir: "ltr", children: dir }) }),
1810
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: CLS.name, children: name })
1811
+ ]
1812
+ }
1813
+ );
1814
+ }
1815
+ function LineStats({ entry }) {
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: CLS.stats, children: [
1817
+ entry.additions === void 0 || entry.additions === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: CLS.add, children: [
1818
+ "+",
1819
+ entry.additions
1820
+ ] }),
1821
+ entry.deletions === void 0 || entry.deletions === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: CLS.del, children: [
1822
+ "\u2212",
1823
+ entry.deletions
1824
+ ] })
1825
+ ] });
1826
+ }
1827
+ function FileRow(props) {
1828
+ const { entry, selected, actions } = props;
1829
+ const badge = badgeOf(entry.path);
1830
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: CLS.row, "data-status": entry.status === "?" ? "untracked" : entry.status, children: [
1831
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1832
+ "input",
1833
+ {
1834
+ type: "checkbox",
1835
+ className: CLS.checkbox,
1836
+ checked: selected,
1837
+ "aria-label": `\u9009\u62E9 ${entry.path}`,
1838
+ onChange: (event) => {
1839
+ actions.select([entry.path], event.target.checked);
1840
+ }
1841
+ }
1842
+ ),
1843
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: CLS.letter, title: STATUS_LABELS[entry.status], children: entry.status }),
1844
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: CLS.badge, "data-tone": badge.tone, children: badge.text }),
1845
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PathButton, { ...props }),
1846
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LineStats, { entry }),
1847
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RowActions, { ...props })
1848
+ ] });
1849
+ }
1850
+
1851
+ // src/client/changes/changes-list.tsx
1852
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1853
+ function SummaryRow({
1854
+ status,
1855
+ selected
1856
+ }) {
1857
+ const { files, additions, deletions } = summarize(status);
1858
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: CLS.summary, children: [
1859
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: CLS.summaryTitle, children: [
1860
+ files,
1861
+ " \u4E2A\u672A\u63D0\u4EA4\u53D8\u66F4"
1862
+ ] }),
1863
+ additions > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: CLS.add, children: [
1864
+ "+",
1865
+ additions
1866
+ ] }) : null,
1867
+ deletions > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: CLS.del, children: [
1868
+ "\u2212",
1869
+ deletions
1870
+ ] }) : null,
1871
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { className: CLS.summarySelected, children: [
1872
+ "\u5DF2\u9009 ",
1873
+ selected,
1874
+ " \u9879"
1875
+ ] })
1876
+ ] });
1877
+ }
1878
+ function GroupCheckbox({
1879
+ entries,
1880
+ selection,
1881
+ onChange
1882
+ }) {
1883
+ const ref = (0, import_react9.useRef)(null);
1884
+ const check = groupCheck(selection, entries);
1885
+ (0, import_react9.useEffect)(() => {
1886
+ if (ref.current !== null) ref.current.indeterminate = check === "some";
1887
+ }, [check]);
1888
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1889
+ "input",
1890
+ {
1891
+ ref,
1892
+ type: "checkbox",
1893
+ className: CLS.checkbox,
1894
+ checked: check === "all",
1895
+ "aria-label": "\u5168\u9009\u672C\u7EC4",
1896
+ onChange: (event) => {
1897
+ onChange(event.target.checked);
1898
+ }
1899
+ }
1900
+ );
1901
+ }
1902
+ function TextAction({
1903
+ label,
1904
+ danger = false,
1905
+ busy,
1906
+ onClick
1907
+ }) {
1908
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1909
+ "button",
1910
+ {
1911
+ type: "button",
1912
+ className: danger ? `${CLS.groupAction} ${CLS.danger}` : CLS.groupAction,
1913
+ disabled: busy,
1914
+ onClick,
1915
+ children: label
1916
+ }
1917
+ );
1918
+ }
1919
+ function GroupActions({
1920
+ group,
1921
+ entries,
1922
+ busy,
1923
+ actions
1924
+ }) {
1925
+ const paths = entries.map((entry) => entry.path);
1926
+ if (group === "staged")
1927
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1928
+ TextAction,
1929
+ {
1930
+ label: "\u5168\u90E8\u53D6\u6D88\u6682\u5B58",
1931
+ busy,
1932
+ onClick: () => {
1933
+ actions.unstage(paths);
1934
+ }
1935
+ }
1936
+ );
1937
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1939
+ TextAction,
1940
+ {
1941
+ label: "\u5168\u90E8\u64A4\u9500",
1942
+ danger: true,
1943
+ busy,
1944
+ onClick: () => {
1945
+ actions.discard(group, entries);
1946
+ }
1947
+ }
1948
+ ),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1950
+ TextAction,
1951
+ {
1952
+ label: "\u5168\u90E8\u6682\u5B58",
1953
+ busy,
1954
+ onClick: () => {
1955
+ actions.stage(paths);
1956
+ }
1957
+ }
1958
+ )
1959
+ ] });
1960
+ }
1961
+ function GroupHeader({
1962
+ open,
1963
+ onToggle,
1964
+ ...props
1965
+ }) {
1966
+ const { group, entries, selection, actions } = props;
1967
+ const title = GROUP_TITLES[group];
1968
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1969
+ "div",
1970
+ {
1971
+ className: CLS.groupHeader,
1972
+ onClick: (event) => {
1973
+ if (!(event.target instanceof Element)) return;
1974
+ if (event.target.closest("button, input, label, a") !== null) return;
1975
+ onToggle();
1976
+ },
1977
+ children: [
1978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1979
+ "button",
1980
+ {
1981
+ type: "button",
1982
+ className: CLS.iconButton,
1983
+ "aria-expanded": open,
1984
+ "aria-label": `${open ? "\u6298\u53E0" : "\u5C55\u5F00"}${title}`,
1985
+ onClick: onToggle,
1986
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ChevronIcon, { size: 14, className: open ? void 0 : CLS.collapsed })
1987
+ }
1988
+ ),
1989
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1990
+ GroupCheckbox,
1991
+ {
1992
+ entries,
1993
+ selection,
1994
+ onChange: (selected) => {
1995
+ actions.select(
1996
+ entries.map((entry) => entry.path),
1997
+ selected
1998
+ );
1999
+ }
2000
+ }
2001
+ ),
2002
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: CLS.groupTitle, children: title }),
2003
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: CLS.groupCount, children: entries.length }),
2004
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: CLS.groupActions, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(GroupActions, { ...props }) })
2005
+ ]
2006
+ }
2007
+ );
2008
+ }
2009
+ function Group(props) {
2010
+ const [open, setOpen] = (0, import_react9.useState)(true);
2011
+ const { group, entries, selection, busy, actions } = props;
2012
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: CLS.group, "aria-label": GROUP_TITLES[group], children: [
2013
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2014
+ GroupHeader,
2015
+ {
2016
+ ...props,
2017
+ open,
2018
+ onToggle: () => {
2019
+ setOpen((value) => !value);
2020
+ }
2021
+ }
2022
+ ),
2023
+ open ? entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2024
+ FileRow,
2025
+ {
2026
+ group,
2027
+ entry,
2028
+ selected: selection.has(entry.path),
2029
+ busy,
2030
+ actions
2031
+ },
2032
+ `${group}:${entry.path}`
2033
+ )) : null
2034
+ ] });
2035
+ }
2036
+ function ChangesList({ status, selection, busy, actions }) {
2037
+ const groups = GROUP_IDS.filter((group) => status[group].length > 0);
2038
+ if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: CLS.empty, children: "\u6CA1\u6709\u53D8\u66F4" });
2039
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: CLS.list, children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Group, { group, entries: status[group], selection, busy, actions }, group)) });
2040
+ }
2041
+
2042
+ // src/client/changes/use-changes.ts
2043
+ var import_react10 = require("react");
2044
+ var REFRESH_INTERVAL_MS = 15e3;
2045
+ var INITIAL = {
2046
+ answer: void 0,
2047
+ selection: /* @__PURE__ */ new Set(),
2048
+ message: "",
2049
+ busy: void 0,
2050
+ refreshing: false,
2051
+ error: void 0,
2052
+ diff: void 0
2053
+ };
2054
+ function messageOf(error) {
2055
+ return error instanceof Error ? error.message : String(error);
2056
+ }
2057
+ function applyAnswer(state, answer) {
2058
+ if (!answer.repo) return { ...state, answer, selection: /* @__PURE__ */ new Set() };
2059
+ const before = state.answer?.repo === true ? state.answer : void 0;
2060
+ return { ...state, answer, selection: reconcileSelection(state.selection, before, answer) };
2061
+ }
2062
+ function createRun(api, setState, refs) {
2063
+ return (busy, operation, after) => {
2064
+ if (refs.current.current.busy !== void 0) return;
2065
+ refs.bump();
2066
+ setState((previous) => ({ ...previous, busy, error: void 0 }));
2067
+ operation(api).then(
2068
+ (answer) => {
2069
+ setState((previous) => {
2070
+ const next = { ...applyAnswer(previous, answer), busy: void 0 };
2071
+ return after === void 0 ? next : after(next);
2072
+ });
2073
+ },
2074
+ (error) => {
2075
+ setState((previous) => ({ ...previous, busy: void 0, error: messageOf(error) }));
2076
+ }
2077
+ );
2078
+ };
2079
+ }
2080
+ function createRefresh(api, setState, refs) {
2081
+ return () => {
2082
+ const { busy, refreshing } = refs.current.current;
2083
+ if (busy !== void 0 || refreshing) return;
2084
+ const started = refs.generation();
2085
+ setState((previous) => ({ ...previous, refreshing: true }));
2086
+ api.status().then(
2087
+ (answer) => {
2088
+ setState(
2089
+ (previous) => refs.generation() === started ? { ...applyAnswer(previous, answer), refreshing: false } : { ...previous, refreshing: false }
2090
+ );
2091
+ },
2092
+ (error) => {
2093
+ setState((previous) => ({ ...previous, refreshing: false, error: messageOf(error) }));
2094
+ }
2095
+ );
2096
+ };
2097
+ }
2098
+ function writeActions(run, current) {
2099
+ return {
2100
+ stage: (paths) => {
2101
+ run(
2102
+ "stage",
2103
+ (api) => api.stage(paths),
2104
+ (next) => ({ ...next, selection: toggleSelection(next.selection, paths, true) })
2105
+ );
2106
+ },
2107
+ unstage: (paths) => {
2108
+ run(
2109
+ "unstage",
2110
+ (api) => api.unstage(paths),
2111
+ (next) => ({ ...next, selection: toggleSelection(next.selection, paths, false) })
2112
+ );
2113
+ },
2114
+ discard: (target) => {
2115
+ run(
2116
+ "discard",
2117
+ (api) => api.discard(target),
2118
+ (next) => ({ ...next, diff: void 0 })
2119
+ );
2120
+ },
2121
+ commit: () => {
2122
+ const { answer, selection, message: message2 } = current.current;
2123
+ if (answer?.repo !== true) return;
2124
+ const paths = commitPaths(selection, answer);
2125
+ run(
2126
+ "commit",
2127
+ (api) => api.commit({ message: message2, paths }),
2128
+ (next) => ({ ...next, message: "" })
2129
+ );
2130
+ },
2131
+ push: () => {
2132
+ run("push", (api) => api.push());
2133
+ },
2134
+ pull: () => {
2135
+ run("pull", (api) => api.pull());
2136
+ },
2137
+ checkout: (branch, remote) => {
2138
+ run("checkout", (api) => api.checkout({ branch, remote }));
2139
+ },
2140
+ createBranch: (branch) => {
2141
+ run("checkout", (api) => api.createBranch(branch));
2142
+ }
2143
+ };
2144
+ }
2145
+ function localActions(setState) {
2146
+ return {
2147
+ setMessage: (message2) => {
2148
+ setState((previous) => ({ ...previous, message: message2 }));
2149
+ },
2150
+ select: (paths, selected) => {
2151
+ setState((previous) => ({ ...previous, selection: toggleSelection(previous.selection, paths, selected) }));
2152
+ },
2153
+ openDiff: (diff) => {
2154
+ setState((previous) => ({ ...previous, diff }));
2155
+ },
2156
+ dismissError: () => {
2157
+ setState((previous) => ({ ...previous, error: void 0 }));
2158
+ }
2159
+ };
2160
+ }
2161
+ function useChanges(api) {
2162
+ const [state, setState] = (0, import_react10.useState)(INITIAL);
2163
+ const current = (0, import_react10.useRef)(state);
2164
+ const generation = (0, import_react10.useRef)(0);
2165
+ (0, import_react10.useEffect)(() => {
2166
+ current.current = state;
2167
+ }, [state]);
2168
+ const { run, refresh } = (0, import_react10.useMemo)(() => {
2169
+ const refs = {
2170
+ current,
2171
+ generation: () => generation.current,
2172
+ bump: () => {
2173
+ generation.current += 1;
2174
+ }
2175
+ };
2176
+ return { run: createRun(api, setState, refs), refresh: createRefresh(api, setState, refs) };
2177
+ }, [api]);
2178
+ useAutoRefresh(refresh);
2179
+ const actions = (0, import_react10.useMemo)(() => ({ refresh, ...localActions(setState), ...writeActions(run, current) }), [refresh, run]);
2180
+ return { state, actions };
2181
+ }
2182
+ function useAutoRefresh(refresh) {
2183
+ (0, import_react10.useEffect)(() => {
2184
+ const whenVisible = () => {
2185
+ if (document.visibilityState !== "hidden") refresh();
2186
+ };
2187
+ refresh();
2188
+ const timer = window.setInterval(whenVisible, REFRESH_INTERVAL_MS);
2189
+ window.addEventListener("focus", refresh);
2190
+ document.addEventListener("visibilitychange", whenVisible);
2191
+ return () => {
2192
+ window.clearInterval(timer);
2193
+ window.removeEventListener("focus", refresh);
2194
+ document.removeEventListener("visibilitychange", whenVisible);
2195
+ };
2196
+ }, [refresh]);
2197
+ }
2198
+ function canCommit(state) {
2199
+ if (state.answer?.repo !== true || state.busy !== void 0 || state.message.trim() === "") return false;
2200
+ return commitPaths(state.selection, state.answer).length > 0;
2201
+ }
2202
+ function selectedCount(state) {
2203
+ return state.answer?.repo === true ? commitPaths(state.selection, state.answer).length : 0;
2204
+ }
2205
+
2206
+ // src/client/changes/changes-panel.tsx
2207
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2208
+ var NO_DIRECTORY = "\u8FD9\u4E2A\u4F1A\u8BDD\u8FD8\u6CA1\u6709\u5DE5\u4F5C\u76EE\u5F55";
2209
+ var NOT_A_REPO = "\u5F53\u524D\u5DE5\u4F5C\u533A\u4E0D\u662F Git \u4ED3\u5E93";
2210
+ var AI_LABEL = "AI \u751F\u6210\u63D0\u4EA4\u4FE1\u606F";
2211
+ var AI_UNAVAILABLE = "\u6682\u672A\u5F00\u653E\uFF0C\u656C\u8BF7\u671F\u5F85";
2212
+ function useCwd(list, sessionId) {
2213
+ const subscribe = (0, import_react11.useCallback)((listener) => list.subscribe(listener), [list]);
2214
+ return (0, import_react11.useSyncExternalStore)(subscribe, () => list.getSnapshot().byId[sessionId]?.cwd);
2215
+ }
2216
+ function discardText({ entries }) {
2217
+ const [only] = entries;
2218
+ return entries.length === 1 && only !== void 0 ? `\u786E\u5B9A\u8981\u64A4\u9500\u5BF9\u201C${only.path}\u201D\u7684\u66F4\u6539\u5417\uFF1F\u66F4\u6539\u5C06\u65E0\u6CD5\u6062\u590D\u3002` : `\u786E\u5B9A\u8981\u64A4\u9500\u8FD9 ${String(entries.length)} \u4E2A\u6587\u4EF6\u7684\u5168\u90E8\u66F4\u6539\u5417\uFF1F\u66F4\u6539\u5C06\u65E0\u6CD5\u6062\u590D\u3002`;
2219
+ }
2220
+ function DiscardDialog({
2221
+ pending,
2222
+ onConfirm,
2223
+ onClose
2224
+ }) {
2225
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2226
+ import_dsh_client_ui_primitives6.Modal,
2227
+ {
2228
+ open: pending !== void 0,
2229
+ onClose,
2230
+ title: "\u64A4\u9500\u66F4\u6539",
2231
+ closeLabel: "\u5173\u95ED",
2232
+ description: pending === void 0 ? void 0 : discardText(pending),
2233
+ footer: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2234
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_dsh_client_ui_primitives6.Button, { variant: "ghost", onClick: onClose, children: "\u53D6\u6D88" }),
2235
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2236
+ import_dsh_client_ui_primitives6.Button,
2237
+ {
2238
+ variant: "primary",
2239
+ onClick: () => {
2240
+ if (pending !== void 0) onConfirm(pending);
2241
+ },
2242
+ children: "\u786E\u5B9A"
2243
+ }
2244
+ )
2245
+ ] })
2246
+ }
2247
+ );
2248
+ }
2249
+ function AiCommitButton({ anchor }) {
2250
+ const [showTip, setShowTip] = (0, import_react11.useState)(false);
2251
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2252
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2253
+ "button",
2254
+ {
2255
+ type: "button",
2256
+ className: CLS.aiButton,
2257
+ title: AI_LABEL,
2258
+ "aria-label": AI_LABEL,
2259
+ onClick: () => {
2260
+ setShowTip(true);
2261
+ },
2262
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SparkleIcon, {})
2263
+ }
2264
+ ),
2265
+ showTip ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2266
+ import_dsh_client_ui_primitives6.Toast,
2267
+ {
2268
+ text: AI_UNAVAILABLE,
2269
+ anchor,
2270
+ onDone: () => {
2271
+ setShowTip(false);
2272
+ }
2273
+ }
2274
+ ) : null
2275
+ ] });
2276
+ }
2277
+ function CommitBox({
2278
+ state,
2279
+ actions
2280
+ }) {
2281
+ const count = selectedCount(state);
2282
+ const [box, setBox] = (0, import_react11.useState)(null);
2283
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: CLS.commit, ref: setBox, children: [
2284
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2285
+ "textarea",
2286
+ {
2287
+ className: CLS.commitInput,
2288
+ rows: 2,
2289
+ placeholder: "\u63D0\u4EA4\u4FE1\u606F\u2026",
2290
+ "aria-label": "\u63D0\u4EA4\u4FE1\u606F",
2291
+ value: state.message,
2292
+ onChange: (event) => {
2293
+ actions.setMessage(event.target.value);
2294
+ },
2295
+ onKeyDown: (event) => {
2296
+ if (event.key === "Enter" && (event.metaKey || event.ctrlKey) && canCommit(state)) actions.commit();
2297
+ }
2298
+ }
2299
+ ),
2300
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: CLS.commitRow, children: [
2301
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: CLS.commitButton, disabled: !canCommit(state), onClick: actions.commit, children: state.busy === "commit" ? "\u63D0\u4EA4\u4E2D\u2026" : `\u63D0\u4EA4 (${String(count)})` }),
2302
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AiCommitButton, { anchor: box })
2303
+ ] })
2304
+ ] });
2305
+ }
2306
+ function ErrorBanner({
2307
+ error,
2308
+ onDismiss
2309
+ }) {
2310
+ if (error === void 0) return null;
2311
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: CLS.error, role: "alert", children: [
2312
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { children: error }),
2313
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: CLS.groupAction, onClick: onDismiss, children: "\u5173\u95ED" })
2314
+ ] });
2315
+ }
2316
+ function toDiscard({ group, entries }) {
2317
+ const paths = entries.map((entry) => entry.path);
2318
+ return group === "untracked" ? { tracked: [], untracked: paths } : { tracked: paths, untracked: [] };
2319
+ }
2320
+ function RepoView({ api, state, actions, status }) {
2321
+ const [pending, setPending] = (0, import_react11.useState)();
2322
+ const busy = state.busy !== void 0;
2323
+ const listActions = {
2324
+ select: (paths, selected) => {
2325
+ actions.select(paths, selected);
2326
+ },
2327
+ stage: (paths) => {
2328
+ actions.stage(paths);
2329
+ },
2330
+ unstage: (paths) => {
2331
+ actions.unstage(paths);
2332
+ },
2333
+ discard: (group, entries) => {
2334
+ setPending({ group, entries });
2335
+ },
2336
+ open: (entry, side) => {
2337
+ actions.openDiff({ entry, side });
2338
+ }
2339
+ };
2340
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2341
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChangesHeader, { status, api, busy, refreshing: state.refreshing, actions }),
2342
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2343
+ ErrorBanner,
2344
+ {
2345
+ error: state.error,
2346
+ onDismiss: () => {
2347
+ actions.dismissError();
2348
+ }
2349
+ }
2350
+ ),
2351
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SummaryRow, { status, selected: selectedCount(state) }),
2352
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: CLS.scroll, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ChangesList, { status, selection: state.selection, busy, actions: listActions }) }),
2353
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CommitBox, { state, actions }),
2354
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2355
+ DiscardDialog,
2356
+ {
2357
+ pending,
2358
+ onClose: () => {
2359
+ setPending(void 0);
2360
+ },
2361
+ onConfirm: (confirmed) => {
2362
+ setPending(void 0);
2363
+ actions.discard(toDiscard(confirmed));
2364
+ }
2365
+ }
2366
+ )
2367
+ ] });
2368
+ }
2369
+ function Loaded({ api, state, actions }) {
2370
+ const { answer, diff } = state;
2371
+ if (answer === void 0) {
2372
+ return state.error === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: CLS.empty, children: "\u52A0\u8F7D\u4E2D\u2026" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: CLS.error, children: state.error });
2373
+ }
2374
+ if (!answer.repo) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: CLS.empty, children: NOT_A_REPO });
2375
+ if (diff !== void 0)
2376
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2377
+ ChangesDiff,
2378
+ {
2379
+ api,
2380
+ diff,
2381
+ onBack: () => {
2382
+ actions.openDiff(void 0);
2383
+ }
2384
+ }
2385
+ );
2386
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RepoView, { api, state, actions, status: answer });
2387
+ }
2388
+ function Panel({ cwd, fetch }) {
2389
+ const api = (0, import_react11.useMemo)(() => createGitApi(fetch, cwd), [fetch, cwd]);
2390
+ const { state, actions } = useChanges(api);
2391
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: CLS.panel, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Loaded, { api, state, actions }) });
2392
+ }
2393
+ function ChangesPanel({ sessionId, list, fetch }) {
2394
+ const cwd = useCwd(list, sessionId);
2395
+ if (cwd === void 0 || cwd === "") return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `${CLS.panel} ${CLS.empty}`, children: NO_DIRECTORY });
2396
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Panel, { cwd, fetch }, cwd);
2397
+ }
2398
+
2399
+ // src/client/changes/changes-title.tsx
2400
+ var import_jsx_runtime13 = require("react/jsx-runtime");
2401
+ var CHANGES_TITLE = "\u53D8\u66F4";
2402
+ var GLYPH_SIZE = 16;
2403
+ function ChangesTitle() {
2404
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2405
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ChangesIcon, { size: GLYPH_SIZE }),
2406
+ CHANGES_TITLE
2407
+ ] });
2408
+ }
2409
+
2410
+ // src/client/changes/changes-register.ts
2411
+ var CHANGES_ID = "dsh-ccgui.changes";
2412
+ var TAB_SLOT = "sidebar.right.pane.tab";
2413
+ var TITLE_SLOT = "sidebar.right.pane.tab.title";
2414
+ var TITLE = CHANGES_TITLE;
2415
+ var DESCRIPTION = "\u67E5\u770B\u3001\u6682\u5B58\u5E76\u63D0\u4EA4\u5DE5\u4F5C\u533A\u7684 Git \u53D8\u66F4";
2416
+ var GUIDE_ORDER = 70;
2417
+ function registerChanges(ctx, list, fetchFn) {
2418
+ ctx.inject(["sidebarRightTabs", "slots"], (child) => {
2419
+ child.effect(
2420
+ () => child.sidebarRightTabs.register({
2421
+ id: CHANGES_ID,
2422
+ kind: CHANGES_KIND,
2423
+ title: () => TITLE,
2424
+ guide: [{ id: "open", order: GUIDE_ORDER, title: () => TITLE, description: () => DESCRIPTION }]
2425
+ }),
2426
+ "ccgui: changes tab type"
2427
+ );
2428
+ child.slots.inject(
2429
+ TAB_SLOT,
2430
+ () => child.slots.register(
2431
+ { name: TAB_SLOT, key: CHANGES_ID, inject: (sessionId) => ({ sessionId, list, fetch: fetchFn }) },
2432
+ ChangesPanel
2433
+ )
2434
+ );
2435
+ child.slots.inject(TITLE_SLOT, () => child.slots.register({ name: TITLE_SLOT, key: CHANGES_ID }, ChangesTitle));
2436
+ });
2437
+ }
2438
+
2439
+ // src/client/launch-script-styles.ts
2440
+ var LS = {
2441
+ group: "dsh-ls-group",
2442
+ run: "dsh-ls-run",
2443
+ more: "dsh-ls-more",
2444
+ menuRow: "dsh-ls-menu-row",
2445
+ menuName: "dsh-ls-menu-name",
2446
+ menuCommand: "dsh-ls-menu-command",
2447
+ dialog: "dsh-ls-dialog",
2448
+ list: "dsh-ls-list",
2449
+ row: "dsh-ls-row",
2450
+ rowText: "dsh-ls-row-text",
2451
+ rowName: "dsh-ls-row-name",
2452
+ rowCommand: "dsh-ls-row-command",
2453
+ badge: "dsh-ls-badge",
2454
+ rowActions: "dsh-ls-row-actions",
2455
+ iconButton: "dsh-ls-icon-button",
2456
+ empty: "dsh-ls-empty",
2457
+ form: "dsh-ls-form",
2458
+ field: "dsh-ls-field",
2459
+ label: "dsh-ls-label",
2460
+ textarea: "dsh-ls-textarea",
2461
+ hint: "dsh-ls-hint",
2462
+ error: "dsh-ls-error",
2463
+ footer: "dsh-ls-footer"
2464
+ };
2465
+ var MONO = "var(--ds-font-family-code, ui-monospace, SFMono-Regular, Menlo, monospace)";
2466
+ var LAUNCH_SCRIPT_STYLES = `
2467
+ .${LS.group} { display: inline-flex; align-items: center; flex: none; }
2468
+ .${LS.run} { flex: none; width: 28px; padding: 0; color: var(--dsw-alias-label-secondary); }
2469
+ .${LS.run}[data-has-more] { border-top-right-radius: 0; border-bottom-right-radius: 0; }
2470
+ .${LS.run} svg { width: 15px; height: 15px; }
2471
+ .${LS.more} {
2472
+ flex: none; width: 16px; padding: 0; color: var(--dsw-alias-label-tertiary);
2473
+ border-top-left-radius: 0; border-bottom-left-radius: 0;
2474
+ }
2475
+ .${LS.more} svg { width: 12px; height: 12px; }
2476
+ .${LS.menuRow} { display: flex; flex-direction: column; min-width: 0; max-width: 280px; }
2477
+ .${LS.menuName} { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2478
+ .${LS.menuCommand} {
2479
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
2480
+ font-family: ${MONO}; font-size: 11px; color: var(--dsw-alias-label-tertiary);
2481
+ }
2482
+ .${LS.dialog} { width: min(480px, 100%); }
2483
+ .${LS.list} {
2484
+ margin: 0; padding: 0; list-style: none;
2485
+ display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }
2486
+ .${LS.row} {
2487
+ display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 4px 4px 4px 10px;
2488
+ border-radius: var(--dsw-radius-md);
2489
+ }
2490
+ .${LS.row}:hover, .${LS.row}:focus-within { background: var(--dsw-alias-interactive-bg-hover); }
2491
+ .${LS.rowText} { display: flex; flex: 1; flex-direction: column; min-width: 0; }
2492
+ .${LS.rowName} {
2493
+ display: flex; align-items: center; gap: 6px; min-width: 0;
2494
+ font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-primary);
2495
+ }
2496
+ .${LS.rowName} > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2497
+ .${LS.rowCommand} {
2498
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
2499
+ font-family: ${MONO}; font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary);
2500
+ }
2501
+ .${LS.badge} {
2502
+ flex: none; padding: 0 6px; border-radius: var(--dsw-radius-sm);
2503
+ font-size: 11px; line-height: 16px;
2504
+ color: var(--dsw-alias-state-business-primary);
2505
+ background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);
2506
+ }
2507
+ .${LS.rowActions} { display: flex; flex: none; gap: 2px; opacity: 0; }
2508
+ .${LS.row}:hover .${LS.rowActions}, .${LS.row}:focus-within .${LS.rowActions} { opacity: 1; }
2509
+ .${LS.iconButton} { width: 28px; padding: 0; color: var(--dsw-alias-label-secondary); }
2510
+ .${LS.iconButton}[data-danger] { color: var(--dsw-alias-state-error-primary); }
2511
+ .${LS.iconButton} svg { width: 15px; height: 15px; }
2512
+ .${LS.empty} {
2513
+ padding: 20px 12px; border: 0.5px dashed var(--dsw-alias-border-l3); border-radius: var(--dsw-radius-md);
2514
+ text-align: center; font-size: 13px; line-height: 20px; color: var(--dsw-alias-label-tertiary);
2515
+ }
2516
+ .${LS.form} { display: flex; flex-direction: column; gap: 14px; }
2517
+ .${LS.field} { display: flex; flex-direction: column; gap: 6px; }
2518
+ .${LS.label} { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }
2519
+ /* Three 18px lines plus the 8px padding above and below and the 0.5px borders. The
2520
+ textarea starts here and the person can drag it taller; anything longer scrolls. */
2521
+ .${LS.textarea} {
2522
+ box-sizing: border-box; width: 100%; min-height: 71px; padding: 8px 10px; resize: vertical;
2523
+ border: 0.5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md); outline: none;
2524
+ background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary);
2525
+ font-family: ${MONO}; font-size: 12px; line-height: 18px;
2526
+ }
2527
+ .${LS.textarea}:focus { border-color: var(--dsw-alias-state-business-primary); }
2528
+ .${LS.hint} { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-tertiary); }
2529
+ .${LS.error} { font-size: 12px; line-height: 18px; color: var(--dsw-alias-state-error-primary); }
2530
+ .${LS.footer} { display: flex; align-items: center; justify-content: flex-end; gap: 8px; width: 100%; }
2531
+ .${LS.footer} > :first-child[data-leading] { margin-right: auto; }
2532
+ `;
2533
+
2534
+ // src/client/session-tree-styles.ts
2535
+ var GROUP = ':has(> * > [data-row-key^="workspace:"])';
2536
+ var HEADER = ':has(> [data-row-key^="workspace:"])';
2537
+ var ITEM = ':has(> [data-row-key^="session:"])';
2538
+ var ROW2 = '[data-row-key^="session:"]';
2539
+ var INDENT = "var(--dsh-workspace-indent, 0px)";
2540
+ var LINE_X = "20px";
2541
+ var ROW_SHIFT = "28px";
2542
+ var ELBOW_WIDTH = "7px";
2543
+ var ELBOW_RADIUS = "5px";
2544
+ var ROW_GAP = "2px";
2545
+ var FIRST_REACH = "9px";
2546
+ var LINE = "1px solid var(--dsw-alias-border-l4)";
2547
+ var CHIP_FILL = "var(--dsw-alias-border-l2)";
2548
+ var CONTINUED = `${ITEM}:not(:nth-last-child(1 of ${ITEM}))`;
2549
+ var SESSION_TREE_STYLES = `
2550
+ ${GROUP} > ${ITEM} { position: relative; }
2551
+ ${GROUP} > ${ITEM} > ${ROW2} {
2552
+ margin-inline-start: calc(${ROW_SHIFT} + ${INDENT});
2553
+ padding-inline-start: calc(var(--dsh-sidebar-row-padding) - var(--dsh-sidebar-paint-inset));
2554
+ }
2555
+ ${GROUP} > ${ITEM}::before,
2556
+ ${GROUP} > ${CONTINUED}::after {
2557
+ content: '';
2558
+ position: absolute;
2559
+ left: calc(${LINE_X} + ${INDENT});
2560
+ pointer-events: none;
2561
+ box-sizing: border-box;
2562
+ }
2563
+ ${GROUP} > ${ITEM}::before {
2564
+ top: -${ROW_GAP};
2565
+ height: calc(50% + ${ROW_GAP});
2566
+ width: ${ELBOW_WIDTH};
2567
+ border-left: ${LINE};
2568
+ border-bottom: ${LINE};
2569
+ border-bottom-left-radius: ${ELBOW_RADIUS};
2570
+ }
2571
+ ${GROUP} > ${HEADER} + ${ITEM}::before {
2572
+ top: -${FIRST_REACH};
2573
+ height: calc(50% + ${FIRST_REACH});
2574
+ }
2575
+ ${GROUP} > ${CONTINUED}::after {
2576
+ top: 50%;
2577
+ bottom: 0;
2578
+ border-left: ${LINE};
2579
+ }
2580
+ ${GROUP} > ${ITEM} [class*="_timestamp"] {
2581
+ padding: 0 4px;
2582
+ border-radius: 4px;
2583
+ background: ${CHIP_FILL};
2584
+ }
2585
+ ${GROUP} > button {
2586
+ width: calc(100% - ${ROW_SHIFT} - ${INDENT});
2587
+ margin-inline-start: calc(${ROW_SHIFT} + ${INDENT});
2588
+ }
2589
+ `;
2590
+
2591
+ // src/client/launch-scripts.ts
2592
+ var STORAGE_PREFIX = "dsh-ccgui.launchScripts:";
2593
+ var NO_DIRECTORY_KEY = `${STORAGE_PREFIX}*`;
2594
+ var EMPTY2 = [];
2595
+ var MAX_COMMAND_LENGTH = 4e3;
2596
+ var MAX_NAME_LENGTH = 40;
2597
+ function storageKey(cwd) {
2598
+ return cwd === void 0 || cwd === "" ? NO_DIRECTORY_KEY : `${STORAGE_PREFIX}${cwd}`;
2599
+ }
2600
+ function isRecord2(value) {
2601
+ return typeof value === "object" && value !== null;
2602
+ }
2603
+ function normalize(value) {
2604
+ if (!isRecord2(value)) return void 0;
2605
+ const { id, name, command } = value;
2606
+ if (typeof id !== "string" || typeof command !== "string" || command.trim() === "") return void 0;
2607
+ return { id, name: typeof name === "string" ? name : "", command };
2608
+ }
2609
+ function parseScripts(raw) {
2610
+ if (raw === null) return EMPTY2;
2611
+ let value;
2612
+ try {
2613
+ value = JSON.parse(raw);
2614
+ } catch (_error) {
2615
+ return EMPTY2;
2616
+ }
2617
+ if (!Array.isArray(value)) return EMPTY2;
2618
+ return value.map(normalize).filter((script) => script !== void 0);
2619
+ }
2620
+ function scriptLabel(script) {
2621
+ const name = script.name.trim();
2622
+ if (name !== "") return name;
2623
+ return script.command.trim().split(/\r?\n/, 1)[0] ?? "";
2624
+ }
2625
+ function shellInput(command) {
2626
+ const lines = command.trim().split(/\r?\n/).filter((line) => line.trim() !== "");
2627
+ return `${lines.join("\r")}\r`;
2628
+ }
2629
+ function draftProblem(draft) {
2630
+ if (draft.command.trim() === "") return "\u8BF7\u586B\u5199\u8981\u8FD0\u884C\u7684\u547D\u4EE4";
2631
+ if (draft.command.length > MAX_COMMAND_LENGTH) return `\u547D\u4EE4\u4E0D\u80FD\u8D85\u8FC7 ${MAX_COMMAND_LENGTH} \u4E2A\u5B57\u7B26`;
2632
+ if (draft.name.trim().length > MAX_NAME_LENGTH) return `\u540D\u79F0\u4E0D\u80FD\u8D85\u8FC7 ${MAX_NAME_LENGTH} \u4E2A\u5B57\u7B26`;
2633
+ return void 0;
2634
+ }
2635
+ function saveDraft(scripts, draft, newId) {
2636
+ const fields = { name: draft.name.trim(), command: draft.command.trim() };
2637
+ const { id } = draft;
2638
+ if (id === void 0 || !scripts.some((script) => script.id === id)) {
2639
+ return [...scripts, { id: newId(), ...fields }];
2640
+ }
2641
+ return scripts.map((script) => script.id === id ? { ...script, ...fields } : script);
2642
+ }
2643
+ function removeScript(scripts, id) {
2644
+ return scripts.filter((script) => script.id !== id);
2645
+ }
2646
+ function promoteScript(scripts, id) {
2647
+ const chosen = scripts.find((script) => script.id === id);
2648
+ if (chosen === void 0) return scripts;
2649
+ return [chosen, ...scripts.filter((script) => script.id !== id)];
2650
+ }
2651
+ function readRaw(storage, key) {
2652
+ try {
2653
+ return storage.getItem(key);
2654
+ } catch (_error) {
2655
+ return null;
2656
+ }
2657
+ }
2658
+ function createScriptBook(storage) {
2659
+ let cache = /* @__PURE__ */ new Map();
2660
+ let listeners = [];
2661
+ return {
2662
+ read(cwd) {
2663
+ const key = storageKey(cwd);
2664
+ const cached = cache.get(key);
2665
+ if (cached !== void 0) return cached;
2666
+ const scripts = parseScripts(readRaw(storage, key));
2667
+ cache = new Map(cache).set(key, scripts);
2668
+ return scripts;
2669
+ },
2670
+ write(cwd, scripts) {
2671
+ const key = storageKey(cwd);
2672
+ storage.setItem(key, JSON.stringify(scripts));
2673
+ cache = new Map(cache).set(key, scripts);
2674
+ for (const listener of listeners) listener();
2675
+ },
2676
+ subscribe(listener) {
2677
+ listeners = [...listeners, listener];
2678
+ return () => {
2679
+ listeners = listeners.filter((other) => other !== listener);
2680
+ };
2681
+ }
2682
+ };
2683
+ }
2684
+
2685
+ // src/client/launch-script-run.ts
2686
+ var TERMINAL_KIND2 = "terminal";
2687
+ var ATTACH_TIMEOUT_MS = 15e3;
2688
+ var DEAD_PHASES = /* @__PURE__ */ new Set(["failed", "closed", "closing"]);
2689
+ var OPEN_FAILED = "\u6CA1\u80FD\u6253\u5F00\u7EC8\u7AEF\u6807\u7B7E";
2690
+ var ATTACH_FAILED = "\u7EC8\u7AEF\u6CA1\u6709\u51C6\u5907\u597D\uFF0C\u547D\u4EE4\u6CA1\u6709\u53D1\u9001";
2691
+ var ATTACH_TIMED_OUT = "\u7B49\u5F85\u7EC8\u7AEF\u8D85\u65F6\uFF0C\u547D\u4EE4\u6CA1\u6709\u53D1\u9001";
2692
+ function whenWritable(view, timeoutMs) {
2693
+ return new Promise((resolve, reject) => {
2694
+ let unsubscribe = () => void 0;
2695
+ const finish = (error) => {
2696
+ clearTimeout(timer);
2697
+ unsubscribe();
2698
+ if (error === void 0) resolve();
2699
+ else reject(error);
2700
+ };
2701
+ const check = () => {
2702
+ const state = view.state.getSnapshot();
2703
+ if (state.writable) finish();
2704
+ else if (DEAD_PHASES.has(state.phase)) finish(new Error(state.error ?? ATTACH_FAILED));
2705
+ };
2706
+ const timer = setTimeout(() => {
2707
+ finish(new Error(ATTACH_TIMED_OUT));
2708
+ }, timeoutMs);
2709
+ unsubscribe = view.state.subscribe(check);
2710
+ check();
2711
+ });
2712
+ }
2713
+ function openFreshTerminal(sidebar, sessionId) {
2714
+ const before = new Set(sidebar.tabsIn(sessionId).map((tab) => tab.id));
2715
+ sidebar.openTabIn(sessionId, TERMINAL_KIND2);
2716
+ const opened = sidebar.tabsIn(sessionId).find((tab) => tab.kind === TERMINAL_KIND2 && !before.has(tab.id));
2717
+ if (opened === void 0) throw new Error(OPEN_FAILED);
2718
+ return opened;
2719
+ }
2720
+ function createLaunchRunner(sidebar, terminals, timeoutMs = ATTACH_TIMEOUT_MS) {
2721
+ let owned = /* @__PURE__ */ new Map();
2722
+ return {
2723
+ async run(sessionId, script) {
2724
+ const key = `${sessionId}
2725
+ ${script.id}`;
2726
+ const previous = owned.get(key);
2727
+ if (previous !== void 0 && sidebar.tabsIn(sessionId).some((tab2) => tab2.id === previous)) {
2728
+ sidebar.closeIn(sessionId, previous);
2729
+ }
2730
+ const tab = openFreshTerminal(sidebar, sessionId);
2731
+ owned = new Map(owned).set(key, tab.id);
2732
+ const view = terminals.view(sessionId, tab.id, tab.contentId);
2733
+ await whenWritable(view, timeoutMs);
2734
+ view.write(shellInput(script.command));
2735
+ view.rename(scriptLabel(script)).catch(() => {
2736
+ });
2737
+ }
2738
+ };
2739
+ }
2740
+
2741
+ // src/client/launch-script-entry.tsx
2742
+ var import_react14 = require("react");
2743
+ var import_dsh_client_ui_primitives10 = require("@deepseek-ai/dsh-client-ui-primitives");
2744
+
2745
+ // src/client/launch-script-dialog.tsx
2746
+ var import_dsh_client_ui_primitives9 = require("@deepseek-ai/dsh-client-ui-primitives");
2747
+
2748
+ // src/client/launch-script-form.tsx
2749
+ var import_react12 = require("react");
2750
+ var import_dsh_client_ui_primitives7 = require("@deepseek-ai/dsh-client-ui-primitives");
2751
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2752
+ var NAME_LABEL = "\u540D\u79F0";
2753
+ var NAME_PLACEHOLDER = "\u4F8B\u5982\uFF1A\u5F00\u53D1\u670D\u52A1\u5668\uFF08\u53EF\u7559\u7A7A\uFF09";
2754
+ var COMMAND_LABEL = "\u547D\u4EE4";
2755
+ var COMMAND_PLACEHOLDER = "npm run dev";
2756
+ var COMMAND_HINT = "\u5728\u4F1A\u8BDD\u7684\u5DE5\u4F5C\u76EE\u5F55\u4E0B\u6267\u884C\u3002\u591A\u884C\u547D\u4EE4\u4F1A\u9010\u884C\u6267\u884C\u3002\u2318/Ctrl + Enter \u4FDD\u5B58\u3002";
2757
+ function useScriptForm(initial) {
2758
+ const [draft, setDraft] = (0, import_react12.useState)(initial);
2759
+ return {
2760
+ draft,
2761
+ problem: draftProblem(draft),
2762
+ setName: (name) => {
2763
+ setDraft((current) => ({ ...current, name }));
2764
+ },
2765
+ setCommand: (command) => {
2766
+ setDraft((current) => ({ ...current, command }));
2767
+ }
2768
+ };
2769
+ }
2770
+ function CommandField(props) {
2771
+ const commandId = (0, import_react12.useId)();
2772
+ const hintId = (0, import_react12.useId)();
2773
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: LS.field, children: [
2774
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: LS.label, htmlFor: commandId, children: COMMAND_LABEL }),
2775
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2776
+ "textarea",
2777
+ {
2778
+ id: commandId,
2779
+ className: LS.textarea,
2780
+ rows: 3,
2781
+ "data-modal-autofocus": "",
2782
+ spellCheck: false,
2783
+ autoCapitalize: "off",
2784
+ autoCorrect: "off",
2785
+ "aria-describedby": hintId,
2786
+ value: props.command,
2787
+ placeholder: COMMAND_PLACEHOLDER,
2788
+ onChange: (event) => {
2789
+ props.onChange(event.currentTarget.value);
2790
+ }
2791
+ }
2792
+ ),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { id: hintId, className: LS.hint, children: COMMAND_HINT })
2794
+ ] });
2795
+ }
2796
+ function LaunchScriptForm(props) {
2797
+ const { form, error, onSubmit } = props;
2798
+ const nameId = (0, import_react12.useId)();
2799
+ const submitOnShortcut = (event) => {
2800
+ if (event.key !== "Enter" || !(event.metaKey || event.ctrlKey) || event.nativeEvent.isComposing) return;
2801
+ event.preventDefault();
2802
+ onSubmit();
2803
+ };
2804
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: LS.form, onKeyDown: submitOnShortcut, children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: LS.field, children: [
2806
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("label", { className: LS.label, htmlFor: nameId, children: NAME_LABEL }),
2807
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2808
+ import_dsh_client_ui_primitives7.Input,
2809
+ {
2810
+ id: nameId,
2811
+ value: form.draft.name,
2812
+ maxLength: MAX_NAME_LENGTH,
2813
+ placeholder: NAME_PLACEHOLDER,
2814
+ onChange: (event) => {
2815
+ form.setName(event.currentTarget.value);
2816
+ }
2817
+ }
2818
+ )
2819
+ ] }),
2820
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CommandField, { command: form.draft.command, onChange: form.setCommand }),
2821
+ error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { role: "alert", className: LS.error, children: error })
2822
+ ] });
2823
+ }
2824
+
2825
+ // src/client/launch-script-list.tsx
2826
+ var import_react13 = require("react");
2827
+ var import_dsh_client_ui_primitives8 = require("@deepseek-ai/dsh-client-ui-primitives");
2828
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2829
+ var DEFAULT_BADGE2 = "\u9ED8\u8BA4";
2830
+ var RUN = "\u8FD0\u884C";
2831
+ var EDIT = "\u7F16\u8F91";
2832
+ var MAKE_DEFAULT = "\u8BBE\u4E3A\u9ED8\u8BA4";
2833
+ var DELETE = "\u5220\u9664";
2834
+ var CONFIRM_DELETE = "\u518D\u70B9\u4E00\u6B21\u5220\u9664";
2835
+ var EMPTY_TEXT = "\u8FD8\u6CA1\u6709\u542F\u52A8\u811A\u672C\u3002\u6DFB\u52A0\u4E00\u6761\u5E38\u7528\u547D\u4EE4\uFF0C\u4F8B\u5982\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668\uFF0C\u4E4B\u540E\u5728\u6807\u9898\u680F\u4E00\u952E\u8FD0\u884C\u3002";
2836
+ var TOOLTIP_DELAY_MS2 = 500;
2837
+ function RowButton(props) {
2838
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_dsh_client_ui_primitives8.Tooltip, { label: props.label, side: "top", delayMs: TOOLTIP_DELAY_MS2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2839
+ import_dsh_client_ui_primitives8.Button,
2840
+ {
2841
+ size: "sm",
2842
+ className: LS.iconButton,
2843
+ "aria-label": props.label,
2844
+ "data-danger": props.danger === true ? "" : void 0,
2845
+ onClick: props.onClick,
2846
+ children: props.children
2847
+ }
2848
+ ) });
2849
+ }
2850
+ function RowActions2(props) {
2851
+ const { script, first, actions, confirming, onConfirm } = props;
2852
+ const label = scriptLabel(script);
2853
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: LS.rowActions, children: [
2854
+ first ? null : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2855
+ import_dsh_client_ui_primitives8.Button,
2856
+ {
2857
+ size: "sm",
2858
+ onClick: () => {
2859
+ actions.onPromote(script);
2860
+ },
2861
+ children: MAKE_DEFAULT
2862
+ }
2863
+ ),
2864
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RowButton, { label: `${RUN} ${label}`, onClick: () => actions.onRun(script), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_dsh_client_ui_primitives8.IconPlayOutlineRegular, {}) }),
2865
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RowButton, { label: `${EDIT} ${label}`, onClick: () => actions.onEdit(script), children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_dsh_client_ui_primitives8.IconEditOutlineRegular, {}) }),
2866
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2867
+ RowButton,
2868
+ {
2869
+ label: confirming ? CONFIRM_DELETE : `${DELETE} ${label}`,
2870
+ danger: confirming,
2871
+ onClick: () => {
2872
+ if (confirming) actions.onRemove(script);
2873
+ else onConfirm();
2874
+ },
2875
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_dsh_client_ui_primitives8.IconTrashOutlineRegular, {})
2876
+ }
2877
+ )
2878
+ ] });
2879
+ }
2880
+ function ScriptRow(props) {
2881
+ const { script, first } = props;
2882
+ const [confirming, setConfirming] = (0, import_react13.useState)(false);
2883
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2884
+ "li",
2885
+ {
2886
+ className: LS.row,
2887
+ onMouseLeave: () => {
2888
+ setConfirming(false);
2889
+ },
2890
+ children: [
2891
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: LS.rowText, children: [
2892
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: LS.rowName, children: [
2893
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: scriptLabel(script) }),
2894
+ first ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: LS.badge, children: DEFAULT_BADGE2 }) : null
2895
+ ] }),
2896
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: LS.rowCommand, title: script.command, children: script.command })
2897
+ ] }),
2898
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2899
+ RowActions2,
2900
+ {
2901
+ ...props,
2902
+ confirming,
2903
+ onConfirm: () => {
2904
+ setConfirming(true);
2905
+ }
2906
+ }
2907
+ )
2908
+ ]
2909
+ }
2910
+ );
2911
+ }
2912
+ function LaunchScriptList(props) {
2913
+ if (props.scripts.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: LS.empty, children: EMPTY_TEXT });
2914
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ul", { className: LS.list, children: props.scripts.map((script, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ScriptRow, { script, first: index === 0, actions: props.actions }, script.id)) });
2915
+ }
2916
+
2917
+ // src/client/launch-script-dialog.tsx
2918
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2919
+ var TITLE2 = "\u542F\u52A8\u811A\u672C";
2920
+ var ADD_TITLE = "\u6DFB\u52A0\u542F\u52A8\u811A\u672C";
2921
+ var EDIT_TITLE = "\u7F16\u8F91\u542F\u52A8\u811A\u672C";
2922
+ var DESCRIPTION2 = "\u4FDD\u5B58\u5728\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u4E0B\uFF0C\u6240\u6709\u4F1A\u8BDD\u5171\u7528\u3002\u6BCF\u4E2A\u811A\u672C\u5728\u72EC\u7ACB\u7684\u7EC8\u7AEF\u6807\u7B7E\u91CC\u8FD0\u884C\uFF0C\u518D\u6B21\u8FD0\u884C\u4F1A\u5148\u7ED3\u675F\u4E0A\u4E00\u6B21\u3002";
2923
+ var CLOSE = "\u5173\u95ED";
2924
+ var ADD = "\u6DFB\u52A0\u811A\u672C";
2925
+ var DONE = "\u5B8C\u6210";
2926
+ var CANCEL = "\u53D6\u6D88";
2927
+ var BACK = "\u8FD4\u56DE";
2928
+ var SAVE = "\u4FDD\u5B58";
2929
+ var LIST_PAGE = { kind: "list" };
2930
+ var NEW_SCRIPT_PAGE = { kind: "form", draft: { name: "", command: "" } };
2931
+ function FormPage(props) {
2932
+ const { draft, scripts, error, onPage, onChange, onClose, newId } = props;
2933
+ const form = useScriptForm(draft);
2934
+ const backToList = scripts.length > 0;
2935
+ const submit = () => {
2936
+ if (form.problem !== void 0) return;
2937
+ onChange(saveDraft(scripts, form.draft, newId));
2938
+ onPage(LIST_PAGE);
2939
+ };
2940
+ const shown = error ?? (form.draft.command.trim() === "" ? void 0 : form.problem);
2941
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2942
+ import_dsh_client_ui_primitives9.Modal,
2943
+ {
2944
+ open: true,
2945
+ title: draft.id === void 0 ? ADD_TITLE : EDIT_TITLE,
2946
+ closeLabel: CLOSE,
2947
+ className: LS.dialog,
2948
+ onClose,
2949
+ footer: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: LS.footer, children: [
2950
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_dsh_client_ui_primitives9.Button, { variant: "ghost", onClick: backToList ? () => onPage(LIST_PAGE) : onClose, children: backToList ? BACK : CANCEL }),
2951
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_dsh_client_ui_primitives9.Button, { variant: "primary", disabled: form.problem !== void 0, onClick: submit, children: SAVE })
2952
+ ] }),
2953
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(LaunchScriptForm, { form, error: shown, onSubmit: submit })
2954
+ }
2955
+ );
2956
+ }
2957
+ function ListPage(props) {
2958
+ const { scripts, error, onPage, onChange, onRun, onClose } = props;
2959
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
2960
+ import_dsh_client_ui_primitives9.Modal,
2961
+ {
2962
+ open: true,
2963
+ title: TITLE2,
2964
+ description: DESCRIPTION2,
2965
+ closeLabel: CLOSE,
2966
+ className: LS.dialog,
2967
+ onClose,
2968
+ footer: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: LS.footer, children: [
2969
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2970
+ import_dsh_client_ui_primitives9.Button,
2971
+ {
2972
+ "data-leading": "",
2973
+ variant: "outline",
2974
+ icon: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_dsh_client_ui_primitives9.IconPlusOutlineRegular, { size: 14 }),
2975
+ onClick: () => onPage(NEW_SCRIPT_PAGE),
2976
+ children: ADD
2977
+ }
2978
+ ),
2979
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_dsh_client_ui_primitives9.Button, { variant: "primary", onClick: onClose, children: DONE })
2980
+ ] }),
2981
+ children: [
2982
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2983
+ LaunchScriptList,
2984
+ {
2985
+ scripts,
2986
+ actions: {
2987
+ onRun,
2988
+ onEdit: (script) => onPage({ kind: "form", draft: script }),
2989
+ onPromote: (script) => onChange(promoteScript(scripts, script.id)),
2990
+ onRemove: (script) => onChange(removeScript(scripts, script.id))
2991
+ }
2992
+ }
2993
+ ),
2994
+ error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { role: "alert", className: LS.error, children: error })
2995
+ ]
2996
+ }
2997
+ );
2998
+ }
2999
+ function LaunchScriptDialog(props) {
3000
+ const { page } = props;
3001
+ if (page.kind === "list") return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ListPage, { ...props });
3002
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(FormPage, { ...props, draft: page.draft }, page.draft.id ?? "new");
3003
+ }
3004
+
3005
+ // src/client/launch-script-entry.tsx
3006
+ var import_jsx_runtime17 = require("react/jsx-runtime");
3007
+ var MANAGE_ID = "dsh-ccgui.launch-scripts.manage";
3008
+ var SET_UP = "\u8BBE\u7F6E\u542F\u52A8\u811A\u672C";
3009
+ var RUN_PREFIX = "\u8FD0\u884C\uFF1A";
3010
+ var MORE = "\u542F\u52A8\u811A\u672C";
3011
+ var MANAGE = "\u7BA1\u7406\u542F\u52A8\u811A\u672C\u2026";
3012
+ var SAVE_FAILED = "\u6CA1\u80FD\u4FDD\u5B58\u542F\u52A8\u811A\u672C";
3013
+ var TOOLTIP_DELAY_MS3 = 500;
3014
+ function message(error) {
3015
+ return error instanceof Error ? error.message : String(error);
3016
+ }
3017
+ function useWorkspaceScripts(list, book, sessionId) {
3018
+ const subscribeList = (0, import_react14.useCallback)((listener) => list.subscribe(listener), [list]);
3019
+ const cwd = (0, import_react14.useSyncExternalStore)(subscribeList, () => list.getSnapshot().byId[sessionId]?.cwd);
3020
+ const subscribeBook = (0, import_react14.useCallback)((listener) => book.subscribe(listener), [book]);
3021
+ const scripts = (0, import_react14.useSyncExternalStore)(subscribeBook, () => book.read(cwd));
3022
+ return { cwd, scripts };
3023
+ }
3024
+ function MenuRow({ script }) {
3025
+ const label = scriptLabel(script);
3026
+ const command = script.command.trim();
3027
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: LS.menuRow, children: [
3028
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: LS.menuName, children: label }),
3029
+ command === label ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: LS.menuCommand, children: command })
3030
+ ] });
3031
+ }
3032
+ function menuItems(scripts) {
3033
+ return [
3034
+ ...scripts.map((script) => ({
3035
+ id: script.id,
3036
+ label: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(MenuRow, { script }),
3037
+ icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.IconPlayOutlineRegular, { size: 14 })
3038
+ })),
3039
+ { id: MANAGE_ID, label: MANAGE, icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.IconSettingsOutlineRegular, { size: 14 }) }
3040
+ ];
3041
+ }
3042
+ function useLaunchActions({ sessionId, list, book, runner }) {
3043
+ const { cwd, scripts } = useWorkspaceScripts(list, book, sessionId);
3044
+ const [page, setPage] = (0, import_react14.useState)();
3045
+ const [toast, setToast] = (0, import_react14.useState)();
3046
+ const [saveError, setSaveError] = (0, import_react14.useState)();
3047
+ const openPage = (next) => {
3048
+ setSaveError(void 0);
3049
+ setPage(next);
3050
+ };
3051
+ const run = (script) => {
3052
+ openPage(void 0);
3053
+ runner.run(sessionId, script).catch((error) => {
3054
+ setToast(`\u6CA1\u80FD\u8FD0\u884C\u300C${scriptLabel(script)}\u300D\uFF1A${message(error)}`);
3055
+ });
3056
+ };
3057
+ const change = (next) => {
3058
+ try {
3059
+ book.write(cwd, next);
3060
+ setSaveError(void 0);
3061
+ } catch (error) {
3062
+ setSaveError(`${SAVE_FAILED}\uFF1A${message(error)}`);
3063
+ }
3064
+ };
3065
+ return { scripts, page, toast, saveError, openPage, run, change, clearToast: () => setToast(void 0) };
3066
+ }
3067
+ function RunButton(props) {
3068
+ const label = props.primary === void 0 ? SET_UP : `${RUN_PREFIX}${scriptLabel(props.primary)}`;
3069
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.Tooltip, { label, side: "bottom", delayMs: TOOLTIP_DELAY_MS3, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3070
+ import_dsh_client_ui_primitives10.Button,
3071
+ {
3072
+ size: "sm",
3073
+ className: LS.run,
3074
+ "aria-label": label,
3075
+ "data-has-more": props.primary === void 0 ? void 0 : "",
3076
+ onClick: props.onClick,
3077
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.IconPlayOutlineRegular, {})
3078
+ }
3079
+ ) });
3080
+ }
3081
+ function ScriptMenu(props) {
3082
+ const [open, setOpen] = (0, import_react14.useState)(false);
3083
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3084
+ import_dsh_client_ui_primitives10.Menu,
3085
+ {
3086
+ open,
3087
+ items: menuItems(props.scripts),
3088
+ onSelect: (id) => {
3089
+ setOpen(false);
3090
+ const chosen = props.scripts.find((script) => script.id === id);
3091
+ if (chosen === void 0) props.onManage();
3092
+ else props.onRun(chosen);
3093
+ },
3094
+ onClose: () => {
3095
+ setOpen(false);
3096
+ },
3097
+ portal: true,
3098
+ anchor: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3099
+ import_dsh_client_ui_primitives10.Button,
3100
+ {
3101
+ size: "sm",
3102
+ className: LS.more,
3103
+ "aria-label": MORE,
3104
+ "aria-haspopup": "menu",
3105
+ "aria-expanded": open,
3106
+ onClick: () => {
3107
+ setOpen((value) => !value);
3108
+ },
3109
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.IconChevronDownOutlineRegular, {})
3110
+ }
3111
+ )
3112
+ }
3113
+ );
3114
+ }
3115
+ function LaunchScriptEntry(props) {
3116
+ const { scripts, page, toast, saveError, openPage, run, change, clearToast } = useLaunchActions(props);
3117
+ const [anchor, setAnchor] = (0, import_react14.useState)(null);
3118
+ const primary = scripts[0];
3119
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: LS.group, ref: setAnchor, children: [
3120
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3121
+ RunButton,
3122
+ {
3123
+ primary,
3124
+ onClick: () => {
3125
+ if (primary === void 0) openPage(NEW_SCRIPT_PAGE);
3126
+ else run(primary);
3127
+ }
3128
+ }
3129
+ ),
3130
+ primary === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ScriptMenu, { scripts, onRun: run, onManage: () => openPage(LIST_PAGE) }),
3131
+ page === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3132
+ LaunchScriptDialog,
3133
+ {
3134
+ page,
3135
+ scripts,
3136
+ error: saveError,
3137
+ onPage: openPage,
3138
+ onChange: change,
3139
+ onRun: run,
3140
+ onClose: () => {
3141
+ openPage(void 0);
3142
+ },
3143
+ newId: props.newId
3144
+ }
3145
+ ),
3146
+ toast === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_dsh_client_ui_primitives10.Toast, { text: toast, anchor, onDone: clearToast })
3147
+ ] });
3148
+ }
3149
+
3150
+ // src/client/launch-script-register.ts
3151
+ var SLOT2 = "conversation.session.header.utilities";
3152
+ var ENTRY_ORDER2 = -2;
3153
+ function registerLaunchScripts(ctx, list, storage, newId) {
3154
+ ctx.inject(["sidebarRight", "webTerminals"], (child) => {
3155
+ const book = createScriptBook(storage);
3156
+ const runner = createLaunchRunner(child.sidebarRight, child.webTerminals);
3157
+ child.slots.inject(
3158
+ SLOT2,
3159
+ () => child.slots.register(
3160
+ {
3161
+ name: SLOT2,
3162
+ id: "dsh-ccgui.launch-scripts",
3163
+ order: ENTRY_ORDER2,
3164
+ inject: () => ({ list, book, runner, newId })
3165
+ },
3166
+ LaunchScriptEntry
3167
+ )
3168
+ );
3169
+ });
3170
+ }
3171
+
3172
+ // src/client/feature-settings.ts
3173
+ var FEATURES_STORAGE_KEY = "dsh-ccgui.features";
3174
+ var FEATURES = [
3175
+ {
3176
+ id: "filesDefault",
3177
+ title: "\u53F3\u4FA7\u680F\u9ED8\u8BA4\u6253\u5F00\u5DE5\u4F5C\u533A\u6587\u4EF6",
3178
+ description: "\u5C55\u5F00\u53F3\u4FA7\u680F\u65F6\u76F4\u63A5\u663E\u793A\u5DE5\u4F5C\u533A\u6587\u4EF6\u3002\u5173\u95ED\u540E\u6062\u590D\u663E\u793A\u300C\u5F00\u59CB\u300D\u5F15\u5BFC\u9875\u3002"
3179
+ },
3180
+ {
3181
+ id: "gitChanges",
3182
+ title: "\u53F3\u4FA7\u680F\u7684\u53D8\u66F4\u9875",
3183
+ description: "\u5728\u53F3\u4FA7\u680F\u67E5\u770B\u3001\u6682\u5B58\u5E76\u63D0\u4EA4 Git \u53D8\u66F4\uFF0C\u548C\u5DE5\u4F5C\u533A\u6587\u4EF6\u4E00\u8D77\u6253\u5F00\u3002\u5173\u95ED\u540E\u79FB\u9664\u8FD9\u4E2A\u9875\u9762\u3002"
3184
+ },
3185
+ {
3186
+ id: "compactTabs",
3187
+ title: "\u53F3\u4FA7\u680F\u7D27\u51D1\u9875\u7B7E",
3188
+ description: "\u53F3\u4FA7\u680F\u7684\u9875\u7B7E\u53EA\u663E\u793A\u56FE\u6807\uFF0C\u60AC\u505C\u65F6\u663E\u793A\u540D\u79F0\u548C\u5173\u95ED\u6309\u94AE\u3002\u5173\u95ED\u540E\u6062\u590D\u56FE\u6807\u52A0\u6587\u5B57\u7684\u5BBD\u9875\u7B7E\u3002"
3189
+ },
3190
+ {
3191
+ id: "terminalEntry",
3192
+ title: "\u4F1A\u8BDD\u9876\u90E8\u7684\u7EC8\u7AEF\u6309\u94AE",
3193
+ description: "\u5728\u4F1A\u8BDD\u6807\u9898\u680F\u4E00\u952E\u6253\u5F00\u6216\u6536\u8D77\u7EC8\u7AEF\u3002\u5173\u95ED\u540E\u4ECE\u53F3\u4FA7\u680F\u6253\u5F00\u7EC8\u7AEF\u3002"
3194
+ },
3195
+ {
3196
+ id: "launchScripts",
3197
+ title: "\u4F1A\u8BDD\u9876\u90E8\u7684\u542F\u52A8\u811A\u672C",
3198
+ description: "\u5728\u4F1A\u8BDD\u6807\u9898\u680F\u4FDD\u5B58\u5E76\u4E00\u952E\u8FD0\u884C\u5E38\u7528\u547D\u4EE4\u3002\u5173\u95ED\u53EA\u9690\u85CF\u5165\u53E3\uFF0C\u5DF2\u4FDD\u5B58\u7684\u811A\u672C\u4F1A\u4FDD\u7559\u3002"
3199
+ }
3200
+ ];
3201
+ var DEFAULT_FLAGS = {
3202
+ filesDefault: true,
3203
+ gitChanges: true,
3204
+ compactTabs: true,
3205
+ terminalEntry: true,
3206
+ launchScripts: true
3207
+ };
3208
+ function isRecord3(value) {
3209
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3210
+ }
3211
+ function parseFlags(raw) {
3212
+ if (raw === null) return DEFAULT_FLAGS;
3213
+ let value;
3214
+ try {
3215
+ value = JSON.parse(raw);
3216
+ } catch (_error) {
3217
+ return DEFAULT_FLAGS;
3218
+ }
3219
+ if (!isRecord3(value)) return DEFAULT_FLAGS;
3220
+ return FEATURES.reduce((flags, { id }) => {
3221
+ const stored = value[id];
3222
+ return typeof stored === "boolean" ? { ...flags, [id]: stored } : flags;
3223
+ }, DEFAULT_FLAGS);
3224
+ }
3225
+ function readFlags(storage) {
3226
+ try {
3227
+ return parseFlags(storage.getItem(FEATURES_STORAGE_KEY));
3228
+ } catch (_error) {
3229
+ return DEFAULT_FLAGS;
3230
+ }
3231
+ }
3232
+ function createFeatureSettings(storage) {
3233
+ let flags = readFlags(storage);
3234
+ let listeners = [];
3235
+ return {
3236
+ getSnapshot: () => flags,
3237
+ subscribe(listener) {
3238
+ listeners = [...listeners, listener];
3239
+ return () => {
3240
+ listeners = listeners.filter((candidate) => candidate !== listener);
3241
+ };
3242
+ },
3243
+ set(id, enabled) {
3244
+ if (flags[id] === enabled) return;
3245
+ flags = { ...flags, [id]: enabled };
3246
+ try {
3247
+ storage.setItem(FEATURES_STORAGE_KEY, JSON.stringify(flags));
3248
+ } catch (_error) {
3249
+ }
3250
+ for (const listener of listeners) listener();
3251
+ }
3252
+ };
3253
+ }
3254
+ function whileEnabled(settings, id, install) {
3255
+ let uninstall;
3256
+ const reconcile = () => {
3257
+ const enabled = settings.getSnapshot()[id];
3258
+ if (enabled && uninstall === void 0) uninstall = install();
3259
+ if (!enabled && uninstall !== void 0) {
3260
+ const current = uninstall;
3261
+ uninstall = void 0;
3262
+ current();
3263
+ }
3264
+ };
3265
+ reconcile();
3266
+ const unsubscribe = settings.subscribe(reconcile);
3267
+ return () => {
3268
+ unsubscribe();
3269
+ uninstall?.();
3270
+ uninstall = void 0;
3271
+ };
3272
+ }
3273
+
3274
+ // src/client/compact-tabs.ts
3275
+ var CHIP = "[data-dockkit-tab]";
3276
+ var TITLE3 = "[data-dockkit-tab-title]";
3277
+ var CLOSE2 = "[data-dockkit-tab-close]";
3278
+ var SIDEBAR_TITLE = `${TITLE3} > [data-sidebar-right-tab]`;
3279
+ var TIP_ATTR = "data-dsh-ccgui-tab-tip";
3280
+ var CLOSE_ROOM_PX = 28;
3281
+ var GLYPH_PX = 16;
3282
+ var TIP_GAP_PX = 8;
3283
+ var TIP_MARGIN_PX = 12;
3284
+ var SIDEBAR_CHIP = `${CHIP}:has(> ${SIDEBAR_TITLE})`;
3285
+ var ICON_CHIP = `${SIDEBAR_CHIP}:has(${TITLE3} :is(svg, img)):not(:has(${TITLE3} input))`;
3286
+ var COMPACT_TABS_STYLES = `
3287
+ ${SIDEBAR_CHIP} { min-width: 0; max-width: 128px; padding: 0 8px; }
3288
+ ${ICON_CHIP} { flex: none; max-width: none; padding: 0 6px; }
3289
+ ${ICON_CHIP}[aria-selected="true"]:has(${CLOSE2}) { padding-right: ${String(CLOSE_ROOM_PX)}px; }
3290
+ ${ICON_CHIP} > ${TITLE3} {
3291
+ flex: none;
3292
+ width: ${String(GLYPH_PX)}px;
3293
+ overflow: hidden;
3294
+ white-space: nowrap;
3295
+ mask-image: none;
3296
+ }
3297
+ ${ICON_CHIP} > ${TITLE3} :is(svg, img) { flex: none; }
3298
+ ${ICON_CHIP}:not([aria-selected="true"]) ${CLOSE2} { opacity: 0; pointer-events: none; }
3299
+ [${TIP_ATTR}] {
3300
+ position: fixed;
3301
+ z-index: 1100;
3302
+ box-sizing: border-box;
3303
+ width: max-content;
3304
+ max-width: min(50vw, calc(100vw - 24px));
3305
+ padding: 3px 7px;
3306
+ border-radius: var(--dsw-radius-sm);
3307
+ background: var(--dsw-alias-tooltip-bg);
3308
+ color: var(--dsw-static-neutral-bluish-00);
3309
+ font-size: 13px;
3310
+ line-height: 20px;
3311
+ white-space: pre-line;
3312
+ overflow-wrap: break-word;
3313
+ pointer-events: none;
3314
+ transform: translateX(-50%);
3315
+ }
3316
+ `;
3317
+ function tipPlacement(tip, chip, viewport) {
3318
+ const rect = chip.getBoundingClientRect();
3319
+ const width = tip.getBoundingClientRect().width;
3320
+ const center = Math.min(
3321
+ Math.max(rect.left + rect.width / 2, TIP_MARGIN_PX + width / 2),
3322
+ viewport - TIP_MARGIN_PX - width / 2
3323
+ );
3324
+ return { left: `${String(center)}px`, top: `${String(rect.bottom + TIP_GAP_PX)}px` };
3325
+ }
3326
+ function createCompactTip(doc) {
3327
+ const tip = doc.createElement("div");
3328
+ tip.setAttribute("role", "tooltip");
3329
+ tip.setAttribute(TIP_ATTR, "");
3330
+ tip.hidden = true;
3331
+ let owner;
3332
+ const hide = () => {
3333
+ owner = void 0;
3334
+ tip.hidden = true;
3335
+ tip.remove();
3336
+ };
3337
+ const show = (chip) => {
3338
+ const name = chip.querySelector(TITLE3)?.textContent.trim() ?? "";
3339
+ if (name === "") {
3340
+ hide();
3341
+ return;
3342
+ }
3343
+ owner = chip;
3344
+ tip.textContent = name;
3345
+ tip.hidden = false;
3346
+ doc.body.append(tip);
3347
+ const { left, top } = tipPlacement(tip, chip, doc.defaultView?.innerWidth ?? 0);
3348
+ tip.style.left = left;
3349
+ tip.style.top = top;
3350
+ };
3351
+ const onPointerOver = (event) => {
3352
+ const target = event.target;
3353
+ if (!(target instanceof Element)) return;
3354
+ const chip = target.closest(CHIP);
3355
+ if (chip?.matches(ICON_CHIP) === true) {
3356
+ if (chip !== owner) show(chip);
3357
+ return;
3358
+ }
3359
+ if (!owner?.contains(target)) hide();
3360
+ };
3361
+ const onPointerOut = (event) => {
3362
+ if (owner === void 0) return;
3363
+ const to = event.relatedTarget;
3364
+ if (to instanceof Node && owner.contains(to)) return;
3365
+ hide();
3366
+ };
3367
+ const onFocusIn = (event) => {
3368
+ const target = event.target;
3369
+ if (!(target instanceof Element)) return;
3370
+ const chip = target.closest(CHIP);
3371
+ if (chip?.matches(ICON_CHIP) === true) show(chip);
3372
+ };
3373
+ return { hide, onPointerOver, onPointerOut, onFocusIn };
3374
+ }
3375
+ function installCompactTabs(doc) {
3376
+ const tag = doc.createElement("style");
3377
+ tag.dataset.plugin = "dsh-ccgui.compact-tabs";
3378
+ tag.textContent = COMPACT_TABS_STYLES;
3379
+ doc.head.append(tag);
3380
+ const tip = createCompactTip(doc);
3381
+ doc.addEventListener("pointerover", tip.onPointerOver, true);
3382
+ doc.addEventListener("pointerout", tip.onPointerOut, true);
3383
+ doc.addEventListener("focusin", tip.onFocusIn, true);
3384
+ doc.addEventListener("focusout", tip.hide, true);
3385
+ doc.addEventListener("pointerdown", tip.hide, true);
3386
+ doc.addEventListener("scroll", tip.hide, true);
3387
+ doc.defaultView?.addEventListener("resize", tip.hide);
3388
+ return () => {
3389
+ doc.removeEventListener("pointerover", tip.onPointerOver, true);
3390
+ doc.removeEventListener("pointerout", tip.onPointerOut, true);
3391
+ doc.removeEventListener("focusin", tip.onFocusIn, true);
3392
+ doc.removeEventListener("focusout", tip.hide, true);
3393
+ doc.removeEventListener("pointerdown", tip.hide, true);
3394
+ doc.removeEventListener("scroll", tip.hide, true);
3395
+ doc.defaultView?.removeEventListener("resize", tip.hide);
3396
+ tip.hide();
3397
+ tag.remove();
3398
+ };
3399
+ }
3400
+
3401
+ // src/client/settings-page.tsx
3402
+ var import_dsh_client_ui_primitives13 = require("@deepseek-ai/dsh-client-ui-primitives");
3403
+
3404
+ // src/client/cli-prefs-section.tsx
3405
+ var import_dsh_client_ui_primitives11 = require("@deepseek-ai/dsh-client-ui-primitives");
3406
+ var import_jsx_runtime18 = require("react/jsx-runtime");
3407
+ var SECTION_INTRO = "\u8F93\u5165\u6846 CLI \u5207\u6362\u83DC\u5355\u91CC\u7684\u987A\u5E8F\u548C\u663E\u793A\u7684\u9879\u3002\u5173\u95ED\u7684 CLI \u4E0D\u518D\u51FA\u73B0\u5728\u83DC\u5355\u4E2D\u3002";
3408
+ var EMPTY_HINT = "\u6253\u5F00\u4EFB\u4E00\u4F1A\u8BDD\u540E\uFF0C\u8FD9\u91CC\u4F1A\u5217\u51FA\u53EF\u5207\u6362\u7684 CLI\u3002";
3409
+ var OFF_HINT = "\u5DF2\u5173\u95ED\uFF0C\u4E0D\u5728 CLI \u83DC\u5355\u4E2D\u663E\u793A";
3410
+ var LOCKED_HINT = "\u5185\u7F6E\u63D0\u4F9B\u65B9\uFF0C\u59CB\u7EC8\u663E\u793A";
3411
+ var SWITCH_ON_TITLE = "\u5173\u95ED\u540E\u4E0D\u518D\u51FA\u73B0\u5728 CLI \u83DC\u5355";
3412
+ var SWITCH_OFF_TITLE = "\u5F00\u542F\u540E\u91CD\u65B0\u51FA\u73B0\u5728 CLI \u83DC\u5355";
3413
+ var MORE_CLIS_HINT = "\u66F4\u591A CLI \u9002\u914D\u4E2D\u2026";
3414
+ var MARK_SIZE2 = 16;
3415
+ var ARROW_SIZE = 14;
3416
+ var SECTION_CLASS = "dsh-ccgui-cli-prefs";
3417
+ var CLI_PREFS_STYLES = `
3418
+ .${SECTION_CLASS} { margin: 0; }
3419
+ .${SECTION_CLASS}-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; }
3420
+ .${SECTION_CLASS}-row + .${SECTION_CLASS}-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }
3421
+ .${SECTION_CLASS}-name { flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0; color: var(--dsw-alias-label-primary); font-size: 13px; line-height: 20px; }
3422
+ .${SECTION_CLASS}-off { color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-size: 12px; line-height: 18px; }
3423
+ .${SECTION_CLASS}-locked { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-size: 12px; line-height: 18px; }
3424
+ .${SECTION_CLASS}-moves { display: flex; gap: 2px; }
3425
+ .${SECTION_CLASS}-more { display: flex; align-items: center; gap: 10px; margin: 14px 0 0; color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-size: 12px; line-height: 18px; }
3426
+ .${SECTION_CLASS}-more::before, .${SECTION_CLASS}-more::after { content: ''; flex: 1; border-top: 1px dashed var(--dsw-alias-border-l2); }
3427
+ `;
3428
+ function MoveButtons({
3429
+ entry,
3430
+ first,
3431
+ last,
3432
+ prefs
3433
+ }) {
3434
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `${SECTION_CLASS}-moves`, children: [
3435
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3436
+ import_dsh_client_ui_primitives11.Button,
3437
+ {
3438
+ size: "sm",
3439
+ "aria-label": `\u4E0A\u79FB ${entry.label}`,
3440
+ disabled: first,
3441
+ icon: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_dsh_client_ui_primitives11.IconChevronUpOutlineRegular, { size: ARROW_SIZE }),
3442
+ onClick: () => {
3443
+ prefs.move(entry.id, -1);
3444
+ }
3445
+ }
3446
+ ),
3447
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3448
+ import_dsh_client_ui_primitives11.Button,
3449
+ {
3450
+ size: "sm",
3451
+ "aria-label": `\u4E0B\u79FB ${entry.label}`,
3452
+ disabled: last,
3453
+ icon: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_dsh_client_ui_primitives11.IconChevronDownOutlineRegular, { size: ARROW_SIZE }),
3454
+ onClick: () => {
3455
+ prefs.move(entry.id, 1);
3456
+ }
3457
+ }
3458
+ )
3459
+ ] });
3460
+ }
3461
+ function CliRow({
3462
+ entry,
3463
+ first,
3464
+ last,
3465
+ prefs
3466
+ }) {
3467
+ const locked = entry.id === OFFICIAL_PROVIDER_ID;
3468
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: `${SECTION_CLASS}-row`, "aria-label": entry.label, children: [
3469
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: `${SECTION_CLASS}-name`, children: [
3470
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ProviderMark, { provider: entry.id, size: MARK_SIZE2 }),
3471
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: entry.label }),
3472
+ entry.enabled ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `${SECTION_CLASS}-off`, role: "status", children: OFF_HINT })
3473
+ ] }),
3474
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(MoveButtons, { entry, first, last, prefs }),
3475
+ locked ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `${SECTION_CLASS}-locked`, children: LOCKED_HINT }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3476
+ import_dsh_client_ui_primitives11.Switch,
3477
+ {
3478
+ checked: entry.enabled,
3479
+ label: `\u542F\u7528 ${entry.label}`,
3480
+ title: entry.enabled ? SWITCH_ON_TITLE : SWITCH_OFF_TITLE,
3481
+ onChange: (next) => {
3482
+ prefs.setEnabled(entry.id, next);
3483
+ }
3484
+ }
3485
+ )
3486
+ ] });
3487
+ }
3488
+ function CliPrefsSection({ prefs }) {
3489
+ const entries = listedEntries(useStore(prefs));
3490
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: SECTION_CLASS, children: [
3491
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "dsh-ccgui-settings-intro", children: entries.length === 0 ? EMPTY_HINT : SECTION_INTRO }),
3492
+ entries.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "dsh-ccgui-settings-list", children: entries.map((entry, index) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
3493
+ CliRow,
3494
+ {
3495
+ entry,
3496
+ first: index === 0,
3497
+ last: index === entries.length - 1,
3498
+ prefs
3499
+ },
3500
+ entry.id
3501
+ )) }),
3502
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: `${SECTION_CLASS}-more`, children: MORE_CLIS_HINT })
3503
+ ] });
3504
+ }
3505
+
3506
+ // src/client/features-section.tsx
3507
+ var import_dsh_client_ui_primitives12 = require("@deepseek-ai/dsh-client-ui-primitives");
3508
+ var import_jsx_runtime19 = require("react/jsx-runtime");
3509
+ var FEATURES_INTRO = "CC GUI \u5728 DeepSeek Harness \u4E0A\u52A0\u5165\u7684\u4EA4\u4E92\u3002\u5173\u95ED\u67D0\u4E00\u9879\u5373\u6062\u590D\u539F\u6765\u7684\u4EA4\u4E92\uFF0C\u7ACB\u5373\u751F\u6548\u3002";
3510
+ var PAGE_CLASS = "dsh-ccgui-settings";
3511
+ function FeatureRow({
3512
+ feature,
3513
+ enabled,
3514
+ settings
3515
+ }) {
3516
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: `${PAGE_CLASS}-row`, children: [
3517
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
3518
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `${PAGE_CLASS}-title`, children: feature.title }),
3519
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: `${PAGE_CLASS}-desc`, children: feature.description })
3520
+ ] }),
3521
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3522
+ import_dsh_client_ui_primitives12.Switch,
3523
+ {
3524
+ checked: enabled,
3525
+ label: feature.title,
3526
+ onChange: (next) => {
3527
+ settings.set(feature.id, next);
3528
+ }
3529
+ }
3530
+ )
3531
+ ] });
3532
+ }
3533
+ function FeaturesSection({ settings }) {
3534
+ const flags = useStore(settings);
3535
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { children: [
3536
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: `${PAGE_CLASS}-intro`, children: FEATURES_INTRO }),
3537
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ul", { className: `${PAGE_CLASS}-list`, children: FEATURES.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(FeatureRow, { feature, enabled: flags[feature.id], settings }, feature.id)) })
3538
+ ] });
3539
+ }
3540
+
3541
+ // src/client/more-section.tsx
3542
+ var import_jsx_runtime20 = require("react/jsx-runtime");
3543
+ var INTRO = "\u6B63\u5728\u5F00\u53D1\u7684\u529F\u80FD\uFF0C\u4F1A\u9646\u7EED\u5728\u8FD9\u91CC\u5F00\u653E\u3002";
3544
+ var SOON_LABEL = "\u5373\u5C06\u5F00\u653E\u2026";
3545
+ var SOON_CLASS = "dsh-ccgui-more-soon";
3546
+ var UPCOMING_FEATURES = [
3547
+ { id: "autoRename", title: "\u4F1A\u8BDD\u81EA\u52A8\u547D\u540D", description: "\u6839\u636E\u5BF9\u8BDD\u5185\u5BB9\u81EA\u52A8\u751F\u6210\u4F1A\u8BDD\u6807\u9898\uFF0C\u4E0D\u7528\u624B\u52A8\u6539\u540D\u3002" },
3548
+ { id: "worktree", title: "WorkTree", description: "\u4E3A\u6BCF\u4E2A\u4F1A\u8BDD\u5EFA\u7ACB\u72EC\u7ACB\u7684 Git \u5DE5\u4F5C\u6811\uFF0C\u591A\u4E2A\u4EFB\u52A1\u4E92\u4E0D\u5E72\u6270\u3002" },
3549
+ { id: "gitInfo", title: "Git \u4FE1\u606F\u81EA\u52A8\u751F\u6210", description: "\u6839\u636E\u6539\u52A8\u81EA\u52A8\u751F\u6210\u63D0\u4EA4\u4FE1\u606F\u548C\u53D8\u66F4\u8BF4\u660E\u3002" },
3550
+ { id: "promptBoost", title: "\u589E\u5F3A\u63D0\u793A\u8BCD", description: "\u628A\u4E00\u53E5\u8BDD\u6269\u5199\u6210\u5B8C\u6574\u7684\u63D0\u793A\u8BCD\uFF0C\u51CF\u5C11\u6765\u56DE\u8865\u5145\u80CC\u666F\u3002" },
3551
+ {
3552
+ id: "accountQuota",
3553
+ title: "AI \u8D26\u53F7\u9650\u989D\u63D0\u793A",
3554
+ description: "\u663E\u793A\u5404 AI \u8D26\u53F7\u7684\u5269\u4F59\u989D\u5EA6\u548C\u91CD\u7F6E\u65F6\u95F4\uFF0C\u5FEB\u7528\u5B8C\u65F6\u63D0\u524D\u63D0\u9192\u3002"
3555
+ }
3556
+ ];
3557
+ var MORE_SECTION_STYLES = `
3558
+ .${SOON_CLASS} { flex: 0 0 auto; padding: 2px 8px; border: 0.5px solid var(--dsw-alias-border-l2); border-radius: 999px; color: var(--dsw-alias-label-tertiary, var(--dsw-alias-label-secondary)); font-size: 12px; line-height: 18px; }
3559
+ `;
3560
+ function MoreSection() {
3561
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("section", { children: [
3562
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "dsh-ccgui-settings-intro", children: INTRO }),
3563
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("ul", { className: "dsh-ccgui-settings-list", children: UPCOMING_FEATURES.map((feature) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("li", { className: "dsh-ccgui-settings-row", children: [
3564
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
3565
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-ccgui-settings-title", children: feature.title }),
3566
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "dsh-ccgui-settings-desc", children: feature.description })
3567
+ ] }),
3568
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: SOON_CLASS, children: SOON_LABEL })
3569
+ ] }, feature.id)) })
3570
+ ] });
3571
+ }
3572
+
3573
+ // src/client/settings-about.tsx
3574
+ var import_react15 = require("react");
3575
+
3576
+ // src/client/assets/wechat-group.png
3577
+ var wechat_group_default = "data:image/png;base64,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";
3578
+
3579
+ // src/client/settings-about.tsx
3580
+ var import_jsx_runtime21 = require("react/jsx-runtime");
3581
+ var PLUGIN_VERSION = true ? "1.0.0" : "\u5F00\u53D1\u7248";
3582
+ var REPO_URL = "https://github.com/zhukunpenglinyutong/desktop-cc-gui";
3583
+ var VERSION_LABEL = "\u7248\u672C";
3584
+ var VERSION_VALUE = /^\d/.test(PLUGIN_VERSION) ? `v${PLUGIN_VERSION}` : PLUGIN_VERSION;
3585
+ var WECHAT_LABEL = "\u5FAE\u4FE1\u4EA4\u6D41\u7FA4";
3586
+ var WECHAT_DESC = "\u626B\u63CF\u4F5C\u8005\u4E2A\u4EBA\u516C\u4F17\u53F7\u4E8C\u7EF4\u7801\uFF0C\u83B7\u53D6\u5FAE\u4FE1\u4EA4\u6D41\u7FA4\u4E8C\u7EF4\u7801\uFF0C\u52A0\u7FA4\u83B7\u5F97\u6700\u65B0\u8D44\u8BAF\u548C\u6280\u672F\u652F\u6301";
3587
+ var WECHAT_TIP = "\u4F7F\u7528\u5FAE\u4FE1\u626B\u4E00\u626B";
3588
+ var WECHAT_QR_ALT = "\u5B98\u65B9\u5FAE\u4FE1\u4EA4\u6D41\u7FA4\u4E8C\u7EF4\u7801";
3589
+ var QR_SIZE = 160;
3590
+ var ABOUT_CLASS = "dsh-ccgui-about";
3591
+ var SETTINGS_ABOUT_STYLES = `
3592
+ .${ABOUT_CLASS} { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 0; }
3593
+ .${ABOUT_CLASS}-pill { position: relative; display: inline-flex; align-items: center; gap: 6px; box-sizing: border-box; height: 28px; padding: 0 10px; border: 0.5px solid var(--dsw-alias-border-l2); border-radius: 8px; background: var(--dsw-alias-bg-secondary, rgba(127, 127, 127, 0.08)); color: var(--dsw-alias-label-secondary); font: inherit; font-size: 12px; line-height: 18px; text-decoration: none; white-space: nowrap; }
3594
+ .${ABOUT_CLASS}-value { color: var(--dsw-alias-label-primary); font-weight: 500; }
3595
+ button.${ABOUT_CLASS}-pill, a.${ABOUT_CLASS}-pill { cursor: pointer; }
3596
+ button.${ABOUT_CLASS}-pill:hover, a.${ABOUT_CLASS}-pill:hover, .${ABOUT_CLASS}-pill[aria-expanded="true"] { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l3, var(--dsw-alias-border-l2)); }
3597
+ .${ABOUT_CLASS}-anchor { position: relative; }
3598
+ .${ABOUT_CLASS}-qr { position: absolute; top: calc(100% + 8px); left: 0; z-index: 10; width: 240px; padding: 16px; border: 0; border-radius: 12px; background: var(--dsw-alias-bg-layer-1); --dsw-elevation-stroke-color: var(--dsw-alias-border-l1); box-shadow: var(--dsw-elevation-panel); color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; text-align: center; }
3599
+ .${ABOUT_CLASS}-qr p { margin: 0; }
3600
+ .${ABOUT_CLASS}-qr img { display: block; margin: 12px auto 8px; padding: 8px; border-radius: 8px; background: #fff; }
3601
+ `;
3602
+ function useEscape(active, close) {
3603
+ (0, import_react15.useEffect)(() => {
3604
+ if (!active) return void 0;
3605
+ const onKey = (event) => {
3606
+ if (event.key === "Escape") close();
3607
+ };
3608
+ document.addEventListener("keydown", onKey);
3609
+ return () => {
3610
+ document.removeEventListener("keydown", onKey);
3611
+ };
3612
+ }, [active, close]);
3613
+ }
3614
+ function WechatGroup() {
3615
+ const [open, setOpen] = (0, import_react15.useState)(false);
3616
+ useEscape(open, () => {
3617
+ setOpen(false);
3618
+ });
3619
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: `${ABOUT_CLASS}-anchor`, children: [
3620
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3621
+ "button",
3622
+ {
3623
+ type: "button",
3624
+ className: `${ABOUT_CLASS}-pill`,
3625
+ "aria-expanded": open,
3626
+ onClick: () => {
3627
+ setOpen((value) => !value);
3628
+ },
3629
+ children: WECHAT_LABEL
3630
+ }
3631
+ ),
3632
+ open ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: `${ABOUT_CLASS}-qr`, children: [
3633
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: WECHAT_DESC }),
3634
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("img", { src: wechat_group_default, alt: WECHAT_QR_ALT, width: QR_SIZE, height: QR_SIZE }),
3635
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: WECHAT_TIP })
3636
+ ] }) : null
3637
+ ] });
3638
+ }
3639
+ function SettingsAbout() {
3640
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: ABOUT_CLASS, children: [
3641
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: `${ABOUT_CLASS}-pill`, children: [
3642
+ VERSION_LABEL,
3643
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: `${ABOUT_CLASS}-value`, children: VERSION_VALUE })
3644
+ ] }),
3645
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(WechatGroup, {}),
3646
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("a", { className: `${ABOUT_CLASS}-pill`, href: REPO_URL, target: "_blank", rel: "noreferrer", children: "GitHub" })
3647
+ ] });
3648
+ }
3649
+
3650
+ // src/client/settings-tabs.tsx
3651
+ var import_react16 = require("react");
3652
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3653
+ var TABS_CLASS = "dsh-ccgui-tabs";
3654
+ var SETTINGS_TABS_STYLES = `
3655
+ .${TABS_CLASS} { display: flex; gap: 24px; margin: 4px 0 8px; border-bottom: 0.5px solid var(--dsw-alias-border-l2); }
3656
+ .${TABS_CLASS}-tab { position: relative; margin: 0 0 -0.5px; padding: 8px 0; border: none; background: none; color: var(--dsw-alias-label-secondary); font: inherit; font-size: 13px; line-height: 20px; cursor: pointer; }
3657
+ .${TABS_CLASS}-tab:hover { color: var(--dsw-alias-label-primary); }
3658
+ .${TABS_CLASS}-tab[aria-selected="true"] { color: var(--dsw-alias-label-primary); font-weight: 500; }
3659
+ .${TABS_CLASS}-tab[aria-selected="true"]::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; border-radius: 1px; background: var(--dsw-alias-label-primary); }
3660
+ .${TABS_CLASS}-tab:focus-visible { outline: 2px solid var(--dsw-alias-border-focus, currentColor); outline-offset: 2px; border-radius: 4px; }
3661
+ `;
3662
+ function nextIndex(key, index, count) {
3663
+ switch (key) {
3664
+ case "ArrowRight":
3665
+ return (index + 1) % count;
3666
+ case "ArrowLeft":
3667
+ return (index - 1 + count) % count;
3668
+ case "Home":
3669
+ return 0;
3670
+ case "End":
3671
+ return count - 1;
3672
+ default:
3673
+ return void 0;
3674
+ }
3675
+ }
3676
+ function TabButton({
3677
+ tab,
3678
+ prefix,
3679
+ active,
3680
+ onSelect
3681
+ }) {
3682
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3683
+ "button",
3684
+ {
3685
+ type: "button",
3686
+ role: "tab",
3687
+ id: `${prefix}-${tab.id}-tab`,
3688
+ "data-tab": tab.id,
3689
+ className: `${TABS_CLASS}-tab`,
3690
+ "aria-selected": active,
3691
+ "aria-controls": `${prefix}-${tab.id}-panel`,
3692
+ tabIndex: active ? 0 : -1,
3693
+ onClick: onSelect,
3694
+ children: tab.label
3695
+ }
3696
+ );
3697
+ }
3698
+ function SettingsTabs({
3699
+ tabs,
3700
+ label
3701
+ }) {
3702
+ const [selected, setSelected] = (0, import_react16.useState)(tabs[0]?.id);
3703
+ const strip = (0, import_react16.useRef)(null);
3704
+ const prefix = (0, import_react16.useId)();
3705
+ const current = tabs.find((tab) => tab.id === selected) ?? tabs[0];
3706
+ const onKeyDown = (event) => {
3707
+ const index = tabs.findIndex((tab) => tab.id === current?.id);
3708
+ const next = nextIndex(event.key, index, tabs.length);
3709
+ const target = next === void 0 ? void 0 : tabs[next];
3710
+ if (target === void 0) return;
3711
+ event.preventDefault();
3712
+ setSelected(target.id);
3713
+ strip.current?.querySelector(`[data-tab="${target.id}"]`)?.focus();
3714
+ };
3715
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3716
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { ref: strip, className: TABS_CLASS, role: "tablist", "aria-label": label, onKeyDown, children: tabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3717
+ TabButton,
3718
+ {
3719
+ tab,
3720
+ prefix,
3721
+ active: tab.id === current?.id,
3722
+ onSelect: () => {
3723
+ setSelected(tab.id);
3724
+ }
3725
+ },
3726
+ tab.id
3727
+ )) }),
3728
+ current === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "tabpanel", id: `${prefix}-${current.id}-panel`, "aria-labelledby": `${prefix}-${current.id}-tab`, children: current.render() })
3729
+ ] });
3730
+ }
3731
+
3732
+ // src/client/settings-page.tsx
3733
+ var import_jsx_runtime23 = require("react/jsx-runtime");
3734
+ var SETTINGS_TITLE = "CC GUI \u8BBE\u7F6E";
3735
+ var CLI_TAB_LABEL = "CLI \u5217\u8868";
3736
+ var FEATURES_TAB_LABEL = "\u754C\u9762\u4EA4\u4E92";
3737
+ var MORE_TAB_LABEL = "\u66F4\u591A\u529F\u80FD";
3738
+ var PAGE_CLASS2 = "dsh-ccgui-settings";
3739
+ var SETTINGS_PAGE_STYLES = `
3740
+ .${PAGE_CLASS2} { display: flex; flex-direction: column; gap: 12px; box-sizing: border-box; max-width: 720px; color: var(--dsw-alias-label-primary); }
3741
+ .${PAGE_CLASS2}-header { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px; }
3742
+ .${PAGE_CLASS2} h1 { margin: 0; color: var(--dsw-alias-label-primary); font-size: 16px; line-height: 24px; font-weight: 500; }
3743
+ .${PAGE_CLASS2}-intro { margin: 0 0 12px; color: var(--dsw-alias-label-secondary); font-size: 13px; line-height: 20px; }
3744
+ .${PAGE_CLASS2}-list { margin: 0; padding: 0; list-style: none; }
3745
+ /* The host paints an on switch with the brand color, which is near-white in the dark theme;
3746
+ a green track (with a white thumb) reads as "on" at a glance in both themes. */
3747
+ .${PAGE_CLASS2} [role="switch"][aria-checked="true"] { background: var(--dsw-alias-state-success-primary, #2da44e); }
3748
+ .${PAGE_CLASS2} [role="switch"][aria-checked="true"] > span { background: #fff; }
3749
+ .${PAGE_CLASS2}-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 0; }
3750
+ .${PAGE_CLASS2}-row + .${PAGE_CLASS2}-row { border-top: 0.5px solid var(--dsw-alias-border-l2); }
3751
+ .${PAGE_CLASS2}-title { color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 20px; }
3752
+ .${PAGE_CLASS2}-desc { margin-top: 2px; color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; }
3753
+ ${SETTINGS_TABS_STYLES}${CLI_PREFS_STYLES}${SETTINGS_ABOUT_STYLES}${MORE_SECTION_STYLES}`;
3754
+ function SettingsPage({
3755
+ settings,
3756
+ cliPrefs
3757
+ }) {
3758
+ const tabs = [
3759
+ { id: "cli", label: CLI_TAB_LABEL, render: () => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CliPrefsSection, { prefs: cliPrefs }) },
3760
+ { id: "features", label: FEATURES_TAB_LABEL, render: () => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(FeaturesSection, { settings }) },
3761
+ { id: "more", label: MORE_TAB_LABEL, render: () => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(MoreSection, {}) }
3762
+ ];
3763
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: PAGE_CLASS2, children: [
3764
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `${PAGE_CLASS2}-header`, children: [
3765
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { children: SETTINGS_TITLE }),
3766
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SettingsAbout, {})
3767
+ ] }),
3768
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(SettingsTabs, { tabs, label: SETTINGS_TITLE })
3769
+ ] });
3770
+ }
3771
+ function SettingsIcon({ size }) {
3772
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_dsh_client_ui_primitives13.IconSlidersTwoOutlineRegular, { size });
3773
+ }
3774
+
3775
+ // src/client/settings-register.ts
3776
+ var SETTINGS_SECTION_ID = "dsh-ccgui.settings";
3777
+ var SETTINGS_ORDER = 50;
3778
+ function isDisposable(value) {
3779
+ return typeof value === "object" && value !== null && "dispose" in value && typeof value.dispose === "function";
3780
+ }
3781
+ function registerSettingsPage(ctx, settings, cliPrefs) {
3782
+ ctx.slots.inject(
3783
+ "settings.section",
3784
+ () => ctx.slots.register(
3785
+ {
3786
+ name: "settings.section",
3787
+ id: SETTINGS_SECTION_ID,
3788
+ order: SETTINGS_ORDER,
3789
+ label: SETTINGS_TITLE,
3790
+ inject: () => ({ settings, cliPrefs })
3791
+ },
3792
+ SettingsPage
3793
+ )
3794
+ );
3795
+ ctx.slots.inject(
3796
+ "settings.section.icon",
3797
+ () => ctx.slots.register({ name: "settings.section.icon", id: SETTINGS_SECTION_ID }, SettingsIcon)
3798
+ );
3799
+ }
3800
+ function gateInject(ctx, settings, id, inject2) {
3801
+ return (deps, apply2) => {
3802
+ ctx.effect(
3803
+ () => whileEnabled(settings, id, () => {
3804
+ const fiber = inject2(deps, apply2);
3805
+ return () => {
3806
+ if (!isDisposable(fiber)) return;
3807
+ fiber.dispose().catch((_error) => {
3808
+ });
3809
+ };
3810
+ }),
3811
+ `ccgui: ${id} switch`
3812
+ );
3813
+ return void 0;
3814
+ };
3815
+ }
3816
+
3817
+ // src/client/index.tsx
3818
+ var import_jsx_runtime24 = require("react/jsx-runtime");
3819
+ var SLOT3 = "conversation.input.left";
3820
+ var MODEL_SLOT = "conversation.input.right";
3821
+ var SESSION_ROW_SLOT = "sidebar.session.row.leading";
3822
+ var MODEL_MENU_ORDER = 1e3;
3823
+ var SESSION_MARK_ORDER = 20;
3824
+ var WRAP_CLASS = "dsh-cli-switcher-wrap";
3825
+ var BUTTON_CLASS = "dsh-cli-switcher";
3826
+ var SESSION_MARK_CLASS = "dsh-cli-session-mark";
3827
+ var NOT_STARTED = { blank: true };
3828
+ var NO_CHOICE_LABEL = "\u9009\u62E9 CLI";
3829
+ var SWITCH_FAILED_LABEL = "\u5207\u6362\u5931\u8D25";
3830
+ var STYLES = `
3831
+ .${WRAP_CLASS} { order: -1; }
3832
+ :has(> * > .${WRAP_CLASS}) > :first-child { order: -2; }
3833
+ .${BUTTON_CLASS} {
3834
+ display: flex;
3835
+ align-items: center;
3836
+ gap: 4px;
3837
+ height: 28px;
3838
+ padding: 0 4px 0 8px;
3839
+ border: none;
3840
+ border-radius: var(--dsw-radius-sm);
3841
+ outline: none;
3842
+ background: transparent;
3843
+ color: var(--dsw-alias-label-secondary);
3844
+ font-size: 13px;
3845
+ line-height: 20px;
3846
+ white-space: nowrap;
3847
+ cursor: pointer;
3848
+ }
3849
+ .${BUTTON_CLASS}:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
3850
+ .${BUTTON_CLASS}:focus-visible { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, currentColor); }
3851
+ .${BUTTON_CLASS}:disabled { cursor: default; }
3852
+ .${SESSION_MARK_CLASS} { display: inline-flex; color: var(--dsw-alias-label-secondary); }
3853
+ [data-slot="${SESSION_ROW_SLOT}"] > * ~ .${SESSION_MARK_CLASS} { display: none; }
3854
+ `;
3855
+ var BROWSER_STORAGE = {
3856
+ getItem: (key) => window.localStorage.getItem(key),
3857
+ setItem: (key, value) => {
3858
+ window.localStorage.setItem(key, value);
3859
+ }
3860
+ };
3861
+ function installStyles() {
3862
+ const tag = document.createElement("style");
3863
+ tag.dataset.plugin = "dsh-ccgui";
3864
+ tag.textContent = `${STYLES}${MODEL_MENU_STYLES}${TERMINAL_ENTRY_STYLES}${LAUNCH_SCRIPT_STYLES}${SESSION_TREE_STYLES}${SESSION_STATUS_STYLES}${SETTINGS_PAGE_STYLES}${CHANGES_STYLES}`;
3865
+ document.head.append(tag);
3866
+ return () => {
3867
+ tag.remove();
3868
+ };
3869
+ }
3870
+ function useStarted(session) {
3871
+ const snapshot = (0, import_react17.useSyncExternalStore)(
3872
+ (listener) => session?.subscribe(listener) ?? (() => {
3873
+ }),
3874
+ () => session?.getSnapshot() ?? NOT_STARTED
3875
+ );
3876
+ return snapshot.blank === false;
3877
+ }
3878
+ function useChoose(state, select) {
3879
+ const [error, setError] = (0, import_react17.useState)();
3880
+ const choose = (id) => {
3881
+ setError(void 0);
3882
+ const selection = selectionForChoice(state, id);
3883
+ if (selection === void 0) return;
3884
+ void select(selection).then(
3885
+ (result) => {
3886
+ setError(result.error?.message);
3887
+ },
3888
+ (reason) => {
3889
+ setError(String(reason));
3890
+ }
3891
+ );
3892
+ };
3893
+ return { error, choose };
3894
+ }
3895
+ function CliSwitcher({ directory, load, select, session, prefs }) {
3896
+ const state = useStore(directory);
3897
+ const started = useStarted(session);
3898
+ const prefsSnapshot = useStore(prefs);
3899
+ const [open, setOpen] = (0, import_react17.useState)(false);
3900
+ const { error, choose } = useChoose(state, select);
3901
+ (0, import_react17.useEffect)(load, [load]);
3902
+ const { visible, items: listed, currentId, currentLabel } = cliChoices(state);
3903
+ (0, import_react17.useEffect)(() => {
3904
+ prefs.remember(listed);
3905
+ }, [prefs, listed]);
3906
+ if (!visible) return null;
3907
+ const items = arrangeChoices(listed, prefsSnapshot);
3908
+ const hint = started ? "\u8981\u6362 CLI\uFF0C\u8BF7\u65B0\u5EFA\u4F1A\u8BDD" : error ?? "\u5207\u6362 CLI";
3909
+ const label = error === void 0 ? currentLabel ?? NO_CHOICE_LABEL : SWITCH_FAILED_LABEL;
3910
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
3911
+ import_dsh_client_ui_primitives14.Menu,
3912
+ {
3913
+ open: open && !started,
3914
+ className: WRAP_CLASS,
3915
+ items: items.map((item) => ({ ...item, icon: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProviderMark, { provider: item.id, size: 14 }) })),
3916
+ selectedId: currentId,
3917
+ onSelect: (id) => {
3918
+ setOpen(false);
3919
+ choose(id);
3920
+ },
3921
+ onClose: () => {
3922
+ setOpen(false);
3923
+ },
3924
+ side: "top",
3925
+ portal: true,
3926
+ anchor: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3927
+ "button",
3928
+ {
3929
+ type: "button",
3930
+ className: BUTTON_CLASS,
3931
+ "aria-label": "\u5207\u6362 CLI",
3932
+ title: hint,
3933
+ disabled: started,
3934
+ onClick: () => {
3935
+ setOpen((value) => !value);
3936
+ },
3937
+ children: [
3938
+ currentId === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProviderMark, { provider: currentId, size: 14 }),
3939
+ label,
3940
+ started ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_dsh_client_ui_primitives14.IconChevronDownOutlineRegular, { size: 14 })
3941
+ ]
3942
+ }
3943
+ )
3944
+ }
3945
+ );
3946
+ }
3947
+ function SessionMark({ sessionId, list }) {
3948
+ const provider = useSessionProvider(list, sessionId);
3949
+ if (provider === void 0) return null;
3950
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: SESSION_MARK_CLASS, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ProviderMark, { provider, size: 14 }) });
3951
+ }
3952
+ function directoryFace(ctx, sessionId) {
3953
+ const directory = ctx.modelDirectories.directoryFor(sessionId);
3954
+ return {
3955
+ directory: directory.store,
3956
+ load: () => {
3957
+ directory.load().catch(() => {
3958
+ });
3959
+ },
3960
+ select: (selection) => directory.select(selection),
3961
+ session: ctx.sessions.binding(sessionId)?.session
3962
+ };
3963
+ }
3964
+ function registerSwitchableFeatures(ctx, settings) {
3965
+ const terminal = {
3966
+ slots: ctx.slots,
3967
+ inject: gateInject(ctx, settings, "terminalEntry", (deps, apply2) => ctx.inject(deps, apply2))
3968
+ };
3969
+ const files = {
3970
+ inject: gateInject(ctx, settings, "filesDefault", (deps, apply2) => ctx.inject(deps, apply2))
3971
+ };
3972
+ const scripts = {
3973
+ slots: ctx.slots,
3974
+ inject: gateInject(ctx, settings, "launchScripts", (deps, apply2) => ctx.inject(deps, apply2))
3975
+ };
3976
+ registerTerminalEntry(terminal);
3977
+ const changes = {
3978
+ inject: gateInject(ctx, settings, "gitChanges", (deps, apply2) => ctx.inject(deps, apply2))
3979
+ };
3980
+ registerFilesDefault(files);
3981
+ registerChanges(changes, ctx.sessions.list, (input, init) => window.fetch(input, init));
3982
+ registerLaunchScripts(scripts, ctx.sessions.list, BROWSER_STORAGE, () => crypto.randomUUID());
3983
+ ctx.effect(() => whileEnabled(settings, "compactTabs", () => installCompactTabs(document)), "ccgui: compact tabs");
3984
+ }
3985
+ var inject = ["slots", "modelDirectories", "sessions"];
3986
+ function apply(ctx) {
3987
+ ctx.effect(installStyles, "ccgui: styles");
3988
+ const cliPrefs = createCliPrefs(BROWSER_STORAGE);
3989
+ ctx.slots.inject(
3990
+ SLOT3,
3991
+ () => ctx.slots.register(
3992
+ {
3993
+ name: SLOT3,
3994
+ id: "dsh-ccgui.switcher",
3995
+ inject: (sessionId) => ({ ...directoryFace(ctx, sessionId), prefs: cliPrefs })
3996
+ },
3997
+ CliSwitcher
3998
+ )
3999
+ );
4000
+ ctx.slots.inject(
4001
+ MODEL_SLOT,
4002
+ () => ctx.slots.register(
4003
+ {
4004
+ name: MODEL_SLOT,
4005
+ id: "dsh-ccgui.model-menu",
4006
+ order: MODEL_MENU_ORDER,
4007
+ inject: (sessionId) => ({
4008
+ ...directoryFace(ctx, sessionId),
4009
+ available: ctx.sessions.subagentAddress(sessionId) === void 0
4010
+ })
4011
+ },
4012
+ CliModelMenu
4013
+ )
4014
+ );
4015
+ ctx.slots.inject(
4016
+ SESSION_ROW_SLOT,
4017
+ () => ctx.slots.register(
4018
+ {
4019
+ name: SESSION_ROW_SLOT,
4020
+ id: "dsh-ccgui.session-mark",
4021
+ order: SESSION_MARK_ORDER,
4022
+ inject: () => ({ list: ctx.sessions.list })
4023
+ },
4024
+ SessionMark
4025
+ )
4026
+ );
4027
+ ctx.slots.inject(
4028
+ SESSION_STATUS_SLOT,
4029
+ () => ctx.slots.register(
4030
+ { name: SESSION_STATUS_SLOT, id: "dsh-ccgui.session-status-mark", inject: () => ({ list: ctx.sessions.list }) },
4031
+ SessionStatusMark
4032
+ )
4033
+ );
4034
+ const settings = createFeatureSettings(BROWSER_STORAGE);
4035
+ registerSettingsPage(ctx, settings, cliPrefs);
4036
+ registerSwitchableFeatures(ctx, settings);
4037
+ registerAddToChat(ctx);
4038
+ }
4039
+ return module.exports; } });