dsh-vscode-workbench 0.2.3 → 0.2.5
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/README.en.md +27 -10
- package/README.md +26 -11
- package/cordis.patch.yml +2 -0
- package/lib/client.js +1039 -417
- package/lib/client.js.map +1 -1
- package/lib/index.js +15 -249
- package/lib/index.js.map +1 -1
- package/lib/types/client/DshBrowserPage.d.ts +6 -0
- package/lib/types/client/DshPanelPage.d.ts +9 -0
- package/lib/types/client/Icon.d.ts +1 -1
- package/lib/types/client/TerminalPanel.d.ts +5 -2
- package/lib/types/client/Workbench.d.ts +7 -1
- package/lib/types/client/browser.d.ts +26 -0
- package/lib/types/client/dshPanels.d.ts +4 -0
- package/lib/types/client/shortcuts.d.ts +2 -0
- package/lib/types/client/terminal.d.ts +37 -32
- package/package.json +15 -4
- package/src/client/DshBrowserPage.tsx +61 -0
- package/src/client/DshPanelPage.tsx +63 -0
- package/src/client/Icon.tsx +1 -1
- package/src/client/TerminalPanel.tsx +63 -40
- package/src/client/Workbench.tsx +72 -11
- package/src/client/browser.ts +68 -0
- package/src/client/dshPanels.ts +16 -0
- package/src/client/index.tsx +25 -6
- package/src/client/shortcuts.ts +9 -0
- package/src/client/styles.ts +18 -7
- package/src/client/terminal.ts +125 -78
- package/src/index.ts +0 -2
- package/src/lsp.ts +22 -14
- package/lib/types/terminal.d.ts +0 -46
- package/src/terminal.ts +0 -173
package/lib/client.js
CHANGED
|
@@ -44,9 +44,310 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
enumerable: true
|
|
45
45
|
}) : target, mod));
|
|
46
46
|
//#endregion
|
|
47
|
+
let _deepseek_ai_dsh_api_terminal_controller_client = require("@deepseek-ai/dsh-api-terminal-controller/client");
|
|
47
48
|
let react = require("react");
|
|
48
49
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
49
50
|
let react_dom = require("react-dom");
|
|
51
|
+
//#region src/client/terminal.ts
|
|
52
|
+
const STORAGE_PREFIX = "dvw:native-terminal-tab:v1:";
|
|
53
|
+
/** Own workbench membership without overwriting the official sidebar's terminal inventory. */
|
|
54
|
+
var TerminalWorkspaces = class {
|
|
55
|
+
models;
|
|
56
|
+
workspaces = /* @__PURE__ */ new Map();
|
|
57
|
+
saved = Object.create(null);
|
|
58
|
+
constructor(models) {
|
|
59
|
+
this.models = models;
|
|
60
|
+
try {
|
|
61
|
+
this.saved = this.readSaved();
|
|
62
|
+
} catch {}
|
|
63
|
+
this.retain();
|
|
64
|
+
window.addEventListener("storage", this.onStorage);
|
|
65
|
+
}
|
|
66
|
+
get(sessionId) {
|
|
67
|
+
let workspace = this.workspaces.get(sessionId);
|
|
68
|
+
if (workspace === void 0) {
|
|
69
|
+
workspace = new TerminalWorkspaceController(this, sessionId, this.saved[sessionId] ?? []);
|
|
70
|
+
this.workspaces.set(sessionId, workspace);
|
|
71
|
+
}
|
|
72
|
+
return workspace;
|
|
73
|
+
}
|
|
74
|
+
save(sessionId, ids) {
|
|
75
|
+
const previous = this.saved[sessionId] ?? [];
|
|
76
|
+
try {
|
|
77
|
+
for (const id of ids) if (!previous.includes(id)) localStorage.setItem(STORAGE_PREFIX + JSON.stringify([sessionId, id]), "open");
|
|
78
|
+
for (const id of previous) if (!ids.includes(id)) localStorage.removeItem(STORAGE_PREFIX + JSON.stringify([sessionId, id]));
|
|
79
|
+
this.sync(this.readSaved());
|
|
80
|
+
} catch {
|
|
81
|
+
this.saved[sessionId] = ids;
|
|
82
|
+
this.retain();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
readSaved() {
|
|
86
|
+
const saved = Object.create(null);
|
|
87
|
+
for (let index = 0; index < localStorage.length; index++) {
|
|
88
|
+
const key = localStorage.key(index);
|
|
89
|
+
if (!key?.startsWith(STORAGE_PREFIX)) continue;
|
|
90
|
+
try {
|
|
91
|
+
const value = JSON.parse(key.slice(27));
|
|
92
|
+
if (!Array.isArray(value) || value.length !== 2) continue;
|
|
93
|
+
const [sessionId, id] = value;
|
|
94
|
+
if (typeof sessionId !== "string" || typeof id !== "string" || !id.startsWith("dvw-terminal:")) continue;
|
|
95
|
+
(saved[sessionId] ??= []).push(id);
|
|
96
|
+
} catch {}
|
|
97
|
+
}
|
|
98
|
+
return saved;
|
|
99
|
+
}
|
|
100
|
+
sync(saved) {
|
|
101
|
+
this.saved = saved;
|
|
102
|
+
for (const [sessionId, workspace] of this.workspaces) workspace.reconcile(saved[sessionId] ?? []);
|
|
103
|
+
this.retain();
|
|
104
|
+
}
|
|
105
|
+
onStorage = (event) => {
|
|
106
|
+
if (event.storageArea !== localStorage || event.key !== null && !event.key.startsWith(STORAGE_PREFIX)) return;
|
|
107
|
+
this.sync(this.readSaved());
|
|
108
|
+
};
|
|
109
|
+
retain() {
|
|
110
|
+
this.models.retainTabs(Object.entries(this.saved).flatMap(([sessionId, ids]) => ids.map((id) => ({
|
|
111
|
+
sessionId,
|
|
112
|
+
tabId: id,
|
|
113
|
+
contentId: id
|
|
114
|
+
}))));
|
|
115
|
+
}
|
|
116
|
+
dispose() {
|
|
117
|
+
window.removeEventListener("storage", this.onStorage);
|
|
118
|
+
for (const workspace of this.workspaces.values()) workspace.dispose();
|
|
119
|
+
this.models.retainTabs([]);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
/** Layout only; the official model owns processes, stream ordering, recovery and input control. */
|
|
123
|
+
var TerminalWorkspaceController = class {
|
|
124
|
+
owner;
|
|
125
|
+
sessionId;
|
|
126
|
+
closeFailures;
|
|
127
|
+
snapshot;
|
|
128
|
+
listeners = /* @__PURE__ */ new Set();
|
|
129
|
+
views = /* @__PURE__ */ new Map();
|
|
130
|
+
constructor(owner, sessionId, ids) {
|
|
131
|
+
this.owner = owner;
|
|
132
|
+
this.sessionId = sessionId;
|
|
133
|
+
this.closeFailures = owner.models.closeFailures;
|
|
134
|
+
this.snapshot = {
|
|
135
|
+
terminals: ids.map((id) => ({
|
|
136
|
+
id,
|
|
137
|
+
title: "终端"
|
|
138
|
+
})),
|
|
139
|
+
loading: false
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
view(id) {
|
|
143
|
+
const existing = this.views.get(id);
|
|
144
|
+
if (existing !== void 0) return existing.model;
|
|
145
|
+
const model = this.owner.models.view(this.sessionId, id, id);
|
|
146
|
+
const unsubscribe = model.state.subscribe(() => this.updateTitles());
|
|
147
|
+
this.views.set(id, {
|
|
148
|
+
model,
|
|
149
|
+
unsubscribe
|
|
150
|
+
});
|
|
151
|
+
this.updateTitles();
|
|
152
|
+
return model;
|
|
153
|
+
}
|
|
154
|
+
async refresh() {
|
|
155
|
+
this.set({
|
|
156
|
+
...this.snapshot,
|
|
157
|
+
loading: true,
|
|
158
|
+
error: void 0
|
|
159
|
+
});
|
|
160
|
+
try {
|
|
161
|
+
await Promise.all(this.snapshot.terminals.map((entry) => this.view(entry.id).refresh()));
|
|
162
|
+
this.set({
|
|
163
|
+
...this.snapshot,
|
|
164
|
+
loading: false
|
|
165
|
+
});
|
|
166
|
+
return true;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
this.fail(error);
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async create() {
|
|
173
|
+
const entry = {
|
|
174
|
+
id: `dvw-terminal:${crypto.randomUUID()}`,
|
|
175
|
+
title: "终端"
|
|
176
|
+
};
|
|
177
|
+
this.set({
|
|
178
|
+
terminals: [...this.snapshot.terminals, entry],
|
|
179
|
+
loading: false
|
|
180
|
+
});
|
|
181
|
+
this.save();
|
|
182
|
+
await this.view(entry.id).refresh();
|
|
183
|
+
return this.snapshot.terminals.find((row) => row.id === entry.id) ?? entry;
|
|
184
|
+
}
|
|
185
|
+
close(id) {
|
|
186
|
+
this.owner.models.close(this.sessionId, id, id);
|
|
187
|
+
this.views.get(id)?.unsubscribe();
|
|
188
|
+
this.views.delete(id);
|
|
189
|
+
this.set({
|
|
190
|
+
...this.snapshot,
|
|
191
|
+
terminals: this.snapshot.terminals.filter((entry) => entry.id !== id)
|
|
192
|
+
});
|
|
193
|
+
this.save();
|
|
194
|
+
}
|
|
195
|
+
async rename(id, title) {
|
|
196
|
+
try {
|
|
197
|
+
await this.view(id).rename(title);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.fail(error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
retryClose(id) {
|
|
203
|
+
this.owner.models.retryClose(id);
|
|
204
|
+
}
|
|
205
|
+
reconcile(ids) {
|
|
206
|
+
const entries = new Map(this.snapshot.terminals.map((entry) => [entry.id, entry]));
|
|
207
|
+
for (const [id, view] of this.views) if (!ids.includes(id)) {
|
|
208
|
+
view.unsubscribe();
|
|
209
|
+
this.views.delete(id);
|
|
210
|
+
}
|
|
211
|
+
this.set({
|
|
212
|
+
...this.snapshot,
|
|
213
|
+
terminals: ids.map((id) => entries.get(id) ?? {
|
|
214
|
+
id,
|
|
215
|
+
title: "终端"
|
|
216
|
+
})
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
getSnapshot = () => this.snapshot;
|
|
220
|
+
subscribe = (listener) => {
|
|
221
|
+
this.listeners.add(listener);
|
|
222
|
+
return () => this.listeners.delete(listener);
|
|
223
|
+
};
|
|
224
|
+
dispose() {
|
|
225
|
+
for (const view of this.views.values()) view.unsubscribe();
|
|
226
|
+
this.views.clear();
|
|
227
|
+
}
|
|
228
|
+
save() {
|
|
229
|
+
this.owner.save(this.sessionId, this.snapshot.terminals.map((entry) => entry.id));
|
|
230
|
+
}
|
|
231
|
+
updateTitles() {
|
|
232
|
+
this.set({
|
|
233
|
+
...this.snapshot,
|
|
234
|
+
terminals: this.snapshot.terminals.map((entry) => ({
|
|
235
|
+
...entry,
|
|
236
|
+
title: this.views.get(entry.id)?.model.state.getSnapshot().title ?? entry.title
|
|
237
|
+
}))
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
fail(error) {
|
|
241
|
+
this.set({
|
|
242
|
+
...this.snapshot,
|
|
243
|
+
loading: false,
|
|
244
|
+
error: error instanceof Error ? error.message : String(error)
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
set(snapshot) {
|
|
248
|
+
this.snapshot = snapshot;
|
|
249
|
+
for (const listener of this.listeners) listener();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
function terminalIssue(state) {
|
|
253
|
+
return state.issue === void 0 ? state.error ?? state.info?.error : {
|
|
254
|
+
missingTerminal: "此终端已不存在,请关闭后新建终端。",
|
|
255
|
+
inputFull: "终端输入缓冲已满,请重新连接。",
|
|
256
|
+
attachmentEnded: "终端连接已结束,请重新连接。",
|
|
257
|
+
invalidOutput: "终端输出无法解析,请重新连接。",
|
|
258
|
+
terminalLimit: "终端数量已达上限,请关闭不用的终端。"
|
|
259
|
+
}[state.issue];
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/client/browser.ts
|
|
263
|
+
/** Navigate official browser tabs; their controller, renderer and persistence stay with DSH. */
|
|
264
|
+
var NativeBrowser = class {
|
|
265
|
+
ctx;
|
|
266
|
+
snapshot = {
|
|
267
|
+
available: false,
|
|
268
|
+
tabs: []
|
|
269
|
+
};
|
|
270
|
+
listeners = /* @__PURE__ */ new Set();
|
|
271
|
+
lifetime = new AbortController();
|
|
272
|
+
disposers;
|
|
273
|
+
constructor(ctx) {
|
|
274
|
+
this.ctx = ctx;
|
|
275
|
+
this.disposers = [ctx.sidebarRight.openTabs.subscribe(() => this.update()), ctx.sidebarRightTabs.subscribe(() => this.update())];
|
|
276
|
+
this.update();
|
|
277
|
+
}
|
|
278
|
+
getSnapshot = () => this.snapshot;
|
|
279
|
+
subscribe = (listener) => {
|
|
280
|
+
this.listeners.add(listener);
|
|
281
|
+
return () => this.listeners.delete(listener);
|
|
282
|
+
};
|
|
283
|
+
async open(sessionId, request) {
|
|
284
|
+
const signal = request === void 0 ? this.lifetime.signal : AbortSignal.any([request, this.lifetime.signal]);
|
|
285
|
+
signal.throwIfAborted();
|
|
286
|
+
if (!this.snapshot.available) throw new Error("官方浏览器尚未启用,请重新加载 Harness。");
|
|
287
|
+
const ready = () => this.ctx.sidebarRight.mounted.getSnapshot() === sessionId && [...document.querySelectorAll("[data-sidebar-right-session]")].some((node) => node.getAttribute("data-sidebar-right-session") === sessionId);
|
|
288
|
+
if (!ready()) await new Promise((resolve, reject) => {
|
|
289
|
+
const clean = () => {
|
|
290
|
+
clearTimeout(timer);
|
|
291
|
+
unsubscribe();
|
|
292
|
+
observer.disconnect();
|
|
293
|
+
signal.removeEventListener("abort", abort);
|
|
294
|
+
};
|
|
295
|
+
const abort = () => {
|
|
296
|
+
clean();
|
|
297
|
+
reject(signal.reason);
|
|
298
|
+
};
|
|
299
|
+
const timer = setTimeout(() => {
|
|
300
|
+
clean();
|
|
301
|
+
reject(/* @__PURE__ */ new Error("工作区尚未就绪,请稍后重试。"));
|
|
302
|
+
}, 1e4);
|
|
303
|
+
const check = () => {
|
|
304
|
+
if (ready()) {
|
|
305
|
+
clean();
|
|
306
|
+
resolve();
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const unsubscribe = this.ctx.sidebarRight.mounted.subscribe(check);
|
|
310
|
+
const observer = new MutationObserver(check);
|
|
311
|
+
observer.observe(document.body, {
|
|
312
|
+
childList: true,
|
|
313
|
+
subtree: true
|
|
314
|
+
});
|
|
315
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
316
|
+
});
|
|
317
|
+
signal.throwIfAborted();
|
|
318
|
+
const before = new Set(this.ctx.sidebarRight.tabsIn(sessionId).map((tab) => tab.id));
|
|
319
|
+
this.ctx.sidebarRight.openTabIn(sessionId, "browser", { revealIfOpened: false });
|
|
320
|
+
const tab = this.ctx.sidebarRight.tabsIn(sessionId).find((tab) => tab.kind === "browser" && !before.has(tab.id));
|
|
321
|
+
if (tab === void 0) throw new Error("浏览器页面未能打开,请重试。");
|
|
322
|
+
this.update();
|
|
323
|
+
return tab.id;
|
|
324
|
+
}
|
|
325
|
+
focus(id) {
|
|
326
|
+
this.ctx.sidebarRight.focus(id);
|
|
327
|
+
if (!this.ctx.sidebarRight.isExpanded()) this.ctx.sidebarRight.toggleExpanded();
|
|
328
|
+
}
|
|
329
|
+
close(sessionId, id) {
|
|
330
|
+
this.ctx.sidebarRight.closeIn(sessionId, id);
|
|
331
|
+
this.update();
|
|
332
|
+
}
|
|
333
|
+
dispose() {
|
|
334
|
+
this.lifetime.abort();
|
|
335
|
+
for (const dispose of this.disposers) dispose();
|
|
336
|
+
this.listeners.clear();
|
|
337
|
+
}
|
|
338
|
+
update() {
|
|
339
|
+
this.snapshot = {
|
|
340
|
+
available: this.ctx.sidebarRightTabs.get("browser") !== void 0,
|
|
341
|
+
tabs: this.ctx.sidebarRight.openTabs.getSnapshot().filter((tab) => tab.kind === "browser").map((tab) => ({
|
|
342
|
+
id: tab.tabId,
|
|
343
|
+
sessionId: tab.sessionId,
|
|
344
|
+
title: this.ctx.sidebarRight.tabsIn(tab.sessionId).find((record) => record.id === tab.tabId)?.title ?? "浏览器"
|
|
345
|
+
}))
|
|
346
|
+
};
|
|
347
|
+
for (const listener of this.listeners) listener();
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
//#endregion
|
|
50
351
|
//#region src/client/service.ts
|
|
51
352
|
const SNAPSHOT_KEY = "dvw:workbench:snapshot:v1";
|
|
52
353
|
const DEFAULT_SNAPSHOT = {
|
|
@@ -7409,273 +7710,6 @@ window.__ModuleLoader__.load({
|
|
|
7409
7710
|
});
|
|
7410
7711
|
}
|
|
7411
7712
|
//#endregion
|
|
7412
|
-
//#region src/client/api.ts
|
|
7413
|
-
var ApiError = class extends Error {
|
|
7414
|
-
code;
|
|
7415
|
-
constructor(code, message) {
|
|
7416
|
-
super(message);
|
|
7417
|
-
this.code = code;
|
|
7418
|
-
}
|
|
7419
|
-
};
|
|
7420
|
-
/** Back off while DSH publishes the current session after startup; every view shares this retry. */
|
|
7421
|
-
function sessionRetryDelay(error, attempt) {
|
|
7422
|
-
if (!(error instanceof ApiError) || error.code !== "session-not-found" || attempt >= 10) return void 0;
|
|
7423
|
-
return Math.min(250 * (attempt + 1), 1e3);
|
|
7424
|
-
}
|
|
7425
|
-
function wait(ms, signal) {
|
|
7426
|
-
return new Promise((resolve, reject) => {
|
|
7427
|
-
const abort = () => {
|
|
7428
|
-
clearTimeout(timer);
|
|
7429
|
-
reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
7430
|
-
};
|
|
7431
|
-
const timer = setTimeout(() => {
|
|
7432
|
-
signal?.removeEventListener("abort", abort);
|
|
7433
|
-
resolve();
|
|
7434
|
-
}, ms);
|
|
7435
|
-
if (signal?.aborted === true) {
|
|
7436
|
-
abort();
|
|
7437
|
-
return;
|
|
7438
|
-
}
|
|
7439
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
7440
|
-
});
|
|
7441
|
-
}
|
|
7442
|
-
async function request$2(method, body, signal) {
|
|
7443
|
-
const response = await fetch(`/dsh-vscode/api/${method}`, {
|
|
7444
|
-
method: "POST",
|
|
7445
|
-
headers: { "content-type": "application/json" },
|
|
7446
|
-
body: JSON.stringify(body),
|
|
7447
|
-
signal
|
|
7448
|
-
});
|
|
7449
|
-
const answer = await response.json();
|
|
7450
|
-
if (!response.ok || !answer.ok) throw new ApiError(answer.error?.code ?? "request-failed", answer.error?.message ?? `request failed (${response.status})`);
|
|
7451
|
-
return answer.value;
|
|
7452
|
-
}
|
|
7453
|
-
async function api(method, body, signal) {
|
|
7454
|
-
return withSessionRetry(() => request$2(method, body, signal), signal);
|
|
7455
|
-
}
|
|
7456
|
-
/** Retry an operation while DSH is still publishing the selected session. */
|
|
7457
|
-
async function withSessionRetry(operation, signal) {
|
|
7458
|
-
for (let attempt = 0;; attempt++) try {
|
|
7459
|
-
return await operation();
|
|
7460
|
-
} catch (error) {
|
|
7461
|
-
const delay = sessionRetryDelay(error, attempt);
|
|
7462
|
-
if (delay === void 0) throw error;
|
|
7463
|
-
await wait(delay, signal);
|
|
7464
|
-
}
|
|
7465
|
-
}
|
|
7466
|
-
//#endregion
|
|
7467
|
-
//#region src/client/websocket.ts
|
|
7468
|
-
const WEB_PAGE_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
7469
|
-
"http:",
|
|
7470
|
-
"https:",
|
|
7471
|
-
"blob:",
|
|
7472
|
-
"data:",
|
|
7473
|
-
"about:",
|
|
7474
|
-
"filesystem:"
|
|
7475
|
-
]);
|
|
7476
|
-
/** Parse a shell-published base only when it is a credential-free HTTP(S) origin. */
|
|
7477
|
-
function networkBase(value) {
|
|
7478
|
-
if (typeof value !== "string" || value === "") return void 0;
|
|
7479
|
-
let url;
|
|
7480
|
-
try {
|
|
7481
|
-
url = new URL(value);
|
|
7482
|
-
} catch {
|
|
7483
|
-
return;
|
|
7484
|
-
}
|
|
7485
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
7486
|
-
if (url.username !== "" || url.password !== "" || url.host === "") return void 0;
|
|
7487
|
-
return {
|
|
7488
|
-
protocol: url.protocol,
|
|
7489
|
-
host: url.host
|
|
7490
|
-
};
|
|
7491
|
-
}
|
|
7492
|
-
/** Read the Host origin published by the DSH Desktop shell before application boot. */
|
|
7493
|
-
function transportStreamBaseUrl(globals = globalThis) {
|
|
7494
|
-
const transport = globals.__DSH_TRANSPORT__;
|
|
7495
|
-
return typeof transport?.streamBaseUrl === "string" ? transport.streamBaseUrl : void 0;
|
|
7496
|
-
}
|
|
7497
|
-
/**
|
|
7498
|
-
* Resolve an absolute workbench route to a WebSocket URL.
|
|
7499
|
-
*
|
|
7500
|
-
* Network pages keep their own origin. Application-delivered pages such as
|
|
7501
|
-
* `dsh-app://app/` have no WebSocket transport of their own, so they must use
|
|
7502
|
-
* the local Host origin published by the desktop shell.
|
|
7503
|
-
*/
|
|
7504
|
-
function websocketUrl(path, location = globalThis.location, streamBaseUrl = transportStreamBaseUrl()) {
|
|
7505
|
-
const route = path.startsWith("/") ? path : `/${path}`;
|
|
7506
|
-
if (WEB_PAGE_PROTOCOLS.has(location.protocol)) {
|
|
7507
|
-
if (location.host === "") return void 0;
|
|
7508
|
-
return `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}${route}`;
|
|
7509
|
-
}
|
|
7510
|
-
const base = networkBase(streamBaseUrl);
|
|
7511
|
-
if (base === void 0) return void 0;
|
|
7512
|
-
return `${base.protocol === "https:" ? "wss" : "ws"}://${base.host}${route}`;
|
|
7513
|
-
}
|
|
7514
|
-
//#endregion
|
|
7515
|
-
//#region src/client/terminal.ts
|
|
7516
|
-
async function request$1(method, body) {
|
|
7517
|
-
const response = await fetch(`/dsh-vscode-terminal/api/${method}`, {
|
|
7518
|
-
method: "POST",
|
|
7519
|
-
headers: { "content-type": "application/json" },
|
|
7520
|
-
body: JSON.stringify(body)
|
|
7521
|
-
});
|
|
7522
|
-
const text = await response.text();
|
|
7523
|
-
let answer;
|
|
7524
|
-
try {
|
|
7525
|
-
answer = JSON.parse(text);
|
|
7526
|
-
} catch {
|
|
7527
|
-
throw new Error(`terminal request returned invalid JSON (${response.status})`);
|
|
7528
|
-
}
|
|
7529
|
-
if (!response.ok || answer.ok !== true) throw new ApiError(answer.error?.code ?? "terminal-request-failed", answer.error?.message ?? "terminal request failed");
|
|
7530
|
-
return answer.value;
|
|
7531
|
-
}
|
|
7532
|
-
var SocketConnection = class {
|
|
7533
|
-
socket;
|
|
7534
|
-
listeners = /* @__PURE__ */ new Set();
|
|
7535
|
-
errorListeners = /* @__PURE__ */ new Set();
|
|
7536
|
-
closed = false;
|
|
7537
|
-
queue = [];
|
|
7538
|
-
constructor(sessionId, id) {
|
|
7539
|
-
const url = websocketUrl(`/dsh-vscode-terminal/ws?sessionId=${encodeURIComponent(sessionId)}&id=${encodeURIComponent(id)}`);
|
|
7540
|
-
if (url === void 0) throw new Error("无法连接终端:桌面端没有发布本地 Host 地址");
|
|
7541
|
-
this.socket = new WebSocket(url);
|
|
7542
|
-
this.socket.onopen = () => {
|
|
7543
|
-
for (const value of this.queue) this.socket.send(value);
|
|
7544
|
-
this.queue = [];
|
|
7545
|
-
};
|
|
7546
|
-
this.socket.onerror = () => {
|
|
7547
|
-
for (const listener of this.errorListeners) listener("终端 WebSocket 连接失败");
|
|
7548
|
-
};
|
|
7549
|
-
this.socket.onclose = () => {
|
|
7550
|
-
if (!this.closed) for (const listener of this.errorListeners) listener("终端 WebSocket 连接已断开");
|
|
7551
|
-
};
|
|
7552
|
-
this.socket.onmessage = (event) => {
|
|
7553
|
-
try {
|
|
7554
|
-
const value = JSON.parse(String(event.data));
|
|
7555
|
-
if (typeof value.sequence !== "number" || typeof value.data !== "string") return;
|
|
7556
|
-
for (const listener of this.listeners) listener({
|
|
7557
|
-
sequence: value.sequence,
|
|
7558
|
-
data: value.data,
|
|
7559
|
-
replay: value.type === "replay"
|
|
7560
|
-
});
|
|
7561
|
-
} catch {}
|
|
7562
|
-
};
|
|
7563
|
-
}
|
|
7564
|
-
send(value) {
|
|
7565
|
-
const text = JSON.stringify(value);
|
|
7566
|
-
if (this.socket.readyState === WebSocket.OPEN) this.socket.send(text);
|
|
7567
|
-
else this.queue.push(text);
|
|
7568
|
-
}
|
|
7569
|
-
write(data) {
|
|
7570
|
-
this.send({
|
|
7571
|
-
type: "input",
|
|
7572
|
-
data
|
|
7573
|
-
});
|
|
7574
|
-
}
|
|
7575
|
-
resize(cols, rows) {
|
|
7576
|
-
this.send({
|
|
7577
|
-
type: "resize",
|
|
7578
|
-
cols,
|
|
7579
|
-
rows
|
|
7580
|
-
});
|
|
7581
|
-
}
|
|
7582
|
-
close() {
|
|
7583
|
-
this.closed = true;
|
|
7584
|
-
this.socket.close();
|
|
7585
|
-
}
|
|
7586
|
-
subscribe(listener) {
|
|
7587
|
-
this.listeners.add(listener);
|
|
7588
|
-
return () => this.listeners.delete(listener);
|
|
7589
|
-
}
|
|
7590
|
-
subscribeError(listener) {
|
|
7591
|
-
this.errorListeners.add(listener);
|
|
7592
|
-
return () => this.errorListeners.delete(listener);
|
|
7593
|
-
}
|
|
7594
|
-
};
|
|
7595
|
-
/** Identify automatic terminal-emulator replies that must not be echoed during replay. */
|
|
7596
|
-
function isTerminalProtocolReply(data) {
|
|
7597
|
-
return /^\x1b\](?:10|11|12);(?:rgb:[\da-f]{4}\/[\da-f]{4}\/[\da-f]{4}|#[\da-f]{6})(?:\x07|\x1b\\)$/i.test(data) || /^\x1b\[\??[\d;]*[cR]$/.test(data);
|
|
7598
|
-
}
|
|
7599
|
-
/** Maintain one terminal collection for a DSH session. */
|
|
7600
|
-
var TerminalWorkspaceController = class {
|
|
7601
|
-
sessionId;
|
|
7602
|
-
snapshot = {
|
|
7603
|
-
terminals: [],
|
|
7604
|
-
loading: false
|
|
7605
|
-
};
|
|
7606
|
-
listeners = /* @__PURE__ */ new Set();
|
|
7607
|
-
constructor(sessionId) {
|
|
7608
|
-
this.sessionId = sessionId;
|
|
7609
|
-
}
|
|
7610
|
-
async refresh() {
|
|
7611
|
-
this.set({
|
|
7612
|
-
...this.snapshot,
|
|
7613
|
-
loading: true,
|
|
7614
|
-
error: void 0
|
|
7615
|
-
});
|
|
7616
|
-
try {
|
|
7617
|
-
this.set({
|
|
7618
|
-
terminals: await withSessionRetry(() => request$1("list", { sessionId: this.sessionId })),
|
|
7619
|
-
loading: false
|
|
7620
|
-
});
|
|
7621
|
-
return true;
|
|
7622
|
-
} catch (error) {
|
|
7623
|
-
this.set({
|
|
7624
|
-
...this.snapshot,
|
|
7625
|
-
loading: false,
|
|
7626
|
-
error: error instanceof Error ? error.message : String(error)
|
|
7627
|
-
});
|
|
7628
|
-
return false;
|
|
7629
|
-
}
|
|
7630
|
-
}
|
|
7631
|
-
async create(title) {
|
|
7632
|
-
try {
|
|
7633
|
-
const terminal = await withSessionRetry(() => request$1("create", {
|
|
7634
|
-
sessionId: this.sessionId,
|
|
7635
|
-
...title === void 0 ? {} : { title }
|
|
7636
|
-
}));
|
|
7637
|
-
await this.refresh();
|
|
7638
|
-
return terminal;
|
|
7639
|
-
} catch (error) {
|
|
7640
|
-
this.set({
|
|
7641
|
-
...this.snapshot,
|
|
7642
|
-
loading: false,
|
|
7643
|
-
error: error instanceof Error ? error.message : String(error)
|
|
7644
|
-
});
|
|
7645
|
-
throw error;
|
|
7646
|
-
}
|
|
7647
|
-
}
|
|
7648
|
-
async close(id) {
|
|
7649
|
-
await withSessionRetry(() => request$1("close", {
|
|
7650
|
-
sessionId: this.sessionId,
|
|
7651
|
-
id
|
|
7652
|
-
}));
|
|
7653
|
-
await this.refresh();
|
|
7654
|
-
}
|
|
7655
|
-
async rename(id, title) {
|
|
7656
|
-
await withSessionRetry(() => request$1("rename", {
|
|
7657
|
-
sessionId: this.sessionId,
|
|
7658
|
-
id,
|
|
7659
|
-
title
|
|
7660
|
-
}));
|
|
7661
|
-
await this.refresh();
|
|
7662
|
-
}
|
|
7663
|
-
connect(id) {
|
|
7664
|
-
return new SocketConnection(this.sessionId, id);
|
|
7665
|
-
}
|
|
7666
|
-
getSnapshot() {
|
|
7667
|
-
return this.snapshot;
|
|
7668
|
-
}
|
|
7669
|
-
subscribe(listener) {
|
|
7670
|
-
this.listeners.add(listener);
|
|
7671
|
-
return () => this.listeners.delete(listener);
|
|
7672
|
-
}
|
|
7673
|
-
set(snapshot) {
|
|
7674
|
-
this.snapshot = snapshot;
|
|
7675
|
-
for (const listener of this.listeners) listener();
|
|
7676
|
-
}
|
|
7677
|
-
};
|
|
7678
|
-
//#endregion
|
|
7679
7713
|
//#region src/client/TerminalPanel.tsx
|
|
7680
7714
|
const LIGHT_ANSI = {
|
|
7681
7715
|
black: "#000000",
|
|
@@ -7710,102 +7744,109 @@ window.__ModuleLoader__.load({
|
|
|
7710
7744
|
};
|
|
7711
7745
|
}
|
|
7712
7746
|
function XtermView({ workspace, id, colorScheme }) {
|
|
7747
|
+
const model = workspace.view(id);
|
|
7748
|
+
const state = (0, react.useSyncExternalStore)(model.state.subscribe, model.state.getSnapshot);
|
|
7713
7749
|
const root = (0, react.useRef)(null);
|
|
7714
|
-
const
|
|
7715
|
-
const
|
|
7716
|
-
const
|
|
7717
|
-
const
|
|
7718
|
-
|
|
7750
|
+
const screen = (0, react.useRef)();
|
|
7751
|
+
const fit = (0, react.useRef)();
|
|
7752
|
+
const revision = (0, react.useRef)(0);
|
|
7753
|
+
const current = (0, react.useRef)(state);
|
|
7754
|
+
current.current = state;
|
|
7755
|
+
const measure = () => {
|
|
7756
|
+
const node = root.current;
|
|
7757
|
+
const dimensions = fit.current?.proposeDimensions();
|
|
7758
|
+
if (!node?.clientWidth || !node.clientHeight || !current.current.writable || dimensions === void 0) return;
|
|
7759
|
+
const cols = Math.min(dimensions.cols, current.current.environment?.maxCols ?? 500);
|
|
7760
|
+
const rows = Math.min(dimensions.rows, current.current.environment?.maxRows ?? 200);
|
|
7761
|
+
if (cols < 2 || rows < 1) return;
|
|
7762
|
+
screen.current?.resize(cols, rows);
|
|
7763
|
+
model.resize(cols, rows);
|
|
7764
|
+
};
|
|
7765
|
+
(0, react.useLayoutEffect)(() => {
|
|
7719
7766
|
if (root.current === null) return;
|
|
7720
|
-
const background = root.current === null ? void 0 : getComputedStyle(root.current).backgroundColor;
|
|
7721
7767
|
const terminal = new import_xterm.Terminal({
|
|
7722
|
-
convertEol: false,
|
|
7723
7768
|
cursorBlink: true,
|
|
7724
7769
|
fontFamily: "ui-monospace,SFMono-Regular,Menlo,Consolas,monospace",
|
|
7725
7770
|
fontSize: 13,
|
|
7726
7771
|
minimumContrastRatio: 4.5,
|
|
7727
7772
|
theme: {
|
|
7728
7773
|
...terminalTheme(colorScheme),
|
|
7729
|
-
|
|
7730
|
-
}
|
|
7774
|
+
background: getComputedStyle(root.current).backgroundColor
|
|
7775
|
+
},
|
|
7776
|
+
scrollback: 1e3
|
|
7731
7777
|
});
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
terminal.loadAddon(fit);
|
|
7778
|
+
const addon = new import_addon_fit.FitAddon();
|
|
7779
|
+
terminal.loadAddon(addon);
|
|
7735
7780
|
terminal.open(root.current);
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
return;
|
|
7743
|
-
}
|
|
7744
|
-
const output = connection.subscribe((value) => {
|
|
7745
|
-
if (value.replay) {
|
|
7746
|
-
replaying.current = true;
|
|
7747
|
-
clearTimeout(replayGuard.current);
|
|
7748
|
-
}
|
|
7749
|
-
terminal.write(value.data, () => {
|
|
7750
|
-
if (value.replay) replayGuard.current = setTimeout(() => {
|
|
7751
|
-
replaying.current = false;
|
|
7752
|
-
}, 250);
|
|
7753
|
-
});
|
|
7754
|
-
});
|
|
7755
|
-
const connectionError = connection.subscribeError(setError);
|
|
7756
|
-
const input = terminal.onData((data) => {
|
|
7757
|
-
if (!replaying.current || !isTerminalProtocolReply(data)) connection.write(data);
|
|
7758
|
-
});
|
|
7759
|
-
const resize = terminal.onResize(({ cols, rows }) => connection.resize(cols, rows));
|
|
7760
|
-
const observer = new ResizeObserver(() => {
|
|
7761
|
-
try {
|
|
7762
|
-
fit.fit();
|
|
7763
|
-
} catch {}
|
|
7764
|
-
});
|
|
7781
|
+
terminal.textarea?.setAttribute("aria-label", "终端输入");
|
|
7782
|
+
screen.current = terminal;
|
|
7783
|
+
fit.current = addon;
|
|
7784
|
+
revision.current = 0;
|
|
7785
|
+
const input = terminal.onData((data) => model.write(data));
|
|
7786
|
+
const observer = new ResizeObserver(measure);
|
|
7765
7787
|
observer.observe(root.current);
|
|
7766
|
-
try {
|
|
7767
|
-
fit.fit();
|
|
7768
|
-
terminal.focus();
|
|
7769
|
-
} catch (exception) {
|
|
7770
|
-
setError(exception instanceof Error ? exception.message : String(exception));
|
|
7771
|
-
}
|
|
7772
7788
|
return () => {
|
|
7773
|
-
terminalRef.current = void 0;
|
|
7774
|
-
clearTimeout(replayGuard.current);
|
|
7775
7789
|
observer.disconnect();
|
|
7776
|
-
connectionError();
|
|
7777
7790
|
input.dispose();
|
|
7778
|
-
resize.dispose();
|
|
7779
|
-
output();
|
|
7780
|
-
connection.close();
|
|
7781
7791
|
terminal.dispose();
|
|
7792
|
+
screen.current = void 0;
|
|
7793
|
+
fit.current = void 0;
|
|
7782
7794
|
};
|
|
7783
|
-
}, [
|
|
7795
|
+
}, [model]);
|
|
7796
|
+
(0, react.useEffect)(() => model.mount(), [model]);
|
|
7797
|
+
(0, react.useLayoutEffect)(() => {
|
|
7798
|
+
const terminal = screen.current;
|
|
7799
|
+
const render = state.render;
|
|
7800
|
+
if (terminal === void 0 || render === void 0 || render.revision <= revision.current) return;
|
|
7801
|
+
revision.current = render.revision;
|
|
7802
|
+
if (render.frame.type === "snapshot") {
|
|
7803
|
+
terminal.reset();
|
|
7804
|
+
terminal.resize(render.frame.info.cols, render.frame.info.rows);
|
|
7805
|
+
}
|
|
7806
|
+
terminal.write(render.frame.type === "snapshot" ? render.frame.screen : render.frame.data, () => model.acknowledge(render.revision));
|
|
7807
|
+
}, [state.render, model]);
|
|
7808
|
+
(0, react.useLayoutEffect)(() => {
|
|
7809
|
+
if (screen.current === void 0) return;
|
|
7810
|
+
screen.current.options.disableStdin = !state.writable;
|
|
7811
|
+
if (state.writable) {
|
|
7812
|
+
measure();
|
|
7813
|
+
screen.current.focus();
|
|
7814
|
+
} else if (state.info !== void 0) screen.current.resize(state.info.cols, state.info.rows);
|
|
7815
|
+
}, [
|
|
7816
|
+
state.writable,
|
|
7817
|
+
state.info?.cols,
|
|
7818
|
+
state.info?.rows,
|
|
7819
|
+
model
|
|
7820
|
+
]);
|
|
7784
7821
|
(0, react.useEffect)(() => {
|
|
7785
|
-
if (
|
|
7786
|
-
const background = root.current === null ? void 0 : getComputedStyle(root.current).backgroundColor;
|
|
7787
|
-
terminalRef.current.options.theme = {
|
|
7822
|
+
if (screen.current !== void 0) screen.current.options.theme = {
|
|
7788
7823
|
...terminalTheme(colorScheme),
|
|
7789
|
-
...
|
|
7824
|
+
...root.current === null ? {} : { background: getComputedStyle(root.current).backgroundColor }
|
|
7790
7825
|
};
|
|
7791
7826
|
}, [colorScheme]);
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7827
|
+
const error = terminalIssue(state);
|
|
7828
|
+
const retry = state.phase === "failed" || state.phase === "disconnected";
|
|
7829
|
+
const readOnly = state.phase === "connected" && state.info?.state === "running" && !state.writable;
|
|
7830
|
+
const ended = state.info?.state === "exited";
|
|
7831
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
7832
|
+
className: "dvw-terminal-pane",
|
|
7833
|
+
children: [(error || retry || readOnly || ended || state.info === void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7834
|
+
className: "dvw-terminal-notice",
|
|
7835
|
+
role: "status",
|
|
7836
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: error ?? (ended ? `进程已退出(${state.info?.exitCode ?? "—"})` : readOnly ? "其他页面正在控制此终端" : retry ? "终端连接已断开" : "正在启动终端…") }), (retry || readOnly) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7837
|
+
onClick: () => state.info === void 0 ? void model.refresh() : model.connect(),
|
|
7838
|
+
children: readOnly ? "接管输入" : "重新连接"
|
|
7839
|
+
})]
|
|
7840
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7841
|
+
ref: root,
|
|
7842
|
+
className: "dvw-terminal-host"
|
|
7843
|
+
})]
|
|
7798
7844
|
});
|
|
7799
7845
|
}
|
|
7800
|
-
/**
|
|
7801
|
-
function TerminalPanel({
|
|
7802
|
-
const
|
|
7803
|
-
|
|
7804
|
-
sessionId,
|
|
7805
|
-
value: new TerminalWorkspaceController(sessionId)
|
|
7806
|
-
};
|
|
7807
|
-
const workspace = workspaceRef.current.value;
|
|
7808
|
-
const snapshot = (0, react.useSyncExternalStore)(workspace.subscribe.bind(workspace), workspace.getSnapshot.bind(workspace));
|
|
7846
|
+
/** Keep the incumbent terminal layout while using the official process and stream models. */
|
|
7847
|
+
function TerminalPanel({ workspace, colorScheme }) {
|
|
7848
|
+
const snapshot = (0, react.useSyncExternalStore)(workspace.subscribe, workspace.getSnapshot);
|
|
7849
|
+
const closeFailures = (0, react.useSyncExternalStore)(workspace.closeFailures.subscribe, workspace.closeFailures.getSnapshot);
|
|
7809
7850
|
const [active, setActive] = (0, react.useState)();
|
|
7810
7851
|
const [context, setContext] = (0, react.useState)();
|
|
7811
7852
|
const [renaming, setRenaming] = (0, react.useState)();
|
|
@@ -7872,18 +7913,34 @@ window.__ModuleLoader__.load({
|
|
|
7872
7913
|
children: [
|
|
7873
7914
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7874
7915
|
className: "dvw-terminal-main",
|
|
7875
|
-
children: [
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7916
|
+
children: [
|
|
7917
|
+
snapshot.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7918
|
+
className: "dvw-terminal-error",
|
|
7919
|
+
children: snapshot.error
|
|
7920
|
+
}),
|
|
7921
|
+
closeFailures.map((failure) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7922
|
+
className: "dvw-terminal-notice",
|
|
7923
|
+
role: "alert",
|
|
7924
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
7925
|
+
"终端“",
|
|
7926
|
+
failure.title,
|
|
7927
|
+
"”未能关闭:",
|
|
7928
|
+
failure.message
|
|
7929
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7930
|
+
onClick: () => workspace.retryClose(failure.id),
|
|
7931
|
+
children: "重试关闭"
|
|
7932
|
+
})]
|
|
7933
|
+
}, failure.id)),
|
|
7934
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7935
|
+
className: "dvw-terminal-panes",
|
|
7936
|
+
"data-split": shown.length > 1 || void 0,
|
|
7937
|
+
children: shown.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XtermView, {
|
|
7938
|
+
workspace,
|
|
7939
|
+
id,
|
|
7940
|
+
colorScheme
|
|
7941
|
+
}, id))
|
|
7942
|
+
})
|
|
7943
|
+
]
|
|
7887
7944
|
}),
|
|
7888
7945
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7889
7946
|
className: "dvw-terminal-resizer",
|
|
@@ -7992,6 +8049,61 @@ window.__ModuleLoader__.load({
|
|
|
7992
8049
|
});
|
|
7993
8050
|
}
|
|
7994
8051
|
//#endregion
|
|
8052
|
+
//#region src/client/api.ts
|
|
8053
|
+
var ApiError = class extends Error {
|
|
8054
|
+
code;
|
|
8055
|
+
constructor(code, message) {
|
|
8056
|
+
super(message);
|
|
8057
|
+
this.code = code;
|
|
8058
|
+
}
|
|
8059
|
+
};
|
|
8060
|
+
/** Back off while DSH publishes the current session after startup; every view shares this retry. */
|
|
8061
|
+
function sessionRetryDelay(error, attempt) {
|
|
8062
|
+
if (!(error instanceof ApiError) || error.code !== "session-not-found" || attempt >= 10) return void 0;
|
|
8063
|
+
return Math.min(250 * (attempt + 1), 1e3);
|
|
8064
|
+
}
|
|
8065
|
+
function wait(ms, signal) {
|
|
8066
|
+
return new Promise((resolve, reject) => {
|
|
8067
|
+
const abort = () => {
|
|
8068
|
+
clearTimeout(timer);
|
|
8069
|
+
reject(signal?.reason ?? /* @__PURE__ */ new Error("aborted"));
|
|
8070
|
+
};
|
|
8071
|
+
const timer = setTimeout(() => {
|
|
8072
|
+
signal?.removeEventListener("abort", abort);
|
|
8073
|
+
resolve();
|
|
8074
|
+
}, ms);
|
|
8075
|
+
if (signal?.aborted === true) {
|
|
8076
|
+
abort();
|
|
8077
|
+
return;
|
|
8078
|
+
}
|
|
8079
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
8080
|
+
});
|
|
8081
|
+
}
|
|
8082
|
+
async function request$1(method, body, signal) {
|
|
8083
|
+
const response = await fetch(`/dsh-vscode/api/${method}`, {
|
|
8084
|
+
method: "POST",
|
|
8085
|
+
headers: { "content-type": "application/json" },
|
|
8086
|
+
body: JSON.stringify(body),
|
|
8087
|
+
signal
|
|
8088
|
+
});
|
|
8089
|
+
const answer = await response.json();
|
|
8090
|
+
if (!response.ok || !answer.ok) throw new ApiError(answer.error?.code ?? "request-failed", answer.error?.message ?? `request failed (${response.status})`);
|
|
8091
|
+
return answer.value;
|
|
8092
|
+
}
|
|
8093
|
+
async function api(method, body, signal) {
|
|
8094
|
+
return withSessionRetry(() => request$1(method, body, signal), signal);
|
|
8095
|
+
}
|
|
8096
|
+
/** Retry an operation while DSH is still publishing the selected session. */
|
|
8097
|
+
async function withSessionRetry(operation, signal) {
|
|
8098
|
+
for (let attempt = 0;; attempt++) try {
|
|
8099
|
+
return await operation();
|
|
8100
|
+
} catch (error) {
|
|
8101
|
+
const delay = sessionRetryDelay(error, attempt);
|
|
8102
|
+
if (delay === void 0) throw error;
|
|
8103
|
+
await wait(delay, signal);
|
|
8104
|
+
}
|
|
8105
|
+
}
|
|
8106
|
+
//#endregion
|
|
7995
8107
|
//#region node_modules/.pnpm/vscode-icons-js@11.6.1/node_modules/vscode-icons-js/dist/generated/FileExtensions1ToIcon.js
|
|
7996
8108
|
var require_FileExtensions1ToIcon = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
7997
8109
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -14683,6 +14795,196 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
14683
14795
|
});
|
|
14684
14796
|
}
|
|
14685
14797
|
//#endregion
|
|
14798
|
+
//#region src/client/dshPanels.ts
|
|
14799
|
+
/** Locate the central panel DSH renders when a global panel (Plugins, market…) is open. */
|
|
14800
|
+
function findDshGlobalPanel(documentRoot = document) {
|
|
14801
|
+
return documentRoot.querySelector("[data-global-panel]");
|
|
14802
|
+
}
|
|
14803
|
+
const DSH_PANEL_TITLES = {
|
|
14804
|
+
plugins: "插件",
|
|
14805
|
+
"dsh-market": "插件市场",
|
|
14806
|
+
automations: "自动化任务",
|
|
14807
|
+
ssh: "SSH"
|
|
14808
|
+
};
|
|
14809
|
+
/** Tab-style label for an embedded DSH panel; unknown ids keep their own name. */
|
|
14810
|
+
function dshPanelLabel(id) {
|
|
14811
|
+
return DSH_PANEL_TITLES[id] ?? id;
|
|
14812
|
+
}
|
|
14813
|
+
//#endregion
|
|
14814
|
+
//#region src/client/DshPanelPage.tsx
|
|
14815
|
+
/**
|
|
14816
|
+
* Pin a DSH global panel over the workbench editor while its tab is active.
|
|
14817
|
+
* The official page keeps its own DOM and state; switching to a file only
|
|
14818
|
+
* hides it, so returning to the tab does not rebuild the page.
|
|
14819
|
+
*/
|
|
14820
|
+
function DshPanelPage({ panelId, active }) {
|
|
14821
|
+
const activeRef = (0, react.useRef)(active);
|
|
14822
|
+
activeRef.current = active;
|
|
14823
|
+
(0, react.useLayoutEffect)(() => {
|
|
14824
|
+
let panel = null;
|
|
14825
|
+
let frame = 0;
|
|
14826
|
+
const clear = (node) => {
|
|
14827
|
+
node.removeAttribute("data-dvw-dsh-page");
|
|
14828
|
+
node.removeAttribute("data-dvw-dsh-hidden");
|
|
14829
|
+
for (const property of [
|
|
14830
|
+
"left",
|
|
14831
|
+
"top",
|
|
14832
|
+
"width",
|
|
14833
|
+
"height"
|
|
14834
|
+
]) node.style.removeProperty(property);
|
|
14835
|
+
};
|
|
14836
|
+
const place = () => {
|
|
14837
|
+
const next = findDshGlobalPanel();
|
|
14838
|
+
if (next !== panel) {
|
|
14839
|
+
if (panel !== null) clear(panel);
|
|
14840
|
+
panel = next;
|
|
14841
|
+
panel?.setAttribute("data-dvw-dsh-page", "");
|
|
14842
|
+
}
|
|
14843
|
+
if (panel === null) return;
|
|
14844
|
+
panel.toggleAttribute("data-dvw-dsh-hidden", !activeRef.current);
|
|
14845
|
+
if (!activeRef.current) return;
|
|
14846
|
+
const editor = document.querySelector(".dvw-editor");
|
|
14847
|
+
if (editor === null) return;
|
|
14848
|
+
const rect = editor.getBoundingClientRect();
|
|
14849
|
+
if (rect.width <= 0 || rect.height <= 0) return;
|
|
14850
|
+
panel.style.setProperty("left", `${Math.round(rect.left)}px`);
|
|
14851
|
+
panel.style.setProperty("top", `${Math.round(rect.top)}px`);
|
|
14852
|
+
panel.style.setProperty("width", `${Math.round(rect.width)}px`);
|
|
14853
|
+
panel.style.setProperty("height", `${Math.round(rect.height)}px`);
|
|
14854
|
+
};
|
|
14855
|
+
const schedule = () => {
|
|
14856
|
+
if (frame !== 0) return;
|
|
14857
|
+
frame = requestAnimationFrame(() => {
|
|
14858
|
+
frame = 0;
|
|
14859
|
+
place();
|
|
14860
|
+
});
|
|
14861
|
+
};
|
|
14862
|
+
place();
|
|
14863
|
+
const resize = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(schedule);
|
|
14864
|
+
const editor = document.querySelector(".dvw-editor");
|
|
14865
|
+
if (editor !== null) resize?.observe(editor);
|
|
14866
|
+
window.addEventListener("resize", schedule);
|
|
14867
|
+
const observer = new MutationObserver((records) => {
|
|
14868
|
+
if (records.every((record) => record.target instanceof Element && record.target.closest(".dvw-overlay") !== null)) return;
|
|
14869
|
+
schedule();
|
|
14870
|
+
});
|
|
14871
|
+
observer.observe(document.body, {
|
|
14872
|
+
childList: true,
|
|
14873
|
+
subtree: true
|
|
14874
|
+
});
|
|
14875
|
+
return () => {
|
|
14876
|
+
observer.disconnect();
|
|
14877
|
+
resize?.disconnect();
|
|
14878
|
+
cancelAnimationFrame(frame);
|
|
14879
|
+
window.removeEventListener("resize", schedule);
|
|
14880
|
+
if (panel !== null) clear(panel);
|
|
14881
|
+
};
|
|
14882
|
+
}, [panelId, active]);
|
|
14883
|
+
return null;
|
|
14884
|
+
}
|
|
14885
|
+
//#endregion
|
|
14886
|
+
//#region src/client/DshBrowserPage.tsx
|
|
14887
|
+
/** Present the original browser DOM without moving React-owned nodes or rebuilding webviews. */
|
|
14888
|
+
const PALETTE = {
|
|
14889
|
+
"--dsw-alias-bg-base": "--dvw-surface-1",
|
|
14890
|
+
"--dsw-alias-bg-layer-1": "--dvw-surface-2",
|
|
14891
|
+
"--dsw-alias-bg-layer-2": "--dvw-surface-3",
|
|
14892
|
+
"--dsw-alias-label-primary": "--dvw-text",
|
|
14893
|
+
"--dsw-alias-label-secondary": "--dvw-text-2",
|
|
14894
|
+
"--dsw-alias-label-tertiary": "--dvw-text-3",
|
|
14895
|
+
"--dsw-alias-border-l2": "--dvw-border",
|
|
14896
|
+
"--dsw-alias-border-l3": "--dvw-border-soft",
|
|
14897
|
+
"--dsw-alias-interactive-bg-hover": "--dvw-hover",
|
|
14898
|
+
"--dsw-alias-interactive-bg-active": "--dvw-active"
|
|
14899
|
+
};
|
|
14900
|
+
function DshBrowserPage({ sessionId, tabId, active, colorScheme }) {
|
|
14901
|
+
(0, react.useLayoutEffect)(() => {
|
|
14902
|
+
let page;
|
|
14903
|
+
let restore;
|
|
14904
|
+
let frame = 0;
|
|
14905
|
+
const place = () => {
|
|
14906
|
+
const next = [...document.querySelectorAll("div[data-sidebar-right-tab]")].find((node) => node.dataset.sidebarRightTab === tabId && node.closest("[data-sidebar-right-session]")?.getAttribute("data-sidebar-right-session") === sessionId);
|
|
14907
|
+
if (next !== page) {
|
|
14908
|
+
restore?.();
|
|
14909
|
+
page = next;
|
|
14910
|
+
if (page !== void 0) {
|
|
14911
|
+
const node = page;
|
|
14912
|
+
const popover = node.getAttribute("popover");
|
|
14913
|
+
const styles = [
|
|
14914
|
+
"left",
|
|
14915
|
+
"top",
|
|
14916
|
+
"width",
|
|
14917
|
+
"height",
|
|
14918
|
+
"color-scheme",
|
|
14919
|
+
...Object.keys(PALETTE)
|
|
14920
|
+
].map((property) => [
|
|
14921
|
+
property,
|
|
14922
|
+
node.style.getPropertyValue(property),
|
|
14923
|
+
node.style.getPropertyPriority(property)
|
|
14924
|
+
]);
|
|
14925
|
+
node.setAttribute("popover", "manual");
|
|
14926
|
+
node.setAttribute("data-dvw-browser-page", "");
|
|
14927
|
+
restore = () => {
|
|
14928
|
+
if (node.matches(":popover-open")) node.hidePopover();
|
|
14929
|
+
if (popover === null) node.removeAttribute("popover");
|
|
14930
|
+
else node.setAttribute("popover", popover);
|
|
14931
|
+
node.removeAttribute("data-dvw-browser-page");
|
|
14932
|
+
for (const [property, value, priority] of styles) node.style.setProperty(property, value, priority);
|
|
14933
|
+
};
|
|
14934
|
+
}
|
|
14935
|
+
}
|
|
14936
|
+
if (page === void 0) return;
|
|
14937
|
+
const rect = document.querySelector(".dvw-editor")?.getBoundingClientRect();
|
|
14938
|
+
if (!(active && rect !== void 0 && rect.width > 0 && rect.height > 0)) {
|
|
14939
|
+
if (page.matches(":popover-open")) page.hidePopover();
|
|
14940
|
+
return;
|
|
14941
|
+
}
|
|
14942
|
+
for (const [property, value] of Object.entries({
|
|
14943
|
+
left: rect.left,
|
|
14944
|
+
top: rect.top,
|
|
14945
|
+
width: rect.width,
|
|
14946
|
+
height: rect.height
|
|
14947
|
+
})) page.style.setProperty(property, `${Math.round(value)}px`, "important");
|
|
14948
|
+
const overlay = document.querySelector(".dvw-overlay");
|
|
14949
|
+
if (overlay !== null) {
|
|
14950
|
+
const palette = getComputedStyle(overlay);
|
|
14951
|
+
for (const [alias, token] of Object.entries(PALETTE)) page.style.setProperty(alias, palette.getPropertyValue(token));
|
|
14952
|
+
}
|
|
14953
|
+
page.style.setProperty("color-scheme", colorScheme === "dark" ? "dark" : "light");
|
|
14954
|
+
if (!page.matches(":popover-open")) page.showPopover();
|
|
14955
|
+
};
|
|
14956
|
+
const schedule = () => {
|
|
14957
|
+
if (frame === 0) frame = requestAnimationFrame(() => {
|
|
14958
|
+
frame = 0;
|
|
14959
|
+
place();
|
|
14960
|
+
});
|
|
14961
|
+
};
|
|
14962
|
+
place();
|
|
14963
|
+
const resize = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(schedule);
|
|
14964
|
+
const editor = document.querySelector(".dvw-editor");
|
|
14965
|
+
if (editor !== null) resize?.observe(editor);
|
|
14966
|
+
const observer = new MutationObserver(schedule);
|
|
14967
|
+
observer.observe(document.body, {
|
|
14968
|
+
childList: true,
|
|
14969
|
+
subtree: true
|
|
14970
|
+
});
|
|
14971
|
+
window.addEventListener("resize", schedule);
|
|
14972
|
+
return () => {
|
|
14973
|
+
observer.disconnect();
|
|
14974
|
+
resize?.disconnect();
|
|
14975
|
+
window.removeEventListener("resize", schedule);
|
|
14976
|
+
cancelAnimationFrame(frame);
|
|
14977
|
+
restore?.();
|
|
14978
|
+
};
|
|
14979
|
+
}, [
|
|
14980
|
+
sessionId,
|
|
14981
|
+
tabId,
|
|
14982
|
+
active,
|
|
14983
|
+
colorScheme
|
|
14984
|
+
]);
|
|
14985
|
+
return null;
|
|
14986
|
+
}
|
|
14987
|
+
//#endregion
|
|
14686
14988
|
//#region src/client/ActivityBar.tsx
|
|
14687
14989
|
/** Keep known ids in saved order, appending newly added views at the end. */
|
|
14688
14990
|
function normalizeActivityOrder(value, known) {
|
|
@@ -15077,6 +15379,54 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
15077
15379
|
}), document.body);
|
|
15078
15380
|
}
|
|
15079
15381
|
//#endregion
|
|
15382
|
+
//#region src/client/websocket.ts
|
|
15383
|
+
const WEB_PAGE_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
15384
|
+
"http:",
|
|
15385
|
+
"https:",
|
|
15386
|
+
"blob:",
|
|
15387
|
+
"data:",
|
|
15388
|
+
"about:",
|
|
15389
|
+
"filesystem:"
|
|
15390
|
+
]);
|
|
15391
|
+
/** Parse a shell-published base only when it is a credential-free HTTP(S) origin. */
|
|
15392
|
+
function networkBase(value) {
|
|
15393
|
+
if (typeof value !== "string" || value === "") return void 0;
|
|
15394
|
+
let url;
|
|
15395
|
+
try {
|
|
15396
|
+
url = new URL(value);
|
|
15397
|
+
} catch {
|
|
15398
|
+
return;
|
|
15399
|
+
}
|
|
15400
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return void 0;
|
|
15401
|
+
if (url.username !== "" || url.password !== "" || url.host === "") return void 0;
|
|
15402
|
+
return {
|
|
15403
|
+
protocol: url.protocol,
|
|
15404
|
+
host: url.host
|
|
15405
|
+
};
|
|
15406
|
+
}
|
|
15407
|
+
/** Read the Host origin published by the DSH Desktop shell before application boot. */
|
|
15408
|
+
function transportStreamBaseUrl(globals = globalThis) {
|
|
15409
|
+
const transport = globals.__DSH_TRANSPORT__;
|
|
15410
|
+
return typeof transport?.streamBaseUrl === "string" ? transport.streamBaseUrl : void 0;
|
|
15411
|
+
}
|
|
15412
|
+
/**
|
|
15413
|
+
* Resolve an absolute workbench route to a WebSocket URL.
|
|
15414
|
+
*
|
|
15415
|
+
* Network pages keep their own origin. Application-delivered pages such as
|
|
15416
|
+
* `dsh-app://app/` have no WebSocket transport of their own, so they must use
|
|
15417
|
+
* the local Host origin published by the desktop shell.
|
|
15418
|
+
*/
|
|
15419
|
+
function websocketUrl(path, location = globalThis.location, streamBaseUrl = transportStreamBaseUrl()) {
|
|
15420
|
+
const route = path.startsWith("/") ? path : `/${path}`;
|
|
15421
|
+
if (WEB_PAGE_PROTOCOLS.has(location.protocol)) {
|
|
15422
|
+
if (location.host === "") return void 0;
|
|
15423
|
+
return `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}${route}`;
|
|
15424
|
+
}
|
|
15425
|
+
const base = networkBase(streamBaseUrl);
|
|
15426
|
+
if (base === void 0) return void 0;
|
|
15427
|
+
return `${base.protocol === "https:" ? "wss" : "ws"}://${base.host}${route}`;
|
|
15428
|
+
}
|
|
15429
|
+
//#endregion
|
|
15080
15430
|
//#region src/client/lsp.ts
|
|
15081
15431
|
/** Minimal Language Server Protocol client that rides a WebSocket bridge to a host-spawned server. */
|
|
15082
15432
|
/** LSP CompletionItemKind and SymbolKind share the numeric layout 1–25; Monaco's enums differ, so map explicitly. */
|
|
@@ -49735,6 +50085,14 @@ section.${c}>footer { z-index: 1; }
|
|
|
49735
50085
|
} else workbench.toggleBottomPanel("terminal");
|
|
49736
50086
|
return true;
|
|
49737
50087
|
}
|
|
50088
|
+
/** Match the official desktop browser shortcut while the workbench owns focus. */
|
|
50089
|
+
function handleBrowserShortcut(event, workbench) {
|
|
50090
|
+
if (!workbench.getSnapshot().visible || event.isComposing || !(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey || event.code !== "KeyT") return false;
|
|
50091
|
+
event.preventDefault();
|
|
50092
|
+
event.stopImmediatePropagation();
|
|
50093
|
+
window.dispatchEvent(new Event("dvw-browser-new"));
|
|
50094
|
+
return true;
|
|
50095
|
+
}
|
|
49738
50096
|
//#endregion
|
|
49739
50097
|
//#region src/client/workspaceState.ts
|
|
49740
50098
|
/** Remove editor state that belongs to the previous workspace. */
|
|
@@ -51565,7 +51923,7 @@ section.${c}>footer { z-index: 1; }
|
|
|
51565
51923
|
const ExplorerView = (0, react.memo)(Explorer);
|
|
51566
51924
|
const SearchView = (0, react.memo)(Search);
|
|
51567
51925
|
const GitView = (0, react.memo)(Git);
|
|
51568
|
-
function Workbench({ service, sessionId, cwd, navigation }) {
|
|
51926
|
+
function Workbench({ service, browser, sessionId, cwd, navigation, dshPanelId: hostDshPanelId, onOpenDshPanel, onRestoreConversation, onCloseDshPanel }) {
|
|
51569
51927
|
const [snapshot, setSnapshot] = (0, react.useState)(() => service.getSnapshot());
|
|
51570
51928
|
const [panels, setPanels] = (0, react.useState)(() => service.getPanels());
|
|
51571
51929
|
(0, react.useEffect)(() => service.subscribe(() => {
|
|
@@ -51575,6 +51933,9 @@ section.${c}>footer { z-index: 1; }
|
|
|
51575
51933
|
const [workspace, setWorkspace] = (0, react.useState)();
|
|
51576
51934
|
const [tabs, setTabs] = (0, react.useState)([]);
|
|
51577
51935
|
const [active, setActive] = (0, react.useState)();
|
|
51936
|
+
const [dshTabActive, setDshTabActive] = (0, react.useState)(hostDshPanelId !== void 0);
|
|
51937
|
+
const [dshTabId, setDshTabId] = (0, react.useState)(hostDshPanelId);
|
|
51938
|
+
const dshPanelId = dshTabId;
|
|
51578
51939
|
const [error, setError] = (0, react.useState)();
|
|
51579
51940
|
const [panelHeight, setPanelHeight] = (0, react.useState)(260);
|
|
51580
51941
|
const [sideWidth, setSideWidth] = (0, react.useState)(210);
|
|
@@ -51595,8 +51956,96 @@ section.${c}>footer { z-index: 1; }
|
|
|
51595
51956
|
return Number.isFinite(saved) && saved >= 11 && saved <= 20 ? saved : 14;
|
|
51596
51957
|
});
|
|
51597
51958
|
const [tabMenu, setTabMenu] = (0, react.useState)();
|
|
51959
|
+
const [browserSnapshot, setBrowserSnapshot] = (0, react.useState)(() => browser?.getSnapshot() ?? {
|
|
51960
|
+
available: false,
|
|
51961
|
+
tabs: []
|
|
51962
|
+
});
|
|
51963
|
+
const [browserId, setBrowserId] = (0, react.useState)();
|
|
51964
|
+
const browserTabs = browserSnapshot.tabs.filter((tab) => tab.sessionId === sessionId);
|
|
51965
|
+
const previousBrowserIds = (0, react.useRef)(new Set(browserTabs.map((tab) => tab.id)));
|
|
51966
|
+
(0, react.useEffect)(() => {
|
|
51967
|
+
if (browser === void 0) return;
|
|
51968
|
+
setBrowserSnapshot(browser.getSnapshot());
|
|
51969
|
+
return browser.subscribe(() => setBrowserSnapshot(browser.getSnapshot()));
|
|
51970
|
+
}, [browser]);
|
|
51971
|
+
(0, react.useEffect)(() => {
|
|
51972
|
+
const next = new Set(browserTabs.map((tab) => tab.id));
|
|
51973
|
+
const added = browserTabs.find((tab) => !previousBrowserIds.current.has(tab.id));
|
|
51974
|
+
previousBrowserIds.current = next;
|
|
51975
|
+
if (added !== void 0 && snapshot.visible) {
|
|
51976
|
+
setBrowserId(added.id);
|
|
51977
|
+
setDshTabActive(false);
|
|
51978
|
+
} else if (browserId !== void 0 && !next.has(browserId)) setBrowserId(void 0);
|
|
51979
|
+
}, [
|
|
51980
|
+
browserSnapshot,
|
|
51981
|
+
sessionId,
|
|
51982
|
+
browserId,
|
|
51983
|
+
snapshot.visible
|
|
51984
|
+
]);
|
|
51985
|
+
const browserRequest = (0, react.useRef)();
|
|
51986
|
+
(0, react.useEffect)(() => () => browserRequest.current?.abort(), [
|
|
51987
|
+
browser,
|
|
51988
|
+
sessionId,
|
|
51989
|
+
snapshot.visible
|
|
51990
|
+
]);
|
|
51991
|
+
const newBrowser = async () => {
|
|
51992
|
+
if (browser === void 0 || sessionId === void 0) return;
|
|
51993
|
+
setDshTabActive(false);
|
|
51994
|
+
onRestoreConversation?.();
|
|
51995
|
+
browserRequest.current?.abort();
|
|
51996
|
+
const request = new AbortController();
|
|
51997
|
+
browserRequest.current = request;
|
|
51998
|
+
try {
|
|
51999
|
+
setBrowserId(await browser.open(sessionId, request.signal));
|
|
52000
|
+
} catch (error) {
|
|
52001
|
+
if (!request.signal.aborted) setError(error instanceof Error ? error.message : String(error));
|
|
52002
|
+
}
|
|
52003
|
+
};
|
|
52004
|
+
(0, react.useEffect)(() => {
|
|
52005
|
+
if (browserId !== void 0 && !dshTabActive) browser?.focus(browserId);
|
|
52006
|
+
}, [
|
|
52007
|
+
browser,
|
|
52008
|
+
browserId,
|
|
52009
|
+
dshTabActive
|
|
52010
|
+
]);
|
|
52011
|
+
(0, react.useEffect)(() => {
|
|
52012
|
+
if (!snapshot.visible) return;
|
|
52013
|
+
const open = () => void newBrowser();
|
|
52014
|
+
window.addEventListener("dvw-browser-new", open);
|
|
52015
|
+
return () => window.removeEventListener("dvw-browser-new", open);
|
|
52016
|
+
}, [
|
|
52017
|
+
browser,
|
|
52018
|
+
sessionId,
|
|
52019
|
+
snapshot.visible
|
|
52020
|
+
]);
|
|
52021
|
+
(0, react.useEffect)(() => {
|
|
52022
|
+
if (hostDshPanelId !== void 0) setBrowserId(void 0);
|
|
52023
|
+
}, [hostDshPanelId]);
|
|
51598
52024
|
const tabsRef = (0, react.useRef)(tabs);
|
|
51599
52025
|
tabsRef.current = tabs;
|
|
52026
|
+
const dshTabActiveRef = (0, react.useRef)(dshTabActive);
|
|
52027
|
+
dshTabActiveRef.current = dshTabActive;
|
|
52028
|
+
const dshTabIdRef = (0, react.useRef)(dshTabId);
|
|
52029
|
+
dshTabIdRef.current = dshTabId;
|
|
52030
|
+
const hostDshPanelIdRef = (0, react.useRef)(hostDshPanelId);
|
|
52031
|
+
hostDshPanelIdRef.current = hostDshPanelId;
|
|
52032
|
+
const openDshPanelRef = (0, react.useRef)(onOpenDshPanel);
|
|
52033
|
+
openDshPanelRef.current = onOpenDshPanel;
|
|
52034
|
+
const restoreConversationRef = (0, react.useRef)(onRestoreConversation);
|
|
52035
|
+
restoreConversationRef.current = onRestoreConversation;
|
|
52036
|
+
const leaveDshPanel = (0, react.useCallback)(() => {
|
|
52037
|
+
setBrowserId(void 0);
|
|
52038
|
+
const wasActive = dshTabActiveRef.current;
|
|
52039
|
+
setDshTabActive(false);
|
|
52040
|
+
if (wasActive) restoreConversationRef.current?.();
|
|
52041
|
+
}, []);
|
|
52042
|
+
(0, react.useCallback)(() => {
|
|
52043
|
+
setBrowserId(void 0);
|
|
52044
|
+
const id = dshTabIdRef.current;
|
|
52045
|
+
if (id === void 0) return;
|
|
52046
|
+
setDshTabActive(true);
|
|
52047
|
+
if (hostDshPanelIdRef.current !== id) openDshPanelRef.current?.(id);
|
|
52048
|
+
}, []);
|
|
51600
52049
|
const [settingsSection, setSettingsSection] = (0, react.useState)("appearance");
|
|
51601
52050
|
const tabListRef = (0, react.useRef)(null);
|
|
51602
52051
|
const workspaceRequests = (0, react.useRef)(new WorkspaceRequestScope());
|
|
@@ -51645,6 +52094,28 @@ section.${c}>footer { z-index: 1; }
|
|
|
51645
52094
|
(0, react.useEffect)(() => localStorage.setItem("dvw:primary-side-visible", primarySideVisible ? "open" : "closed"), [primarySideVisible]);
|
|
51646
52095
|
(0, react.useEffect)(() => localStorage.setItem("dvw:status-bar-visible", statusVisible ? "open" : "closed"), [statusVisible]);
|
|
51647
52096
|
(0, react.useEffect)(() => localStorage.setItem("dvw:font-size", String(fontSize)), [fontSize]);
|
|
52097
|
+
(0, react.useEffect)(() => {
|
|
52098
|
+
if (hostDshPanelId !== void 0) {
|
|
52099
|
+
setDshTabId(hostDshPanelId);
|
|
52100
|
+
setDshTabActive(true);
|
|
52101
|
+
return;
|
|
52102
|
+
}
|
|
52103
|
+
if (dshTabActiveRef.current) setDshTabId(void 0);
|
|
52104
|
+
}, [hostDshPanelId]);
|
|
52105
|
+
(0, react.useEffect)(() => {
|
|
52106
|
+
if (dshTabActive || dshTabId === void 0 || hostDshPanelId === void 0) return;
|
|
52107
|
+
restoreConversationRef.current?.();
|
|
52108
|
+
}, [
|
|
52109
|
+
dshTabActive,
|
|
52110
|
+
dshTabId,
|
|
52111
|
+
hostDshPanelId
|
|
52112
|
+
]);
|
|
52113
|
+
(0, react.useEffect)(() => {
|
|
52114
|
+
if (!dshTabActive) return;
|
|
52115
|
+
const id = dshTabIdRef.current;
|
|
52116
|
+
if (id === void 0 || hostDshPanelId === id) return;
|
|
52117
|
+
openDshPanelRef.current?.(id);
|
|
52118
|
+
}, [dshTabActive, hostDshPanelId]);
|
|
51648
52119
|
(0, react.useEffect)(() => {
|
|
51649
52120
|
if (tabMenu === void 0) return;
|
|
51650
52121
|
const close = () => setTabMenu(void 0);
|
|
@@ -51704,6 +52175,7 @@ section.${c}>footer { z-index: 1; }
|
|
|
51704
52175
|
highlight,
|
|
51705
52176
|
...line !== void 0 ? { preview: false } : {}
|
|
51706
52177
|
}]);
|
|
52178
|
+
leaveDshPanel();
|
|
51707
52179
|
setActive(path);
|
|
51708
52180
|
};
|
|
51709
52181
|
(0, react.useEffect)(() => {
|
|
@@ -52129,8 +52601,9 @@ section.${c}>footer { z-index: 1; }
|
|
|
52129
52601
|
diffMode: "inline",
|
|
52130
52602
|
diffSourcePath: source
|
|
52131
52603
|
}]);
|
|
52604
|
+
leaveDshPanel();
|
|
52132
52605
|
setActive(key);
|
|
52133
|
-
}, [openPath]);
|
|
52606
|
+
}, [openPath, leaveDshPanel]);
|
|
52134
52607
|
(0, react.useEffect)(() => {
|
|
52135
52608
|
const listener = (event) => void open(event.detail);
|
|
52136
52609
|
window.addEventListener("dvw-open-workspace-path", listener);
|
|
@@ -52209,6 +52682,7 @@ section.${c}>footer { z-index: 1; }
|
|
|
52209
52682
|
"search",
|
|
52210
52683
|
"git",
|
|
52211
52684
|
"terminal",
|
|
52685
|
+
"browser",
|
|
52212
52686
|
"chat"
|
|
52213
52687
|
];
|
|
52214
52688
|
const [activityOrder, setActivityOrder] = (0, react.useState)(() => normalizeActivityOrder(readActivityJSON("dvw:activity-order"), ACTIVITY_IDS));
|
|
@@ -52257,6 +52731,17 @@ section.${c}>footer { z-index: 1; }
|
|
|
52257
52731
|
] })
|
|
52258
52732
|
})]
|
|
52259
52733
|
});
|
|
52734
|
+
const showingDshPanel = dshTabId !== void 0 && dshTabActive && !settingsOpen;
|
|
52735
|
+
const closeDshPanel = () => {
|
|
52736
|
+
setDshTabActive(false);
|
|
52737
|
+
setDshTabId(void 0);
|
|
52738
|
+
onCloseDshPanel?.();
|
|
52739
|
+
};
|
|
52740
|
+
const openFromView = (path, line, column, highlight) => {
|
|
52741
|
+
leaveDshPanel();
|
|
52742
|
+
openPath(path, line, column, highlight);
|
|
52743
|
+
};
|
|
52744
|
+
const chatShown = chatVisible && !settingsOpen && !showingDshPanel;
|
|
52260
52745
|
const markdown = activeTab !== void 0 && !activeTab.path.startsWith("diff:") && /\.md$/i.test(activeTab.path);
|
|
52261
52746
|
const diffMarkdown = activeTab?.diff !== void 0 && /\.md$/i.test(activeTab.diffSourcePath ?? "");
|
|
52262
52747
|
const markdownPreview = markdown || diffMarkdown && activeTab?.preview === true;
|
|
@@ -52265,7 +52750,7 @@ section.${c}>footer { z-index: 1; }
|
|
|
52265
52750
|
className: "dvw-overlay",
|
|
52266
52751
|
"data-dvw-theme": colorScheme,
|
|
52267
52752
|
"data-dvw-theme-name": theme,
|
|
52268
|
-
"data-dvw-chat":
|
|
52753
|
+
"data-dvw-chat": chatShown || void 0,
|
|
52269
52754
|
"data-dvw-primary-side": primarySideVisible || void 0,
|
|
52270
52755
|
"data-dvw-status": statusVisible || void 0,
|
|
52271
52756
|
"data-dvw-bottom-panel": snapshot.bottomPanel || void 0,
|
|
@@ -52280,17 +52765,21 @@ section.${c}>footer { z-index: 1; }
|
|
|
52280
52765
|
onDropCapture: suppressAttachmentDrop,
|
|
52281
52766
|
children: [
|
|
52282
52767
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchTitlebar, { name: workspace?.name }),
|
|
52768
|
+
dshTabId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshPanelPage, {
|
|
52769
|
+
panelId: dshTabId,
|
|
52770
|
+
active: showingDshPanel
|
|
52771
|
+
}),
|
|
52283
52772
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshConversationPanel, {
|
|
52284
|
-
visible:
|
|
52773
|
+
visible: chatShown,
|
|
52285
52774
|
width: chatWidth,
|
|
52286
52775
|
statusHeight: statusVisible ? 30 : 6
|
|
52287
52776
|
}),
|
|
52288
52777
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshConversationTheme, {
|
|
52289
|
-
visible:
|
|
52778
|
+
visible: chatShown,
|
|
52290
52779
|
colorScheme,
|
|
52291
52780
|
followDsh: false
|
|
52292
52781
|
}),
|
|
52293
|
-
|
|
52782
|
+
chatShown && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
|
|
52294
52783
|
className: "dvw-chat",
|
|
52295
52784
|
children: [
|
|
52296
52785
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelResizer, {
|
|
@@ -52595,6 +53084,14 @@ section.${c}>footer { z-index: 1; }
|
|
|
52595
53084
|
disabled: !terminalAvailable,
|
|
52596
53085
|
onActivate: () => toggleTerminal(service)
|
|
52597
53086
|
},
|
|
53087
|
+
{
|
|
53088
|
+
id: "browser",
|
|
53089
|
+
label: "新建浏览器",
|
|
53090
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "globe" }),
|
|
53091
|
+
active: browserId !== void 0,
|
|
53092
|
+
disabled: !browserSnapshot.available || sessionId === void 0,
|
|
53093
|
+
onActivate: () => void newBrowser()
|
|
53094
|
+
},
|
|
52598
53095
|
{
|
|
52599
53096
|
id: "chat",
|
|
52600
53097
|
label: chatVisible ? "关闭 DSH 对话栏 (Ctrl+Alt+B)" : "显示 DSH 对话栏 (Ctrl+Alt+B)",
|
|
@@ -52636,19 +53133,22 @@ section.${c}>footer { z-index: 1; }
|
|
|
52636
53133
|
sessionId,
|
|
52637
53134
|
cwd: workspace.cwd,
|
|
52638
53135
|
selected: active,
|
|
52639
|
-
onOpen:
|
|
53136
|
+
onOpen: openFromView,
|
|
52640
53137
|
onAddToDsh: addEntryToDsh
|
|
52641
53138
|
}),
|
|
52642
53139
|
" ",
|
|
52643
53140
|
snapshot.view === "search" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchView, {
|
|
52644
53141
|
sessionId,
|
|
52645
|
-
onOpen:
|
|
53142
|
+
onOpen: openFromView
|
|
52646
53143
|
}),
|
|
52647
53144
|
" ",
|
|
52648
53145
|
snapshot.view === "git" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GitView, {
|
|
52649
53146
|
sessionId,
|
|
52650
53147
|
preferences: commitPreferences,
|
|
52651
|
-
onDiff:
|
|
53148
|
+
onDiff: (path, diff, title, source) => {
|
|
53149
|
+
leaveDshPanel();
|
|
53150
|
+
openDiff(path, diff, title, source);
|
|
53151
|
+
}
|
|
52652
53152
|
})
|
|
52653
53153
|
]
|
|
52654
53154
|
}),
|
|
@@ -52681,57 +53181,113 @@ section.${c}>footer { z-index: 1; }
|
|
|
52681
53181
|
children: [
|
|
52682
53182
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
52683
53183
|
className: "dvw-tabs",
|
|
52684
|
-
"data-empty": tabs.length === 0 || void 0,
|
|
52685
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
53184
|
+
"data-empty": tabs.length === 0 && dshPanelId === void 0 && browserTabs.length === 0 || void 0,
|
|
53185
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
52686
53186
|
className: "dvw-tab-list",
|
|
52687
53187
|
ref: tabListRef,
|
|
52688
|
-
children:
|
|
52689
|
-
|
|
52690
|
-
|
|
52691
|
-
|
|
52692
|
-
|
|
52693
|
-
|
|
52694
|
-
|
|
52695
|
-
|
|
52696
|
-
|
|
52697
|
-
}
|
|
52698
|
-
|
|
52699
|
-
|
|
52700
|
-
|
|
52701
|
-
|
|
52702
|
-
|
|
52703
|
-
|
|
52704
|
-
|
|
52705
|
-
|
|
52706
|
-
|
|
52707
|
-
|
|
52708
|
-
|
|
52709
|
-
|
|
52710
|
-
|
|
52711
|
-
|
|
52712
|
-
|
|
52713
|
-
|
|
52714
|
-
|
|
52715
|
-
|
|
52716
|
-
|
|
52717
|
-
|
|
52718
|
-
|
|
52719
|
-
|
|
52720
|
-
|
|
52721
|
-
className: "dvw-tab-
|
|
52722
|
-
|
|
52723
|
-
|
|
53188
|
+
children: [
|
|
53189
|
+
browserTabs.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
53190
|
+
className: "dvw-tab",
|
|
53191
|
+
"data-dvw-browser-tab": tab.id,
|
|
53192
|
+
"data-active": browserId === tab.id && !dshTabActive,
|
|
53193
|
+
title: tab.title,
|
|
53194
|
+
onClick: () => {
|
|
53195
|
+
leaveDshPanel();
|
|
53196
|
+
setBrowserId(tab.id);
|
|
53197
|
+
},
|
|
53198
|
+
children: [
|
|
53199
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "globe" }),
|
|
53200
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53201
|
+
className: "dvw-tab-name",
|
|
53202
|
+
children: tab.title
|
|
53203
|
+
}),
|
|
53204
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53205
|
+
className: "dvw-tab-close",
|
|
53206
|
+
onClick: (event) => {
|
|
53207
|
+
event.stopPropagation();
|
|
53208
|
+
browser?.close(tab.sessionId, tab.id);
|
|
53209
|
+
},
|
|
53210
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
|
|
53211
|
+
})
|
|
53212
|
+
]
|
|
53213
|
+
}, tab.id)),
|
|
53214
|
+
dshPanelId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
53215
|
+
className: "dvw-tab",
|
|
53216
|
+
"data-active": dshTabActive,
|
|
53217
|
+
"data-dvw-dsh-tab": "",
|
|
53218
|
+
title: `${dshPanelLabel(dshPanelId)}(DSH 官方页面)`,
|
|
53219
|
+
onClick: () => setDshTabActive(true),
|
|
53220
|
+
children: [
|
|
53221
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dvw-dsh-tab-mark" }),
|
|
53222
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53223
|
+
className: "dvw-tab-name",
|
|
53224
|
+
children: dshPanelLabel(dshPanelId)
|
|
53225
|
+
}),
|
|
53226
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53227
|
+
className: "dvw-tab-close",
|
|
53228
|
+
onClick: (event) => {
|
|
53229
|
+
event.stopPropagation();
|
|
53230
|
+
closeDshPanel();
|
|
53231
|
+
},
|
|
53232
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
|
|
53233
|
+
})
|
|
53234
|
+
]
|
|
53235
|
+
}),
|
|
53236
|
+
tabs.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
53237
|
+
className: "dvw-tab",
|
|
53238
|
+
"data-active": tab.path === active && !dshTabActive && browserId === void 0,
|
|
53239
|
+
title: tab.diffSourcePath ?? tab.path,
|
|
53240
|
+
onClick: () => {
|
|
53241
|
+
setBrowserId(void 0);
|
|
53242
|
+
setDshTabActive(false);
|
|
53243
|
+
setActive(tab.path);
|
|
53244
|
+
},
|
|
53245
|
+
onAuxClick: (event) => {
|
|
53246
|
+
if (event.button === 1) {
|
|
53247
|
+
event.preventDefault();
|
|
52724
53248
|
close(tab);
|
|
52725
|
-
}
|
|
52726
|
-
|
|
52727
|
-
|
|
52728
|
-
|
|
52729
|
-
|
|
53249
|
+
}
|
|
53250
|
+
},
|
|
53251
|
+
onMouseDown: (event) => {
|
|
53252
|
+
if (event.button === 1) event.preventDefault();
|
|
53253
|
+
},
|
|
53254
|
+
onContextMenu: (event) => {
|
|
53255
|
+
event.preventDefault();
|
|
53256
|
+
setBrowserId(void 0);
|
|
53257
|
+
setDshTabActive(false);
|
|
53258
|
+
setActive(tab.path);
|
|
53259
|
+
setTabMenu({
|
|
53260
|
+
x: event.clientX,
|
|
53261
|
+
y: event.clientY,
|
|
53262
|
+
path: tab.path
|
|
53263
|
+
});
|
|
53264
|
+
},
|
|
53265
|
+
children: [
|
|
53266
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileIcon, {
|
|
53267
|
+
name: tabLabel(tab),
|
|
53268
|
+
className: "dvw-tab-icon"
|
|
53269
|
+
}),
|
|
53270
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
53271
|
+
className: "dvw-tab-name",
|
|
53272
|
+
children: [tab.dirty ? "● " : "", tabLabel(tab)]
|
|
53273
|
+
}),
|
|
53274
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
53275
|
+
className: "dvw-tab-close",
|
|
53276
|
+
onClick: (event) => {
|
|
53277
|
+
event.stopPropagation();
|
|
53278
|
+
close(tab);
|
|
53279
|
+
},
|
|
53280
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "close" })
|
|
53281
|
+
})
|
|
53282
|
+
]
|
|
53283
|
+
}, tab.path))
|
|
53284
|
+
]
|
|
52730
53285
|
})
|
|
52731
53286
|
}),
|
|
52732
53287
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
52733
53288
|
className: "dvw-editor",
|
|
52734
53289
|
"data-outline": markdownPreview && outlineVisible && headings.length > 0,
|
|
53290
|
+
"data-browser-active": browserId !== void 0 || void 0,
|
|
52735
53291
|
children: [
|
|
52736
53292
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
52737
53293
|
className: "dvw-error",
|
|
@@ -52830,7 +53386,22 @@ section.${c}>footer { z-index: 1; }
|
|
|
52830
53386
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
52831
53387
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: "DSH Workbench" }),
|
|
52832
53388
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
52833
|
-
"从资源管理器或搜索结果打开文件"
|
|
53389
|
+
"从资源管理器或搜索结果打开文件",
|
|
53390
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
53391
|
+
className: "dvw-start-tools",
|
|
53392
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
53393
|
+
onClick: () => {
|
|
53394
|
+
if (snapshot.bottomPanel !== "terminal") service.toggleBottomPanel("terminal");
|
|
53395
|
+
queueMicrotask(() => service.runCommand("terminal.new"));
|
|
53396
|
+
},
|
|
53397
|
+
disabled: !terminalAvailable,
|
|
53398
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "terminal" }), "新建终端"]
|
|
53399
|
+
}), browser !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
53400
|
+
onClick: () => void newBrowser(),
|
|
53401
|
+
disabled: !browserSnapshot.available,
|
|
53402
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { name: "globe" }), "浏览器"]
|
|
53403
|
+
})]
|
|
53404
|
+
})
|
|
52834
53405
|
] })
|
|
52835
53406
|
}) : activeTab.diff ? diffMarkdown && activeTab.preview ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MarkdownPreview, {
|
|
52836
53407
|
source: activeTab.diff.modified,
|
|
@@ -52947,6 +53518,12 @@ section.${c}>footer { z-index: 1; }
|
|
|
52947
53518
|
})
|
|
52948
53519
|
]
|
|
52949
53520
|
}),
|
|
53521
|
+
sessionId !== void 0 && browserTabs.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DshBrowserPage, {
|
|
53522
|
+
sessionId,
|
|
53523
|
+
tabId: tab.id,
|
|
53524
|
+
colorScheme,
|
|
53525
|
+
active: browserId === tab.id && !dshTabActive && !settingsOpen && !switcherOpen && snapshot.visible
|
|
53526
|
+
}, tab.id)),
|
|
52950
53527
|
snapshot.bottomPanel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
52951
53528
|
className: "dvw-bottom",
|
|
52952
53529
|
style: { height: panelHeight },
|
|
@@ -53037,8 +53614,8 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
|
|
|
53037
53614
|
.dvw-overlay[data-dvw-theme=dark]{--dvw-base:#191a1b;--dvw-surface-1:#121314;--dvw-surface-2:#202122;--dvw-surface-3:#252526;--dvw-side:#191a1b;--dvw-tab-active:#2a2b2c;--dvw-gutter:#191a1b;--dvw-graph-ref:#3794ff;--dvw-text:#bfbfbf;--dvw-text-2:#8c8c8c;--dvw-text-3:#6e6e6e;--dvw-border:#2a2b2c;--dvw-border-soft:#242526;--dvw-hover:#ffffff12;--dvw-active:#ffffff1f;--dvw-accent:#307e9f;--dvw-error:#e06c75;--dvw-success:#98c379;--dvw-warn:#e5c07b}
|
|
53038
53615
|
.dvw-overlay[data-dvw-theme=light]{--dvw-base:#f9fafb;--dvw-surface-1:#fff;--dvw-surface-2:#fff;--dvw-surface-3:#fff;--dvw-side:#f9fafb;--dvw-tab-active:#e8e8e8;--dvw-gutter:#f9fafb;--dvw-graph-ref:#0063d3;--dvw-text:#1f1f1f;--dvw-text-2:#616161;--dvw-text-3:#8a8a8a;--dvw-border:#e5e5e5;--dvw-border-soft:#ececec;--dvw-hover:#0000000d;--dvw-active:#00000014;--dvw-accent:#0078d4;--dvw-error:#e51400;--dvw-success:#388a34;--dvw-warn:#bf8803;color-scheme:light}
|
|
53039
53616
|
.dvw-overlay *{box-sizing:border-box}.dvw-overlay ::-webkit-scrollbar{width:10px;height:10px}.dvw-overlay ::-webkit-scrollbar-track{background:transparent}.dvw-overlay ::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dvw-text) 20%,transparent);border:2px solid transparent;background-clip:padding-box;border-radius:6px}.dvw-overlay ::-webkit-scrollbar-thumb:hover{background:color-mix(in srgb,var(--dvw-text) 32%,transparent);background-clip:padding-box}.dvw-overlay ::-webkit-scrollbar-corner{background:transparent}.dvw-activity{grid-row:1/3;background:var(--dvw-base);border:1px solid var(--dvw-border);border-radius:8px 0 0 8px;display:flex;flex-direction:column;align-items:center;overflow:hidden}.dvw-activity-menu{min-width:220px}.dvw-activity-empty{flex:1}.dvw-activity-bottom{width:100%;margin-top:auto;display:flex;flex-direction:column;align-items:center}.dvw-menu-separator{height:1px;margin:4px 0;background:var(--dvw-border-soft)}.dvw-menu-check{display:inline-block;width:14px;flex:none;color:var(--dvw-text)}.dvw-act{touch-action:none;user-select:none}.dvw-act[data-dragging=true]{opacity:.35}.dvw-activity-ghost{position:fixed;z-index:120;width:48px;height:48px;display:grid;place-items:center;pointer-events:none;border-radius:8px;background:var(--dvw-tab-active);color:var(--dvw-text);font-size:22px;box-shadow:0 8px 22px rgba(0,0,0,.3);transform:translate(-50%,-50%) scale(1.08);opacity:.95}.dvw-activity-ghost .codicon{font-size:18px}.dvw-act{position:relative;width:48px;height:48px;padding:0;border:0;background:transparent;color:var(--dvw-text-3);font-size:22px;cursor:pointer;display:grid;place-items:center}.dvw-act::before{content:"";position:absolute;left:50%;top:50%;width:32px;height:32px;border-radius:6px;background:transparent;transform:translate(-50%,-50%)}.dvw-act .codicon,.dvw-act svg{position:relative;z-index:1}.dvw-act .codicon{font-size:18px}.dvw-act:hover,.dvw-act[data-active=true]{color:var(--dvw-text)}.dvw-act:hover::before{background:var(--dvw-hover)}.dvw-act[data-active=true]::before{background:var(--dvw-tab-active)}.dvw-act.dsh{margin-top:auto}.dvw-side{grid-column:2;grid-row:1/3;min-width:0;width:100%;background:var(--dvw-side);border-top:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-top-right-radius:8px;border-bottom-right-radius:8px;overflow:hidden;display:flex;flex-direction:column}.dvw-side-resizer{grid-column:2;grid-row:1/3;justify-self:end;width:4px;height:100%;z-index:4;cursor:ew-resize;transform:translateX(2px);touch-action:none}.dvw-side-resizer:hover,.dvw-side-resizer:focus-visible,.dvw-side-resizer[data-dragging=true]{background:var(--dvw-accent)}.dvw-side-head{height:35px;display:flex;align-items:center;padding:0 12px;text-transform:uppercase;font-size:11px;letter-spacing:.4px}.dvw-toolbar{margin-left:auto;display:flex;gap:2px}.dvw-icon{border:0;background:transparent;color:var(--dvw-text-2);border-radius:4px;min-width:24px;height:24px;display:inline-grid;place-items:center;cursor:pointer}.dvw-icon:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-icon:disabled{opacity:.45;cursor:default}.dvw-file-picker{display:none}.dvw-tree,.dvw-results,.dvw-git{overflow:auto;flex:1}.dvw-tree[data-drop-target=true]{outline:1px dashed var(--dvw-accent);outline-offset:-3px}.dvw-tree-row{display:flex;align-items:center;height:22px;padding-right:6px;cursor:pointer;white-space:nowrap}.dvw-tree-row:hover{background:var(--dvw-hover)}.dvw-tree-row[data-selected=true],.dvw-tree-row[data-drop-target=true]{background:var(--dvw-active)}.dvw-chevron{width:16px;flex:none;text-align:center;color:var(--dvw-text-3)}.dvw-file-icon{width:16px;height:16px;flex:none;display:block;object-fit:contain;color:var(--dvw-text-2)}.dvw-file-icon.folder{color:var(--dvw-accent)}.dvw-tree-name{overflow:hidden;text-overflow:ellipsis}.dvw-tree-rename,.dvw-tree-create-input{min-width:0;flex:1;height:20px;border:1px solid var(--dvw-accent);border-radius:2px;background:var(--dvw-surface-1);color:var(--dvw-text);padding:0 3px;font:inherit;letter-spacing:0;outline:0}.dvw-tree-create-row{cursor:text}.dvw-tree-create-row:hover{background:transparent}.dvw-tree-create-input::placeholder{color:var(--dvw-text-3)}.dvw-tree-create-input[aria-invalid=true]{border-color:var(--dvw-error)}.dvw-tree-create-error{min-height:20px;padding-top:2px;padding-right:6px;padding-bottom:3px;color:var(--dvw-error);font-size:11px;line-height:15px;white-space:normal;overflow-wrap:anywhere}.dvw-tree-status{margin-left:auto;padding-left:6px;font-size:11px;font-weight:600;color:var(--dvw-warn)}.dvw-tree-status[data-status=M]{color:var(--dvw-warn)}.dvw-tree-status[data-status=A]{color:var(--dvw-success)}.dvw-tree-status[data-status=D]{color:var(--dvw-error)}.dvw-context-menu{position:fixed;z-index:40;min-width:148px;padding:4px;border:1px solid var(--dvw-border);border-radius:5px;background:var(--dvw-surface-3);box-shadow:0 6px 20px rgba(0,0,0,.3)}.dvw-context-menu button{width:100%;height:28px;border:0;border-radius:3px;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:8px;padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-context-menu button:hover{background:var(--dvw-hover)}.dvw-context-menu .dvw-context-delete{color:var(--dvw-error)}.dvw-tab-menu{min-width:220px}.dvw-tab-menu button{justify-content:space-between;gap:24px}.dvw-tab-menu button span{color:var(--dvw-text-3);font-size:11px}.dvw-tab-menu button:disabled{opacity:.45;cursor:default}.dvw-tab-menu button:disabled:hover{background:transparent}
|
|
53040
|
-
.dvw-main{grid-column:3;grid-row:1;position:relative;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1);border-left:1px solid var(--dvw-border);border-top:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-left:
|
|
53041
|
-
.dvw-bottom-resizer{height:4px;cursor:ns-resize}.dvw-bottom-resizer:hover{background:var(--dvw-accent)}.dvw-bottom-reveal{position:absolute;left:0;right:0;bottom:0;height:6px;z-index:4;cursor:ns-resize}.dvw-bottom-reveal::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:transparent}.dvw-bottom-reveal:hover::after{background:var(--dvw-accent)}.dvw-bottom{grid-column:3;grid-row:2;height:260px;min-height:120px;border-top:1px solid var(--dvw-border);border-left:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-top:4px;margin-left:
|
|
53617
|
+
.dvw-main{grid-column:3;grid-row:1;position:relative;display:flex;min-width:0;min-height:0;flex-direction:column;background:var(--dvw-surface-1);border-left:1px solid var(--dvw-border);border-top:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-left:3px;overflow:hidden}.dvw-tabs{height:35px;background:linear-gradient(to top,var(--dvw-border) 0 1px,var(--dvw-base) 1px 100%);display:flex;overflow:hidden}.dvw-tabs[data-empty]{display:none}.dvw-tab{position:relative;height:35px;margin:0;min-width:110px;max-width:260px;border:0;border-right:1px solid var(--dvw-border-soft);border-radius:8px 8px 0 0;background:transparent;color:var(--dvw-text-2);padding:0 8px 0 12px;display:flex;align-items:center;gap:6px;cursor:pointer;flex:none;white-space:nowrap}.dvw-tab:hover{background:var(--dvw-hover)}.dvw-tab[data-active=true]{background:var(--dvw-surface-1);color:var(--dvw-text);border-top:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border)}.dvw-tab-icon{width:16px;height:16px;flex:none;object-fit:contain}.dvw-tab-close{width:16px;height:16px;flex:none;display:grid;place-items:center;border-radius:3px;opacity:0}.dvw-tab-close:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-tab[data-active=true] .dvw-tab-close,.dvw-tab:hover .dvw-tab-close{opacity:1}.dvw-tab-name{overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;text-align:left;white-space:nowrap}.dvw-editor{position:relative;flex:1;min-height:0}.dvw-editor-toolbar{position:absolute;z-index:3;top:0;right:0;left:0;height:35px;display:flex;align-items:center;justify-content:flex-end;gap:4px;padding:0 10px;border-bottom:1px solid var(--dvw-border-soft);background:var(--dvw-surface-1)}.dvw-editor-body{position:absolute;inset:0;min-height:0}.dvw-editor-body[data-toolbar=true]{top:35px}.dvw-mode-button{height:27px;padding:0 10px;display:flex;align-items:center;gap:6px;border:1px solid transparent;border-radius:5px;background:transparent;color:var(--dvw-text-2);cursor:pointer}.dvw-mode-button:hover{background:var(--dvw-hover)}.dvw-mode-button[data-active=true]{border-color:var(--dvw-border);background:var(--dvw-active);color:var(--dvw-text)}.dvw-empty{height:100%;display:grid;place-items:center;color:var(--dvw-text-3);text-align:center}.dvw-empty strong{font-size:24px;color:var(--dvw-text-2)}.dvw-message{padding:12px;color:var(--dvw-warn)}.dvw-message button{margin-left:10px;padding:2px 10px;border:1px solid var(--dvw-border);border-radius:4px;background:var(--dvw-surface-2);color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-message button:hover{background:var(--dvw-hover)}
|
|
53618
|
+
.dvw-bottom-resizer{height:4px;cursor:ns-resize}.dvw-bottom-resizer:hover{background:var(--dvw-accent)}.dvw-bottom-reveal{position:absolute;left:0;right:0;bottom:0;height:6px;z-index:4;cursor:ns-resize}.dvw-bottom-reveal::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:transparent}.dvw-bottom-reveal:hover::after{background:var(--dvw-accent)}.dvw-bottom{grid-column:3;grid-row:2;height:260px;min-height:120px;border-top:1px solid var(--dvw-border);border-left:1px solid var(--dvw-border);border-right:1px solid var(--dvw-border);border-bottom:1px solid var(--dvw-border);border-radius:8px;margin-top:4px;margin-left:3px;background:var(--dvw-base);display:flex;flex-direction:column}.dvw-bottom-head{height:35px;display:flex;align-items:center;gap:14px;padding:0 12px}.dvw-bottom-title{border:0;border-bottom:1px solid var(--dvw-text);background:transparent;color:var(--dvw-text);height:35px}.dvw-bottom-body{flex:1;min-height:0}.dvw-status{grid-column:1/4;grid-row:3;background:var(--dvw-base);color:var(--dvw-text);display:flex;align-items:center;padding:6px 8px 0;gap:18px;font-size:12px}.dvw-theme-control{position:relative;margin-left:auto}.dvw-theme-trigger{height:22px;min-width:112px;display:flex;align-items:center;gap:7px;padding:0 8px;border:0;border-radius:5px;background:color-mix(in srgb,#000 17%,transparent);color:#fff;cursor:pointer}.dvw-theme-trigger:hover{background:color-mix(in srgb,#000 27%,transparent)}.dvw-theme-orb{width:13px;height:13px;border:2px solid #fff;border-radius:50%;background:linear-gradient(90deg,#191a1b 50%,#fff 50%)}.dvw-theme-orb.dark{background:#191a1b}.dvw-theme-orb.light{background:#fff}.dvw-theme-menu{position:absolute;right:0;bottom:29px;width:224px;padding:6px;border:1px solid var(--dvw-border);border-radius:10px;background:var(--dvw-surface-3);box-shadow:0 10px 35px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-theme-menu button{width:100%;min-height:48px;border:0;border-radius:7px;background:transparent;color:inherit;display:grid;grid-template-columns:30px 1fr 20px;align-items:center;text-align:left;padding:6px;cursor:pointer}.dvw-theme-menu button:hover,.dvw-theme-menu button[aria-checked=true]{background:var(--dvw-hover)}.dvw-theme-menu strong,.dvw-theme-menu small{display:block}.dvw-theme-menu small{color:var(--dvw-text-3);margin-top:2px}.dvw-theme-swatch{width:22px;height:22px;border-radius:6px;border:1px solid var(--dvw-border);background:linear-gradient(135deg,#191a1b 0 50%,#fff 50%)}.dvw-theme-swatch.dark{background:#191a1b}.dvw-theme-swatch.light{background:#fff}
|
|
53042
53619
|
.dvw-search-form{padding:8px;display:grid;gap:6px}.dvw-input,.dvw-textarea,.dvw-select{width:100%;border:1px solid var(--dvw-border);border-radius:2px;background:var(--dvw-surface-2);color:var(--dvw-text);padding:3px 7px;outline:none}.dvw-input:focus,.dvw-textarea:focus,.dvw-select:focus{border-color:var(--dvw-accent)}.dvw-options{display:flex;align-items:center;gap:8px;font-size:11px}.dvw-result-file{height:22px;display:flex;align-items:center;gap:4px;padding:0 8px;font-weight:600}.dvw-result{height:22px;align-items:center;padding:0 8px 0 20px;cursor:pointer;display:flex;gap:8px}.dvw-result:hover{background:var(--dvw-hover)}.dvw-line{color:var(--dvw-text-3);min-width:30px;text-align:right}.dvw-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-search-hit{background:color-mix(in srgb,var(--dvw-accent) 28%,transparent);border-radius:2px}
|
|
53043
53620
|
.dvw-git-head{padding:7px 10px;border-bottom:1px solid var(--dvw-border);display:flex;align-items:center;gap:8px;position:relative}.dvw-branch{min-width:0;border:0;background:transparent;color:var(--dvw-text);font:inherit;font-weight:600;display:flex;align-items:center;gap:5px;cursor:pointer}.dvw-branch-caret{margin-left:2px;font-size:14px;color:var(--dvw-text-3)}.dvw-branch-menu{position:absolute;z-index:12;top:calc(100% + 2px);left:6px;right:6px;padding:4px;border:1px solid var(--dvw-border);border-radius:8px;background:var(--dvw-surface-2);box-shadow:0 10px 28px rgba(0,0,0,.28);color:var(--dvw-text)}.dvw-branch-current{padding:4px 8px;color:var(--dvw-text-3);font-size:11px}.dvw-branch-list{max-height:min(300px,45vh);overflow:auto}.dvw-branch-list button{width:100%;height:26px;display:flex;align-items:center;gap:6px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text);padding:0 8px;text-align:left;font:inherit;cursor:pointer}.dvw-branch-list button:hover{background:var(--dvw-hover)}.dvw-branch-list button[data-active=true]{background:var(--dvw-active)}.dvw-branch-list button span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-branch-worktree{margin-left:auto;flex:none;padding:1px 5px;border-radius:8px;background:var(--dvw-surface-3);color:var(--dvw-text-3);font-size:10px;line-height:14px}.dvw-branch-create{display:flex;gap:4px;align-items:center;margin-top:4px;padding-top:6px;border-top:1px solid var(--dvw-border-soft)}.dvw-branch-create .dvw-input{flex:1;min-width:0}.dvw-branch-create-button{flex:none;width:24px;min-width:24px;height:24px;border:1px solid var(--dvw-border);border-radius:4px}.dvw-commit{display:flex;flex-direction:column;gap:6px;padding:9px}.dvw-commit-actions{display:grid;grid-template-columns:1fr auto;gap:6px}.dvw-commit-button{height:31px;border:0;border-radius:6px;background:color-mix(in srgb,var(--dvw-accent) 24%,var(--dvw-surface-2));color:var(--dvw-text);display:flex;align-items:center;justify-content:center;gap:7px;cursor:pointer}.dvw-commit-button:hover{background:color-mix(in srgb,var(--dvw-accent) 34%,var(--dvw-surface-2))}.dvw-commit-button:disabled{opacity:.45;cursor:default}.dvw-commit-ai{height:31px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-surface-2);color:var(--dvw-text-2);display:flex;align-items:center;justify-content:center;gap:6px;font:inherit;cursor:pointer}.dvw-commit-ai:hover:not(:disabled){background:var(--dvw-hover);color:var(--dvw-text)}.dvw-commit-ai:disabled{opacity:.45;cursor:default}.dvw-group-head{height:30px;display:flex;align-items:center;gap:5px;padding:0 6px 0 9px;font-weight:600;position:sticky;top:0;background:var(--dvw-side);z-index:1}.dvw-group-head:hover{background:var(--dvw-hover)}.dvw-group-head .dvw-count{margin-left:auto;min-width:20px;height:20px;border-radius:10px;display:grid;place-items:center;background:var(--dvw-surface-3);color:var(--dvw-text-2);font-size:11px}.dvw-change{display:flex;align-items:center;height:22px;padding:0 5px 0 19px;gap:5px;cursor:pointer}.dvw-change:hover{background:var(--dvw-hover)}.dvw-change .dvw-icon{opacity:0}.dvw-change:hover .dvw-icon,.dvw-change:focus-within .dvw-icon{opacity:1}.dvw-change-path{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.dvw-badge{font-size:11px;color:var(--dvw-warn)}.dvw-graph{border-top:1px solid var(--dvw-border-soft);margin-top:8px;padding-top:3px}.dvw-graph-list{padding-bottom:8px}.dvw-graph-row{width:100%;height:38px;border:0;background:transparent;color:var(--dvw-text);display:flex;align-items:center;padding:0 7px;text-align:left;cursor:pointer;overflow:hidden}.dvw-graph-row:hover{background:var(--dvw-hover)}.dvw-graph-svg{flex:none;align-self:stretch}.dvw-graph-line{fill:none;stroke-width:1px;stroke-linecap:round;vector-effect:non-scaling-stroke}.dvw-graph-node{stroke:var(--dvw-side);stroke-width:2px;fill:var(--dvw-side)}.dvw-graph-copy{display:flex;min-width:0;flex:1;flex-direction:column;justify-content:center}.dvw-graph-subject{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-graph-meta{font-size:11px;color:var(--dvw-text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-ref{max-width:82px;margin-left:4px;padding:1px 5px;border:1px solid color-mix(in srgb,var(--dvw-accent) 50%,transparent);border-radius:9px;color:var(--dvw-accent);font-size:10px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvw-error{padding:8px;color:var(--dvw-error);white-space:pre-wrap}.dvw-diff{margin:0;height:100%;overflow:auto;padding:8px 0;background:var(--dvw-surface-1);font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;white-space:pre}.dvw-diff-line{display:block;min-height:18px;padding:0 14px}.dvw-diff-line.add{background:color-mix(in srgb,var(--dvw-success) 15%,transparent);color:var(--dvw-success)}.dvw-diff-line.remove{background:color-mix(in srgb,var(--dvw-error) 13%,transparent);color:var(--dvw-error)}.dvw-diff-line.hunk{background:color-mix(in srgb,var(--dvw-accent) 12%,transparent);color:var(--dvw-accent)}.dvw-diff-line.meta{color:var(--dvw-text-3)}.dvw-diff-empty{padding:24px;color:var(--dvw-text-3)}
|
|
53044
53621
|
.dvw-tab-list{display:flex;min-width:0;flex:1;overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;scrollbar-width:none}.dvw-tab-list::-webkit-scrollbar{display:none}.dvw-monaco-diff{position:absolute;inset:0}.dvw-diff-toolbar{justify-content:flex-end}.dvw-group-head{gap:2px;padding-left:2px}.dvw-group-toggle{min-width:0;height:30px;flex:1;border:0;border-radius:5px;background:transparent;color:var(--dvw-text);font:inherit;font-weight:600;display:flex;align-items:center;gap:5px;padding:0 7px;cursor:pointer;text-align:left}.dvw-group-toggle:hover{background:var(--dvw-hover)}.dvw-graph-entry[data-expanded=true]{background:color-mix(in srgb,var(--dvw-accent) 5%,transparent)}.dvw-commit-files{padding:1px 0 5px 26px}.dvw-commit-file{width:100%;height:22px;border:0;background:transparent;color:var(--dvw-text);display:flex;align-items:center;gap:6px;padding:0 7px;text-align:left;cursor:pointer}.dvw-commit-file:hover{background:var(--dvw-hover)}.dvw-commit-file-name{white-space:nowrap}.dvw-commit-file-dir{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dvw-text-3);font-size:11px}
|
|
@@ -53051,7 +53628,7 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
|
|
|
53051
53628
|
.dvw-overlay[data-dvw-chat=true]:not([data-dvw-primary-side=true]){grid-template-columns:48px 0 minmax(0,1fr) var(--dvw-chat-width)}
|
|
53052
53629
|
.dvw-overlay:not([data-dvw-primary-side=true]) .dvw-side{visibility:hidden;border-right:0}.dvw-overlay:not([data-dvw-primary-side=true]) .dvw-activity{border-radius:8px}.dvw-overlay:not([data-dvw-primary-side=true]) .dvw-side-resizer{display:none}
|
|
53053
53630
|
.dvw-overlay:not([data-dvw-status=true]){grid-template-rows:minmax(0,1fr) auto 6px}.dvw-overlay:not([data-dvw-status=true]) .dvw-status{display:none}
|
|
53054
|
-
.dvw-overlay[data-dvw-chat=true] .dvw-status{grid-column:1/-1;padding-right:calc(var(--dvw-chat-width) +
|
|
53631
|
+
.dvw-overlay[data-dvw-chat=true] .dvw-status{grid-column:1/-1;padding-right:calc(var(--dvw-chat-width) + 6px)}
|
|
53055
53632
|
.dvw-chat{grid-column:4;grid-row:1/3;min-width:0;background:var(--dvw-gutter);border-left:1px solid var(--dvw-border);position:relative}
|
|
53056
53633
|
.dvw-chat-head{height:36px;display:flex;align-items:center;justify-content:space-between;padding:0 6px 0 12px;border-bottom:1px solid var(--dvw-border);background:var(--dvw-base);font-weight:600}
|
|
53057
53634
|
.dvw-chat-head>span{display:flex;align-items:center;gap:7px}.dvw-chat-body{height:calc(100% - 36px);background:var(--dvw-base)}
|
|
@@ -53067,7 +53644,7 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
|
|
|
53067
53644
|
.dvw-chat{border-left-color:transparent!important}
|
|
53068
53645
|
.dvw-side-resizer::after,.dvw-chat-resizer::after{background:transparent;left:3px;width:4px}
|
|
53069
53646
|
.dvw-side-resizer:hover::after,.dvw-side-resizer:focus-visible::after,.dvw-side-resizer[data-dragging=true]::after,.dvw-chat-resizer:hover::after,.dvw-chat-resizer:focus-visible::after,.dvw-chat-resizer[data-dragging=true]::after{background:var(--dvw-accent)}
|
|
53070
|
-
[data-dvw-conversation-panel]{position:fixed!important;top:calc(var(--dvw-titlebar-height) + 6px)!important;right:
|
|
53647
|
+
[data-dvw-conversation-panel]{position:fixed!important;top:calc(var(--dvw-titlebar-height) + 6px)!important;right:3px!important;bottom:var(--dvw-status-height,30px)!important;left:auto!important;width:calc(var(--dvw-chat-width) - 6px)!important;height:auto!important;min-width:0!important;z-index:21!important;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:8px!important;overflow:hidden!important;box-shadow:none!important}
|
|
53071
53648
|
html[data-platform=darwin] [data-dvw-conversation-panel]{top:var(--dvw-titlebar-height)!important}
|
|
53072
53649
|
body[data-dvw-palette=light] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#f9fafb;--dsw-specific-sidebar-fill:#f9fafb;--dsw-alias-border-l2:#e5e5e5;background:#f9fafb!important}body[data-dvw-palette=dark] [data-dvw-conversation-panel]{--dsw-alias-bg-base:#191a1b;--dsw-specific-sidebar-fill:#191a1b;--dsw-alias-bg-layer-1:#202122;--dsw-alias-bg-layer-2:#252526;--dsw-alias-bg-layer-3:#2a2b2c;--dsw-alias-label-primary:#bfbfbf;--dsw-alias-label-secondary:#8c8c8c;--dsw-alias-label-tertiary:#6e6e6e;--dsw-alias-border-l2:#2a2b2c;--dsw-alias-border-l3:#303132;--dsw-alias-interactive-bg-hover:#ffffff12;--dsw-alias-interactive-bg-active:#ffffff1f}
|
|
53073
53650
|
body[data-dvw-workbench-active] [data-sidebar-right-expand],body[data-dvw-conversation-active] [data-sidebar-right-expand]{display:none!important}
|
|
@@ -53089,7 +53666,7 @@ body[data-dvw-workbench-active] [data-sidebar-toggle]{display:none!important}
|
|
|
53089
53666
|
.dvw-settings-themes{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.dvw-settings-themes button{height:56px;display:grid;grid-template-columns:28px 1fr 18px;align-items:center;gap:7px;padding:0 9px;border:1px solid var(--dvw-border);border-radius:7px;background:var(--dvw-base);color:var(--dvw-text);text-align:left;cursor:pointer}.dvw-settings-themes button:hover{background:var(--dvw-hover)}.dvw-settings-themes button[data-active=true]{border-color:var(--dvw-accent);background:color-mix(in srgb,var(--dvw-accent) 10%,var(--dvw-base))}
|
|
53090
53667
|
.dvw-setting-check{height:36px;display:flex;align-items:center;gap:9px;border-bottom:1px solid var(--dvw-border-soft);cursor:pointer}.dvw-setting-check input{accent-color:var(--dvw-accent)}.dvw-setting-range{display:grid;grid-template-columns:145px 1fr 52px;align-items:center;gap:10px;min-height:42px}.dvw-setting-range input{accent-color:var(--dvw-accent)}.dvw-setting-range output{text-align:right;color:var(--dvw-text-3);font-variant-numeric:tabular-nums}
|
|
53091
53668
|
.dvw-setting-choice{display:grid;grid-template-columns:145px 1fr;align-items:center;gap:10px;min-height:42px}.dvw-setting-choice>span{color:var(--dvw-text-2);font-size:12px}.dvw-setting-segment{display:inline-flex;justify-self:start;padding:2px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-base)}.dvw-setting-segment button{min-width:64px;height:26px;border:0;border-radius:4px;background:transparent;color:var(--dvw-text-2);font:inherit;font-size:12px;cursor:pointer}.dvw-setting-segment button:hover{background:var(--dvw-hover);color:var(--dvw-text)}.dvw-setting-segment button[data-active=true]{background:var(--dvw-active);color:var(--dvw-text)}
|
|
53092
|
-
@media(max-width:900px){.dvw-overlay[data-dvw-chat=true]{--dvw-chat-effective:max(440px,min(var(--dvw-chat-width),calc(100vw - 254px)));grid-template-columns:44px min(210px,var(--dvw-side-width),max(0px,calc(100vw - 164px - var(--dvw-chat-effective)))) minmax(0,1fr) var(--dvw-chat-effective)}.dvw-overlay[data-dvw-chat=true] .dvw-status{padding-right:calc(var(--dvw-chat-effective) +
|
|
53669
|
+
@media(max-width:900px){.dvw-overlay[data-dvw-chat=true]{--dvw-chat-effective:max(440px,min(var(--dvw-chat-width),calc(100vw - 254px)));grid-template-columns:44px min(210px,var(--dvw-side-width),max(0px,calc(100vw - 164px - var(--dvw-chat-effective)))) minmax(0,1fr) var(--dvw-chat-effective)}.dvw-overlay[data-dvw-chat=true] .dvw-status{padding-right:calc(var(--dvw-chat-effective) + 6px)}.dvw-chat-resizer{right:calc(var(--dvw-chat-effective) - 5px)}[data-dvw-conversation-panel]{width:calc(max(440px,min(var(--dvw-chat-width),calc(100vw - 254px))) - 6px)!important}}
|
|
53093
53670
|
.dvw-setting-textarea{width:100%;min-height:84px;resize:vertical;padding:8px 10px;border:1px solid var(--dvw-border);border-radius:6px;background:var(--dvw-base);color:var(--dvw-text);font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
|
|
53094
53671
|
.dvw-setting-textarea:focus{outline:none;border-color:var(--dvw-accent)}
|
|
53095
53672
|
.dvw-setting-extension{display:flex;align-items:center;gap:12px;padding:10px 12px;border:1px solid var(--dvw-border);border-radius:7px;background:var(--dvw-base)}.dvw-setting-extension>div{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}.dvw-setting-extension span{color:var(--dvw-text-3);font-size:12px}.dvw-setting-extension button{height:26px;padding:0 14px;border:1px solid var(--dvw-border);border-radius:4px;background:transparent;color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-setting-extension button:hover{background:var(--dvw-hover)}.dvw-setting-extension button.dvw-primary-button{border-color:var(--dvw-accent);background:var(--dvw-accent);color:#fff}.dvw-setting-hint{margin:8px 0 0;color:var(--dvw-text-3);font-size:11px;line-height:1.5}
|
|
@@ -53114,9 +53691,10 @@ body[data-dvw-workbench-active] [data-sidebar-toggle]{display:none!important}
|
|
|
53114
53691
|
.dvw-tab{border-radius:10px 10px 0 0;border-right:0}
|
|
53115
53692
|
.dvw-tabs{background:color-mix(in srgb,var(--dvw-text) 4%,var(--dvw-base))}
|
|
53116
53693
|
.dvw-tab[data-active=true]{border-top:0;border-right-color:transparent}
|
|
53694
|
+
.dvw-tab:hover:not([data-active=true]){background:color-mix(in srgb,var(--dvw-text) 3%,transparent)}
|
|
53117
53695
|
.dvw-tab[data-active=true]::before,.dvw-tab[data-active=true]::after{content:"";position:absolute;bottom:0;width:10px;height:10px;background:var(--dvw-surface-1);pointer-events:none}
|
|
53118
|
-
.dvw-tab[data-active=true]::before{left:-10px
|
|
53119
|
-
.dvw-tab[data-active=true]::after{right:-10px
|
|
53696
|
+
.dvw-tab[data-active=true]::before{left:-10px;clip-path:path("M10 0C10 5.5 5.5 10 0 10L10 10Z")}
|
|
53697
|
+
.dvw-tab[data-active=true]::after{right:-10px;clip-path:path("M0 0C0 5.5 4.5 10 10 10L0 10Z")}
|
|
53120
53698
|
.dvw-commit-box{position:relative;display:flex;align-items:stretch}
|
|
53121
53699
|
.dvw-commit-input{width:100%;min-height:30px;max-height:96px;field-sizing:content;resize:none;padding:5px 32px 5px 8px;line-height:18px}
|
|
53122
53700
|
.dvw-commit-ai{position:absolute;right:4px;top:50%;transform:translateY(-50%);width:24px;min-width:24px;height:24px;border:0;background:transparent;color:var(--dvw-text-3)}
|
|
@@ -53208,6 +53786,16 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53208
53786
|
.dvw-workspace-switcher>footer button{height:32px;border-radius:9px;padding:0 16px}
|
|
53209
53787
|
.dvw-workspace-switcher .dvw-icon{border-radius:9px}
|
|
53210
53788
|
@media(max-width:760px){.dvw-settings-body{grid-template-columns:1fr;grid-template-rows:auto minmax(0,1fr)}.dvw-settings-nav{grid-column:1;grid-row:1;flex-direction:row;border-right:0;border-bottom:1px solid var(--dvw-border-soft);padding:8px}.dvw-settings-nav button{flex:none}.dvw-settings-body>section{grid-column:1;grid-row:2;padding:16px 18px 24px}}
|
|
53789
|
+
.dvw-dsh-tab-mark{width:16px;height:16px;flex:none;background:currentColor;-webkit-mask:${DSH_MARK_MASK} center/contain no-repeat;mask:${DSH_MARK_MASK} center/contain no-repeat}
|
|
53790
|
+
.codicon-globe:before{content:"\eb01"}
|
|
53791
|
+
.dvw-terminal-pane{display:flex;flex:1;min-width:0;min-height:0;flex-direction:column}.dvw-terminal-panes[data-split=true]>.dvw-terminal-pane+.dvw-terminal-pane{border-left:1px solid var(--dvw-border)}
|
|
53792
|
+
.dvw-terminal-notice{display:flex;align-items:center;gap:8px;padding:4px 10px;color:var(--dvw-text-2);font-size:12px}.dvw-terminal-notice button,.dvw-start-tools button{border:1px solid var(--dvw-border);border-radius:4px;background:var(--dvw-surface-2);color:var(--dvw-text);font:inherit;cursor:pointer}.dvw-terminal-notice button:hover,.dvw-start-tools button:hover{background:var(--dvw-hover)}
|
|
53793
|
+
.dvw-start-tools{display:flex;justify-content:center;gap:10px;margin-top:20px}.dvw-start-tools button{display:flex;align-items:center;gap:8px;padding:8px 16px}.dvw-start-tools button:disabled{opacity:.45;cursor:default}
|
|
53794
|
+
.dvw-editor[data-browser-active]>.dvw-editor-body,.dvw-editor[data-browser-active]>.dvw-editor-toolbar,.dvw-editor[data-browser-active]>.dvw-outline{visibility:hidden}
|
|
53795
|
+
[data-dvw-browser-page]:popover-open{position:fixed!important;inset:auto!important;margin:0!important;padding:0!important;border:0!important;border-radius:0!important;box-sizing:border-box!important;overflow:hidden!important;background:var(--dsw-alias-bg-base,#fff)!important;color:var(--dsw-alias-label-primary,#171717)!important;display:flex!important;flex-direction:column!important}
|
|
53796
|
+
[data-dvw-browser-page]::backdrop{background:transparent;pointer-events:none}
|
|
53797
|
+
[data-dvw-dsh-page]{position:fixed!important;z-index:106!important;margin:0!important;display:flex!important;flex-direction:column!important;box-sizing:border-box!important;overflow:hidden!important;background:var(--dsw-alias-bg-base,#fff)!important;border:0!important;border-radius:0!important;box-shadow:none!important;--dsh-frame-top-clearance:0px;--dsh-frame-chrome-top:0px}
|
|
53798
|
+
[data-dvw-dsh-page][data-dvw-dsh-hidden]{display:none!important}
|
|
53211
53799
|
`;
|
|
53212
53800
|
function installStyles() {
|
|
53213
53801
|
const id = "dsh-vscode-workbench/styles";
|
|
@@ -53284,14 +53872,21 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53284
53872
|
}
|
|
53285
53873
|
//#endregion
|
|
53286
53874
|
//#region src/client/index.tsx
|
|
53287
|
-
const Overlay = ({ service, useSessions, navigation }) => {
|
|
53875
|
+
const Overlay = ({ service, browser, useSessions, usePanelInfo, navigation, openDshPanel, restoreConversation, closeDshPanel }) => {
|
|
53288
53876
|
const session = useSessions(mainViewSession);
|
|
53289
53877
|
const cwd = session?.projectionValues?.workingDirectory ?? session?.cwd;
|
|
53878
|
+
const activePanelId = usePanelInfo((info) => info.activePanelId);
|
|
53879
|
+
const dshPanelId = activePanelId === null || activePanelId === WORKBENCH_PANEL_ID ? void 0 : activePanelId;
|
|
53290
53880
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Workbench, {
|
|
53291
53881
|
service,
|
|
53882
|
+
browser,
|
|
53292
53883
|
sessionId: session?.id,
|
|
53293
53884
|
cwd,
|
|
53294
|
-
navigation
|
|
53885
|
+
navigation,
|
|
53886
|
+
dshPanelId,
|
|
53887
|
+
onOpenDshPanel: openDshPanel,
|
|
53888
|
+
onRestoreConversation: restoreConversation,
|
|
53889
|
+
onCloseDshPanel: closeDshPanel
|
|
53295
53890
|
}, cwd ?? "no-workspace");
|
|
53296
53891
|
};
|
|
53297
53892
|
const WORKBENCH_PANEL_ID = "vscode-workbench";
|
|
@@ -53313,9 +53908,20 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53313
53908
|
}, [service, restoreConversation]);
|
|
53314
53909
|
return null;
|
|
53315
53910
|
}
|
|
53316
|
-
const inject = [
|
|
53911
|
+
const inject = [
|
|
53912
|
+
"slots",
|
|
53913
|
+
"layout",
|
|
53914
|
+
"remote",
|
|
53915
|
+
"remote.terminal",
|
|
53916
|
+
"sidebarRight",
|
|
53917
|
+
"sidebarRightTabs"
|
|
53918
|
+
];
|
|
53317
53919
|
function apply(ctx) {
|
|
53318
53920
|
const service = new WorkbenchController();
|
|
53921
|
+
const browser = new NativeBrowser(ctx);
|
|
53922
|
+
ctx.effect(() => () => browser.dispose(), "dsh-vscode-workbench: browser");
|
|
53923
|
+
const terminals = new TerminalWorkspaces(new _deepseek_ai_dsh_api_terminal_controller_client.ClientTerminals(ctx.isolate("webTerminals"), ctx.remote.terminal));
|
|
53924
|
+
ctx.effect(() => () => terminals.dispose(), "dsh-vscode-workbench: terminal membership");
|
|
53319
53925
|
const navigation = createDshNavigation((name) => ctx.get?.(name));
|
|
53320
53926
|
ctx.effect(() => installStyles(), "dsh-vscode-workbench: styles");
|
|
53321
53927
|
ctx.effect(() => {
|
|
@@ -53327,7 +53933,10 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53327
53933
|
ctx.effect(() => service.registerBottomPanel({
|
|
53328
53934
|
id: "terminal",
|
|
53329
53935
|
title: "终端",
|
|
53330
|
-
component: TerminalPanel
|
|
53936
|
+
component: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TerminalPanel, {
|
|
53937
|
+
...props,
|
|
53938
|
+
workspace: terminals.get(props.sessionId)
|
|
53939
|
+
}, props.sessionId)
|
|
53331
53940
|
}), "dsh-vscode-workbench: terminal panel");
|
|
53332
53941
|
ctx.effect(() => service.registerCommand({
|
|
53333
53942
|
id: "terminal.new",
|
|
@@ -53338,6 +53947,14 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53338
53947
|
const restoreConversation = () => {
|
|
53339
53948
|
ctx.layout?.selectPanel(null);
|
|
53340
53949
|
};
|
|
53950
|
+
const openDshPanel = (panelId) => {
|
|
53951
|
+
try {
|
|
53952
|
+
ctx.layout?.selectPanel(panelId);
|
|
53953
|
+
} catch {}
|
|
53954
|
+
};
|
|
53955
|
+
const closeDshPanel = () => {
|
|
53956
|
+
ctx.layout?.selectPanel(null);
|
|
53957
|
+
};
|
|
53341
53958
|
ctx.slots.inject("main", () => ctx.slots.inject("sidebar.panellist", () => {
|
|
53342
53959
|
const disposeMain = ctx.slots.register({
|
|
53343
53960
|
name: "main",
|
|
@@ -53363,12 +53980,17 @@ body[data-dvw-palette=eyecare] [data-dvw-conversation-panel]{--dsw-alias-bg-base
|
|
|
53363
53980
|
id: "dsh-vscode-workbench-overlay",
|
|
53364
53981
|
inject: () => ({
|
|
53365
53982
|
service,
|
|
53366
|
-
|
|
53983
|
+
browser,
|
|
53984
|
+
navigation,
|
|
53985
|
+
openDshPanel,
|
|
53986
|
+
restoreConversation,
|
|
53987
|
+
closeDshPanel
|
|
53367
53988
|
})
|
|
53368
53989
|
}, Overlay));
|
|
53369
53990
|
ctx.effect(() => {
|
|
53370
53991
|
const onKey = (event) => {
|
|
53371
53992
|
if (handleTerminalShortcut(event, service)) return;
|
|
53993
|
+
if (handleBrowserShortcut(event, service)) return;
|
|
53372
53994
|
if (event.isComposing || !event.ctrlKey || event.altKey) return;
|
|
53373
53995
|
const view = event.shiftKey && event.code === "KeyE" ? "explorer" : event.shiftKey && event.code === "KeyF" ? "search" : event.shiftKey && event.code === "KeyG" ? "git" : void 0;
|
|
53374
53996
|
if (view !== void 0) {
|