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.
- package/LICENSE +21 -0
- package/README.md +327 -2
- package/THIRD_PARTY_NOTICES.md +64 -0
- package/assets/logo.png +0 -0
- package/cordis.patch.yml +32 -0
- package/lib/abortable.d.ts +12 -0
- package/lib/abortable.js +27 -0
- package/lib/adapter.d.ts +39 -0
- package/lib/adapter.js +64 -0
- package/lib/async-queue.d.ts +26 -0
- package/lib/async-queue.js +55 -0
- package/lib/cli-session.d.ts +99 -0
- package/lib/cli-session.js +384 -0
- package/lib/cli-tool.d.ts +18 -0
- package/lib/cli-tool.js +101 -0
- package/lib/client.js +4039 -0
- package/lib/constants.d.ts +22 -0
- package/lib/constants.js +22 -0
- package/lib/git/git-read.d.ts +65 -0
- package/lib/git/git-read.js +139 -0
- package/lib/git/git-requests.d.ts +44 -0
- package/lib/git/git-requests.js +153 -0
- package/lib/git/git-routes.d.ts +38 -0
- package/lib/git/git-routes.js +78 -0
- package/lib/git/git-run.d.ts +58 -0
- package/lib/git/git-run.js +97 -0
- package/lib/git/git-status.d.ts +51 -0
- package/lib/git/git-status.js +122 -0
- package/lib/git/git-write.d.ts +75 -0
- package/lib/git/git-write.js +134 -0
- package/lib/index.d.ts +78 -0
- package/lib/index.js +229 -0
- package/lib/model-cache.d.ts +33 -0
- package/lib/model-cache.js +101 -0
- package/lib/model-catalog.d.ts +63 -0
- package/lib/model-catalog.js +107 -0
- package/lib/model-options.d.ts +26 -0
- package/lib/model-options.js +46 -0
- package/lib/model-probe.d.ts +16 -0
- package/lib/model-probe.js +91 -0
- package/lib/npx-cache.d.ts +39 -0
- package/lib/npx-cache.js +97 -0
- package/lib/permission.d.ts +17 -0
- package/lib/permission.js +34 -0
- package/lib/prompt-images.d.ts +44 -0
- package/lib/prompt-images.js +46 -0
- package/lib/request-input.d.ts +42 -0
- package/lib/request-input.js +113 -0
- package/lib/session/connect.d.ts +41 -0
- package/lib/session/connect.js +68 -0
- package/lib/session/drive-tool.d.ts +39 -0
- package/lib/session/drive-tool.js +37 -0
- package/lib/session/model-state.d.ts +40 -0
- package/lib/session/model-state.js +68 -0
- package/lib/session/outcomes.d.ts +31 -0
- package/lib/session/outcomes.js +67 -0
- package/lib/session/permission-queue.d.ts +24 -0
- package/lib/session/permission-queue.js +33 -0
- package/lib/session/read-step.d.ts +31 -0
- package/lib/session/read-step.js +53 -0
- package/lib/session/tool-mirror.d.ts +65 -0
- package/lib/session/tool-mirror.js +131 -0
- package/lib/session/turn-queue.d.ts +76 -0
- package/lib/session/turn-queue.js +102 -0
- package/lib/session/types.d.ts +58 -0
- package/lib/session/types.js +6 -0
- package/lib/session-registry.d.ts +124 -0
- package/lib/session-registry.js +189 -0
- package/lib/stdio-transport.d.ts +28 -0
- package/lib/stdio-transport.js +164 -0
- package/lib/stream-blocks.d.ts +52 -0
- package/lib/stream-blocks.js +95 -0
- package/lib/tool-record.d.ts +100 -0
- package/lib/tool-record.js +167 -0
- package/lib/transport.d.ts +35 -0
- package/lib/transport.js +5 -0
- 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; } });
|