@dungsil/dsh-plugin-ui-worktree 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -5
- package/assets/light-dark-preview.webp +0 -0
- package/dist/client.js +406 -192
- package/dist/index.js +287 -63
- package/package.json +13 -5
package/dist/client.js
CHANGED
|
@@ -3,6 +3,164 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
3
3
|
let react = require("react");
|
|
4
4
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
5
5
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
+
// ../../tools/ui/src/client.ts
|
|
7
|
+
function useLocaleSnapshot(locale) {
|
|
8
|
+
const subscribe = (0, react.useCallback)((listener) => locale.subscribe(listener), [locale]);
|
|
9
|
+
const getSnapshot = (0, react.useCallback)(() => locale.getSnapshot(), [locale]);
|
|
10
|
+
return (0, react.useSyncExternalStore)(subscribe, getSnapshot);
|
|
11
|
+
}
|
|
12
|
+
/** Each effect owns its sheet, even when another plugin installs the same defaults. */
|
|
13
|
+
function installStyles(css) {
|
|
14
|
+
const style = document.createElement("style");
|
|
15
|
+
style.textContent = css;
|
|
16
|
+
document.head.append(style);
|
|
17
|
+
return () => style.remove();
|
|
18
|
+
}
|
|
19
|
+
// ../../tools/ui/src/icons/git-branch.svg
|
|
20
|
+
var git_branch_default = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <circle cx=\"6\" cy=\"5\" r=\"3\"/>\n <circle cx=\"6\" cy=\"19\" r=\"3\"/>\n <circle cx=\"18\" cy=\"6\" r=\"3\"/>\n <path d=\"M6 8v8M6 14h7a5 5 0 0 0 5-5\"/>\n</svg>\n";
|
|
21
|
+
// ../../tools/ui/src/composer.tsx
|
|
22
|
+
const composerStyles = `
|
|
23
|
+
:where(.dsh-plugin-composer-trigger) { display: flex; align-items: center; gap: 4px; min-width: 0; height: 28px; padding: 0 4px 0 8px; border: 0; border-radius: var(--dsw-radius-sm); background: transparent; color: var(--dsw-alias-label-secondary); font: inherit; font-size: 13px; line-height: 20px; cursor: pointer; }
|
|
24
|
+
:where(.dsh-plugin-composer-trigger):disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
|
|
25
|
+
.dsh-plugin-composer-icon, .dsh-plugin-composer-chevron { display: inline-flex; flex: none; }
|
|
26
|
+
.dsh-plugin-composer-label, .dsh-plugin-composer-detail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
27
|
+
.dsh-plugin-composer-chevron, .dsh-plugin-composer-detail { color: var(--dsw-alias-label-caption); }
|
|
28
|
+
.dsh-plugin-composer-trigger[aria-expanded=true] .dsh-plugin-composer-chevron { transform: rotate(180deg); }
|
|
29
|
+
`;
|
|
30
|
+
const ComposerTrigger = /* @__PURE__ */ (0, react.forwardRef)(function ComposerTrigger({ className = "", icon, label, detail, ...props }, ref) {
|
|
31
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
32
|
+
...props,
|
|
33
|
+
ref,
|
|
34
|
+
type: "button",
|
|
35
|
+
className: `dsh-plugin-composer-trigger ${className}`,
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
38
|
+
className: "dsh-plugin-composer-icon",
|
|
39
|
+
"aria-hidden": "true",
|
|
40
|
+
children: icon
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
43
|
+
className: "dsh-plugin-composer-label",
|
|
44
|
+
children: label
|
|
45
|
+
}),
|
|
46
|
+
detail && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
47
|
+
className: "dsh-plugin-composer-detail",
|
|
48
|
+
children: detail
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
51
|
+
className: "dsh-plugin-composer-chevron",
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {})
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
// ../../tools/ui/src/settings.tsx
|
|
59
|
+
/** The rc.5 settings shell has no icon slot, so decorate only the matching navigation rows. */
|
|
60
|
+
function installSettingsIcon(id, labels, icon) {
|
|
61
|
+
const attribute = "data-dsh-settings-icon";
|
|
62
|
+
const selector = `[${attribute}="${id}"]`;
|
|
63
|
+
const removeStyles = installStyles(`
|
|
64
|
+
${selector} > svg { display: none; }
|
|
65
|
+
${typeof icon === "string" ? `${selector}::before { content: ''; display: block; flex: none; width: 16px; height: 16px; background: currentColor; mask: url("data:image/svg+xml,${encodeURIComponent(icon)}") center / contain no-repeat; }` : ""}
|
|
66
|
+
${selector} > [data-dsh-settings-icon-glyph] { display: inline-flex; flex: none; }
|
|
67
|
+
`);
|
|
68
|
+
const marked = /* @__PURE__ */ new Map();
|
|
69
|
+
const refresh = () => {
|
|
70
|
+
const rows = new Set(document.querySelectorAll("[data-shortcut-modal=\"settings\"] nav button"));
|
|
71
|
+
for (const [row, dispose] of marked) if (!rows.has(row) || !labels.includes(row.textContent?.trim() ?? "")) {
|
|
72
|
+
row.removeAttribute(attribute);
|
|
73
|
+
dispose();
|
|
74
|
+
marked.delete(row);
|
|
75
|
+
}
|
|
76
|
+
for (const row of rows) if (!marked.has(row) && labels.includes(row.textContent?.trim() ?? "")) {
|
|
77
|
+
row.setAttribute(attribute, id);
|
|
78
|
+
let dispose = () => {};
|
|
79
|
+
if (typeof icon !== "string") {
|
|
80
|
+
const glyph = document.createElement("span");
|
|
81
|
+
glyph.setAttribute("data-dsh-settings-icon-glyph", "");
|
|
82
|
+
glyph.setAttribute("aria-hidden", "true");
|
|
83
|
+
row.prepend(glyph);
|
|
84
|
+
const unmount = icon(glyph);
|
|
85
|
+
dispose = () => {
|
|
86
|
+
unmount();
|
|
87
|
+
glyph.remove();
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
marked.set(row, dispose);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const observer = new MutationObserver(refresh);
|
|
94
|
+
observer.observe(document.body, {
|
|
95
|
+
childList: true,
|
|
96
|
+
subtree: true,
|
|
97
|
+
characterData: true
|
|
98
|
+
});
|
|
99
|
+
refresh();
|
|
100
|
+
return () => {
|
|
101
|
+
observer.disconnect();
|
|
102
|
+
for (const [row, dispose] of marked) {
|
|
103
|
+
row.removeAttribute(attribute);
|
|
104
|
+
dispose();
|
|
105
|
+
}
|
|
106
|
+
removeStyles();
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const settingsStyles = `
|
|
110
|
+
.dsh-plugin-settings-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 0; border-bottom: .5px solid var(--dsw-alias-border-l2); }
|
|
111
|
+
.dsh-plugin-settings-text { flex: 1; min-width: 0; }
|
|
112
|
+
.dsh-plugin-settings-picker { min-width: 0; }
|
|
113
|
+
.dsh-plugin-settings-selector { box-sizing: border-box; display: inline-flex; align-items: center; gap: 12px; max-width: 100%; height: 36px; padding: 0 14px; border: none; border-radius: var(--dsw-radius-md); background: var(--dsw-alias-bg-module-platform); color: inherit; font: inherit; cursor: pointer; }
|
|
114
|
+
.dsh-plugin-settings-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
115
|
+
.dsh-plugin-settings-selector svg { flex: none; }
|
|
116
|
+
.dsh-plugin-settings-selector:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
117
|
+
.dsh-plugin-settings-selector:disabled { opacity: .5; cursor: default; }
|
|
118
|
+
.dsh-plugin-settings-selector:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary-new-colorprimary-new-color); outline-offset: 2px; }
|
|
119
|
+
`;
|
|
120
|
+
function SettingsRow({ label, children }) {
|
|
121
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
122
|
+
className: "dsh-plugin-settings-row",
|
|
123
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
124
|
+
className: "dsh-plugin-settings-text",
|
|
125
|
+
children: label
|
|
126
|
+
}), children]
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function SettingsPicker({ className = "", value, selectedId, items, onSelect, disabled = false, ...buttonProps }) {
|
|
130
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
131
|
+
(0, react.useEffect)(() => {
|
|
132
|
+
if (disabled) setOpen(false);
|
|
133
|
+
}, [disabled]);
|
|
134
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
135
|
+
className: `dsh-plugin-settings-picker ${className}`,
|
|
136
|
+
open: open && !disabled,
|
|
137
|
+
onClose: () => setOpen(false),
|
|
138
|
+
items,
|
|
139
|
+
selectedId,
|
|
140
|
+
onSelect: (id) => {
|
|
141
|
+
setOpen(false);
|
|
142
|
+
if (!disabled) onSelect(id);
|
|
143
|
+
},
|
|
144
|
+
align: "end",
|
|
145
|
+
portal: true,
|
|
146
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
147
|
+
...buttonProps,
|
|
148
|
+
type: "button",
|
|
149
|
+
className: "dsh-plugin-settings-selector",
|
|
150
|
+
"aria-haspopup": "menu",
|
|
151
|
+
"aria-expanded": open && !disabled,
|
|
152
|
+
disabled,
|
|
153
|
+
onClick: () => setOpen((current) => !current),
|
|
154
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
155
|
+
className: "dsh-plugin-settings-value",
|
|
156
|
+
children: value
|
|
157
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
|
|
158
|
+
size: 16,
|
|
159
|
+
"aria-hidden": "true"
|
|
160
|
+
})]
|
|
161
|
+
})
|
|
162
|
+
});
|
|
163
|
+
}
|
|
6
164
|
// src/protocol.ts
|
|
7
165
|
const channel = "/api";
|
|
8
166
|
const endpointPrefix = "dungsil-worktree/";
|
|
@@ -17,7 +175,10 @@ function isWorktreeProgress(value) {
|
|
|
17
175
|
].includes(progress.status) && Number.isFinite(progress.updatedAt) && Array.isArray(progress.durations) && progress.durations.length === 4 && progress.durations.every((duration) => Number.isFinite(duration) && duration >= 0) && (progress.branch === void 0 || typeof progress.branch === "string");
|
|
18
176
|
}
|
|
19
177
|
function comparablePath(path) {
|
|
20
|
-
|
|
178
|
+
const value = /^[a-z]:[\\/]/i.test(path) || path.startsWith("\\\\") || path.startsWith("//") ? path.replaceAll("\\", "/").replace(/^[A-Z]:/, (drive) => drive.toLowerCase()) : path;
|
|
179
|
+
let end = value.length;
|
|
180
|
+
while (end > 0 && value[end - 1] === "/") end--;
|
|
181
|
+
return value.slice(0, end);
|
|
21
182
|
}
|
|
22
183
|
function currentWorktree(view) {
|
|
23
184
|
if (!view) return void 0;
|
|
@@ -30,7 +191,7 @@ function currentWorktree(view) {
|
|
|
30
191
|
function isWorktreeView(value) {
|
|
31
192
|
if (!value || typeof value !== "object") return false;
|
|
32
193
|
const view = value;
|
|
33
|
-
return typeof view.cwd === "string" && (view.pendingCreation === void 0 || view.pendingCreation !== null && typeof view.pendingCreation.name === "string" && typeof view.pendingCreation.failed === "boolean") && Array.isArray(view.worktrees) && view.worktrees.every((item) => item && typeof item.path === "string" && (item.branch === null || typeof item.branch === "string"));
|
|
194
|
+
return typeof view.cwd === "string" && (view.needsInitialization === void 0 || typeof view.needsInitialization === "boolean") && (view.pendingCreation === void 0 || view.pendingCreation !== null && typeof view.pendingCreation.name === "string" && typeof view.pendingCreation.failed === "boolean") && Array.isArray(view.worktrees) && view.worktrees.every((item) => item && typeof item.path === "string" && (item.branch === null || typeof item.branch === "string"));
|
|
34
195
|
}
|
|
35
196
|
// src/errors.ts
|
|
36
197
|
const failureCodes = [
|
|
@@ -69,6 +230,7 @@ const copy$1 = {
|
|
|
69
230
|
detached: "分离的 HEAD",
|
|
70
231
|
unknown: "无法获取分支",
|
|
71
232
|
create: "新工作树",
|
|
233
|
+
primaryBranch: "当前分支",
|
|
72
234
|
reservationHint: "发送下一条提示后,将先创建并切换到新工作树再开始任务。选择现有工作树可取消。",
|
|
73
235
|
creationError: "无法确认创建结果,尚未开始任务。请刷新列表,选择工作树或重新预约,然后重新发送提示。",
|
|
74
236
|
close: "关闭",
|
|
@@ -87,6 +249,7 @@ const copy$1 = {
|
|
|
87
249
|
errorOperation: "请求",
|
|
88
250
|
operations: {
|
|
89
251
|
describe: "查询工作树",
|
|
252
|
+
initialize: "初始化工作树选择",
|
|
90
253
|
create: "创建工作树",
|
|
91
254
|
switch: "切换工作树"
|
|
92
255
|
},
|
|
@@ -110,6 +273,7 @@ const copy$1 = {
|
|
|
110
273
|
detached: "Detached HEAD",
|
|
111
274
|
unknown: "Branch unavailable",
|
|
112
275
|
create: "New worktree",
|
|
276
|
+
primaryBranch: "Current branch",
|
|
113
277
|
reservationHint: "The next prompt will create and enter a new worktree before starting work. Select an existing worktree to cancel.",
|
|
114
278
|
creationError: "Creation could not be confirmed, so work did not start. Refresh the list, select a worktree or schedule a new one, then resend your prompt.",
|
|
115
279
|
close: "Close",
|
|
@@ -128,6 +292,7 @@ const copy$1 = {
|
|
|
128
292
|
errorOperation: "Request",
|
|
129
293
|
operations: {
|
|
130
294
|
describe: "List worktrees",
|
|
295
|
+
initialize: "Initialize worktree selection",
|
|
131
296
|
create: "Create worktree",
|
|
132
297
|
switch: "Switch worktree"
|
|
133
298
|
},
|
|
@@ -151,6 +316,7 @@ const copy$1 = {
|
|
|
151
316
|
detached: "분리된 HEAD",
|
|
152
317
|
unknown: "브랜치 확인 불가",
|
|
153
318
|
create: "새 워크트리",
|
|
319
|
+
primaryBranch: "현재 브랜치",
|
|
154
320
|
reservationHint: "다음 프롬프트를 전송하면 새 워크트리를 생성·전환한 뒤 작업을 시작합니다. 기존 워크트리를 선택하면 예약을 취소합니다.",
|
|
155
321
|
creationError: "생성 결과를 확인하지 못해 작업을 시작하지 않았습니다. 목록을 새로고침하고 워크트리를 선택하거나 다시 예약한 뒤 프롬프트를 다시 전송하세요.",
|
|
156
322
|
close: "닫기",
|
|
@@ -169,6 +335,7 @@ const copy$1 = {
|
|
|
169
335
|
errorOperation: "요청",
|
|
170
336
|
operations: {
|
|
171
337
|
describe: "워크트리 조회",
|
|
338
|
+
initialize: "워크트리 선택 초기화",
|
|
172
339
|
create: "워크트리 생성",
|
|
173
340
|
switch: "워크트리 전환"
|
|
174
341
|
},
|
|
@@ -192,8 +359,13 @@ const copy$1 = {
|
|
|
192
359
|
const copy = {
|
|
193
360
|
ko: {
|
|
194
361
|
nav: "워크트리",
|
|
362
|
+
defaultSelection: "기본 선택",
|
|
363
|
+
current: "현재 체크아웃",
|
|
364
|
+
new: "새 워크트리",
|
|
195
365
|
directory: "워크트리 풀 디렉터리",
|
|
196
366
|
remote: "추적 중인 원격 브랜치 사용",
|
|
367
|
+
deleteOnArchive: "보관 시 워크트리 삭제",
|
|
368
|
+
deleteOnArchiveDescription: "이 플러그인이 만든 워크트리만 삭제합니다. 미커밋·미추적·무시된 파일이나 다른 세션이 있으면 유지하며, 브랜치는 삭제하지 않습니다.",
|
|
197
369
|
naming: "자동 브랜치 이름 형식",
|
|
198
370
|
semantic: "시멘틱 (feat/… 또는 fix/…)",
|
|
199
371
|
dsh: "DSH (dsh/*)",
|
|
@@ -209,8 +381,13 @@ const copy = {
|
|
|
209
381
|
},
|
|
210
382
|
zh: {
|
|
211
383
|
nav: "工作树",
|
|
384
|
+
defaultSelection: "默认选择",
|
|
385
|
+
current: "当前检出",
|
|
386
|
+
new: "新工作树",
|
|
212
387
|
directory: "工作树池目录",
|
|
213
388
|
remote: "使用跟踪的远程分支",
|
|
389
|
+
deleteOnArchive: "归档时删除工作树",
|
|
390
|
+
deleteOnArchiveDescription: "仅删除此插件创建的工作树。有未提交、未跟踪、被忽略的文件或其他会话使用时保留,不删除分支。",
|
|
214
391
|
naming: "自动分支命名格式",
|
|
215
392
|
semantic: "语义化(feat/… 或 fix/…)",
|
|
216
393
|
dsh: "DSH(dsh/*)",
|
|
@@ -226,8 +403,13 @@ const copy = {
|
|
|
226
403
|
},
|
|
227
404
|
en: {
|
|
228
405
|
nav: "Worktrees",
|
|
406
|
+
defaultSelection: "Default selection",
|
|
407
|
+
current: "Current checkout",
|
|
408
|
+
new: "New worktree",
|
|
229
409
|
directory: "Worktree pool directory",
|
|
230
410
|
remote: "Use tracked remote branch",
|
|
411
|
+
deleteOnArchive: "Delete worktree on archive",
|
|
412
|
+
deleteOnArchiveDescription: "Only removes worktrees created by this plugin. Keeps worktrees with uncommitted, untracked or ignored files, or other sessions. Branches are kept.",
|
|
231
413
|
naming: "Automatic branch naming",
|
|
232
414
|
semantic: "Semantic (feat/… or fix/…)",
|
|
233
415
|
dsh: "DSH (dsh/*)",
|
|
@@ -249,14 +431,13 @@ const validPrefix = (value) => value.length <= 100 && (value === "" || /^[a-zA-Z
|
|
|
249
431
|
const validSettings = (settings) => validDirectory(settings.directory) && validPrefix(settings.prefix) && (settings.naming !== "custom" || !!settings.prefix);
|
|
250
432
|
const sameSettings = (left, right) => JSON.stringify(left) === JSON.stringify(right);
|
|
251
433
|
function WorktreeSettingsSection({ ctx }) {
|
|
252
|
-
const
|
|
434
|
+
const { active: language } = useLocaleSnapshot(ctx.locale);
|
|
253
435
|
const text = copy[languageKey(language)];
|
|
254
436
|
const id = (0, react.useId)();
|
|
255
437
|
const connection = ctx.get("connection");
|
|
256
438
|
const [draft, setDraft] = (0, react.useState)();
|
|
257
439
|
const [operation, setOperation] = (0, react.useState)("loading");
|
|
258
440
|
const [notice, setNotice] = (0, react.useState)();
|
|
259
|
-
const [namingOpen, setNamingOpen] = (0, react.useState)(false);
|
|
260
441
|
const saved = (0, react.useRef)(void 0);
|
|
261
442
|
const latest = (0, react.useRef)(void 0);
|
|
262
443
|
const pending = (0, react.useRef)(false);
|
|
@@ -277,7 +458,6 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
277
458
|
if (!controller || controller.signal.aborted || pending.current) return;
|
|
278
459
|
pending.current = true;
|
|
279
460
|
blocked.current = true;
|
|
280
|
-
setNamingOpen(false);
|
|
281
461
|
setOperation("loading");
|
|
282
462
|
try {
|
|
283
463
|
await read(controller);
|
|
@@ -327,7 +507,6 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
327
507
|
} finally {
|
|
328
508
|
if (!controller.signal.aborted) {
|
|
329
509
|
if (blocked.current) {
|
|
330
|
-
setNamingOpen(false);
|
|
331
510
|
setOperation("loading");
|
|
332
511
|
try {
|
|
333
512
|
await read(controller);
|
|
@@ -383,19 +562,37 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
383
562
|
draft && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
384
563
|
disabled,
|
|
385
564
|
children: [
|
|
386
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
className: "dsh-worktree-settings-
|
|
390
|
-
children:
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
566
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
567
|
+
id: `${id}-default-selection`,
|
|
568
|
+
className: "dsh-worktree-settings-title",
|
|
569
|
+
children: text.defaultSelection
|
|
570
|
+
}),
|
|
571
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsPicker, {
|
|
572
|
+
className: "dsh-worktree-settings-picker",
|
|
573
|
+
disabled,
|
|
574
|
+
"aria-labelledby": `${id}-default-selection`,
|
|
575
|
+
value: text[draft.defaultSelection],
|
|
576
|
+
selectedId: draft.defaultSelection,
|
|
577
|
+
items: ["current", "new"].map((id) => ({
|
|
578
|
+
id,
|
|
579
|
+
label: text[id]
|
|
580
|
+
})),
|
|
581
|
+
onSelect: (defaultSelection) => {
|
|
582
|
+
change({ defaultSelection });
|
|
583
|
+
}
|
|
584
|
+
})
|
|
585
|
+
}),
|
|
586
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
587
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
588
|
+
htmlFor: `${id}-directory`,
|
|
589
|
+
children: text.directory
|
|
590
|
+
}), invalidDirectory && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
591
|
+
id: `${id}-directory-error`,
|
|
592
|
+
role: "alert",
|
|
593
|
+
children: text.invalidDirectory
|
|
594
|
+
})] }),
|
|
595
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
399
596
|
className: "dsh-worktree-settings-input",
|
|
400
597
|
id: `${id}-directory`,
|
|
401
598
|
type: "text",
|
|
@@ -407,36 +604,43 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
407
604
|
"aria-invalid": invalidDirectory || void 0,
|
|
408
605
|
"aria-describedby": invalidDirectory ? `${id}-directory-error` : void 0,
|
|
409
606
|
onChange: (event) => change({ directory: event.target.value })
|
|
410
|
-
})
|
|
607
|
+
})
|
|
411
608
|
}),
|
|
412
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
children: text.remote
|
|
419
|
-
})
|
|
420
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
609
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
610
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
611
|
+
className: "dsh-worktree-settings-title",
|
|
612
|
+
children: text.remote
|
|
613
|
+
}),
|
|
614
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
421
615
|
label: text.remote,
|
|
422
616
|
checked: draft.remote,
|
|
423
617
|
disabled,
|
|
424
618
|
onChange: (remote) => change({ remote })
|
|
425
|
-
})
|
|
619
|
+
})
|
|
426
620
|
}),
|
|
427
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
621
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
622
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
623
|
+
className: "dsh-worktree-settings-title",
|
|
624
|
+
children: text.deleteOnArchive
|
|
625
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: text.deleteOnArchiveDescription })] }),
|
|
626
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
|
|
627
|
+
label: text.deleteOnArchive,
|
|
628
|
+
checked: draft.deleteOnArchive,
|
|
629
|
+
disabled,
|
|
630
|
+
onChange: (deleteOnArchive) => change({ deleteOnArchive })
|
|
631
|
+
})
|
|
632
|
+
}),
|
|
633
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
634
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
635
|
+
id: `${id}-naming`,
|
|
636
|
+
className: "dsh-worktree-settings-title",
|
|
637
|
+
children: text.naming
|
|
638
|
+
}),
|
|
639
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsPicker, {
|
|
640
|
+
className: "dsh-worktree-settings-picker",
|
|
641
|
+
disabled,
|
|
642
|
+
"aria-labelledby": `${id}-naming`,
|
|
643
|
+
value: text[draft.naming],
|
|
440
644
|
selectedId: draft.naming,
|
|
441
645
|
items: [
|
|
442
646
|
"semantic",
|
|
@@ -446,39 +650,21 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
446
650
|
id,
|
|
447
651
|
label: text[id]
|
|
448
652
|
})),
|
|
449
|
-
onClose: () => setNamingOpen(false),
|
|
450
653
|
onSelect: (naming) => {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
455
|
-
type: "button",
|
|
456
|
-
className: "dsh-worktree-settings-selector",
|
|
457
|
-
disabled,
|
|
458
|
-
"aria-labelledby": `${id}-naming`,
|
|
459
|
-
"aria-haspopup": "menu",
|
|
460
|
-
"aria-expanded": namingOpen,
|
|
461
|
-
onClick: () => setNamingOpen((open) => !open),
|
|
462
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text[draft.naming] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {
|
|
463
|
-
size: 16,
|
|
464
|
-
"aria-hidden": "true"
|
|
465
|
-
})]
|
|
466
|
-
})
|
|
467
|
-
})]
|
|
654
|
+
change({ naming });
|
|
655
|
+
}
|
|
656
|
+
})
|
|
468
657
|
}),
|
|
469
|
-
draft.naming === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
children: text.invalidPrefix
|
|
480
|
-
})]
|
|
481
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
658
|
+
draft.naming === "custom" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsRow, {
|
|
659
|
+
label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
660
|
+
htmlFor: `${id}-prefix`,
|
|
661
|
+
children: text.prefix
|
|
662
|
+
}), invalidPrefix && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
663
|
+
id: `${id}-prefix-error`,
|
|
664
|
+
role: "alert",
|
|
665
|
+
children: text.invalidPrefix
|
|
666
|
+
})] }),
|
|
667
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
482
668
|
className: "dsh-worktree-settings-input",
|
|
483
669
|
id: `${id}-prefix`,
|
|
484
670
|
type: "text",
|
|
@@ -491,7 +677,7 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
491
677
|
autoComplete: "off",
|
|
492
678
|
spellCheck: false,
|
|
493
679
|
onChange: (event) => change({ prefix: event.target.value })
|
|
494
|
-
})
|
|
680
|
+
})
|
|
495
681
|
})
|
|
496
682
|
]
|
|
497
683
|
}),
|
|
@@ -508,30 +694,28 @@ function WorktreeSettingsSection({ ctx }) {
|
|
|
508
694
|
});
|
|
509
695
|
}
|
|
510
696
|
// src/styles.ts
|
|
511
|
-
const styles =
|
|
697
|
+
const styles = `${settingsStyles}${composerStyles}
|
|
512
698
|
.dsh-worktree-sidebar-name { flex: 0 1 auto; min-width: 0; max-width: 88px; margin-inline: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-caption); font-size: 10px; line-height: 16px; }
|
|
699
|
+
[data-row-key]:has(.dsh-vcs-session-request) > .dsh-worktree-sidebar-name { display: none; }
|
|
513
700
|
.dsh-worktree { display: inline-flex; flex-wrap: wrap; align-items: center; min-width: 0; max-width: 100%; color: var(--dsw-alias-label-secondary); font: inherit; }
|
|
514
|
-
.dsh-worktree-controls { display: inline-flex; flex-wrap: nowrap; align-items: center; min-width: 0; max-width: 100%; }
|
|
515
701
|
.dsh-worktree-picker { display: inline-flex; min-width: 0; max-width: 100%; }
|
|
516
|
-
.dsh-worktree-
|
|
517
|
-
.dsh-worktree-
|
|
518
|
-
.dsh-worktree-
|
|
519
|
-
.dsh-worktree-
|
|
520
|
-
.dsh-worktree-
|
|
521
|
-
.dsh-worktree-trigger
|
|
522
|
-
.dsh-worktree-trigger
|
|
702
|
+
.dsh-worktree-pinned { position: sticky; top: 0; z-index: 1; background: var(--dsw-alias-bg-layer-1); }
|
|
703
|
+
.dsh-worktree-option { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
704
|
+
.dsh-worktree-option > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
705
|
+
.dsh-worktree-option > svg { flex: none; width: 14px; height: 14px; margin-inline-start: auto; color: var(--dsw-alias-label-primary); }
|
|
706
|
+
.dsh-worktree-badge { flex: none; padding: 1px 5px; border: 1px solid var(--dsw-alias-border-l2); border-radius: var(--dsw-radius-sm); color: var(--dsw-alias-label-secondary); font-size: 11px; line-height: 16px; font-weight: 400; }
|
|
707
|
+
.dsh-worktree-trigger { display: inline-flex; max-width: 220px; font-weight: 500; }
|
|
708
|
+
.dsh-worktree-trigger .dsh-plugin-composer-icon svg { width: 14px; height: 14px; }
|
|
523
709
|
.dsh-worktree-trigger:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 0; }
|
|
524
710
|
@container (width <= 460px) {
|
|
525
|
-
.dsh-worktree-
|
|
711
|
+
.dsh-worktree-trigger .dsh-plugin-composer-label { display: none; }
|
|
526
712
|
}
|
|
527
713
|
@media (prefers-reduced-motion: no-preference) {
|
|
528
|
-
.dsh-worktree-chevron { transition: transform .12s; }
|
|
714
|
+
.dsh-worktree-trigger .dsh-plugin-composer-chevron { transition: transform .12s; }
|
|
529
715
|
}
|
|
530
716
|
@media (hover: hover) {
|
|
531
|
-
.dsh-worktree-trigger:hover:not(:disabled), .dsh-worktree-
|
|
717
|
+
.dsh-worktree-trigger:hover:not(:disabled), .dsh-worktree-dialog button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
532
718
|
}
|
|
533
|
-
.dsh-worktree-error-trigger { flex: 0 0 auto; min-height: 28px; padding: 2px 6px; border: 0; border-radius: var(--dsw-radius-sm); background: transparent; color: var(--dsw-alias-label-secondary); font: inherit; font-size: 12px; line-height: 20px; white-space: nowrap; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
|
|
534
|
-
.dsh-worktree-error-trigger:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 0; }
|
|
535
719
|
.dsh-worktree-dialog.dsh-worktree-error-dialog { inset: 0; margin: auto; }
|
|
536
720
|
.dsh-worktree-error-dialog dl { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 12px; }
|
|
537
721
|
.dsh-worktree-error-dialog dt { color: var(--dsw-alias-label-secondary); }
|
|
@@ -547,40 +731,35 @@ const styles = `
|
|
|
547
731
|
.dsh-worktree-dialog button:disabled { opacity: .45; cursor: not-allowed; }
|
|
548
732
|
.dsh-worktree-dialog button:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 2px; }
|
|
549
733
|
.dsh-worktree-sr { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
550
|
-
.dsh-worktree-progress { margin: 12px 0 20px; color: var(--dsw-alias-label-secondary); font: 13px
|
|
734
|
+
.dsh-worktree-progress { margin: 12px 0 20px; color: var(--dsw-alias-label-secondary); font: inherit; font-size: var(--dsh-content-font-size-secondary, 13px); line-height: calc(20px + var(--dsh-content-font-delta-secondary, 0px)); }
|
|
551
735
|
.dsh-worktree-progress > p { margin: 0 0 8px; overflow-wrap: anywhere; }
|
|
552
736
|
.dsh-worktree-progress ol { list-style: none; margin: 0; padding: 8px 0 0; border-top: 1px solid var(--dsw-alias-border-l2); }
|
|
553
737
|
.dsh-worktree-progress li { display: flex; align-items: center; gap: 10px; padding: 3px 4px; }
|
|
554
738
|
.dsh-worktree-progress li[data-state=pending] { opacity: .4; }
|
|
555
|
-
.dsh-worktree-progress-mark {
|
|
556
|
-
.dsh-worktree-progress
|
|
739
|
+
.dsh-worktree-progress-mark { display: inline-flex; flex: none; align-items: center; justify-content: center; width: calc(16px + var(--dsh-content-font-delta, 0px)); height: calc(16px + var(--dsh-content-font-delta, 0px)); }
|
|
740
|
+
.dsh-worktree-progress-mark svg { width: calc(14px + var(--dsh-content-font-delta, 0px)); height: calc(14px + var(--dsh-content-font-delta, 0px)); }
|
|
557
741
|
.dsh-worktree-progress li[data-state=failed], .dsh-worktree-progress [role=alert] { color: var(--dsw-alias-state-error-primary); }
|
|
558
742
|
.dsh-worktree-progress [role=alert] { margin-top: 10px; font: inherit; }
|
|
559
|
-
.dsh-worktree-progress-time { margin-inline-start: auto; padding-inline-start: 8px; font-size:
|
|
743
|
+
.dsh-worktree-progress-time { margin-inline-start: auto; padding-inline-start: 8px; font-size: calc(var(--dsh-content-font-size-secondary, 13px) - 1px); font-variant-numeric: tabular-nums; }
|
|
560
744
|
@keyframes dsh-worktree-spin { to { transform: rotate(360deg); } }
|
|
561
745
|
@media (prefers-reduced-motion: no-preference) {
|
|
562
746
|
.dsh-worktree-progress li[data-state=running] .dsh-worktree-progress-mark { animation: dsh-worktree-spin .8s linear infinite; }
|
|
563
747
|
}
|
|
564
748
|
.dsh-worktree-settings { width: 100%; color: var(--dsw-alias-label-primary); font: inherit; }
|
|
565
749
|
.dsh-worktree-settings fieldset { min-width: 0; padding: 0; margin: 0; border: 0; }
|
|
566
|
-
.dsh-worktree-settings-row {
|
|
567
|
-
.dsh-worktree-settings-row:last-child { border-bottom: 0; }
|
|
568
|
-
.dsh-worktree-settings-text { flex: 1; min-width: 0; }
|
|
750
|
+
.dsh-worktree-settings .dsh-plugin-settings-row { gap: 24px; }
|
|
751
|
+
.dsh-worktree-settings .dsh-plugin-settings-row:last-child { border-bottom: 0; }
|
|
569
752
|
.dsh-worktree-settings label, .dsh-worktree-settings-title { display: block; font-size: 14px; font-weight: 400; line-height: 20px; }
|
|
570
|
-
.dsh-worktree-settings-text p { margin: 4px 0 0; color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
|
|
753
|
+
.dsh-worktree-settings .dsh-plugin-settings-text p { margin: 4px 0 0; color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
|
|
571
754
|
.dsh-worktree-settings-input { box-sizing: border-box; width: 220px; max-width: 100%; flex: 0 1 220px; min-width: 0; }
|
|
572
|
-
.dsh-worktree-settings-
|
|
573
|
-
.dsh-worktree-settings-selector
|
|
574
|
-
.dsh-worktree-settings-selector svg { flex: none; }
|
|
575
|
-
.dsh-worktree-settings-selector:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
576
|
-
.dsh-worktree-settings-selector:disabled { opacity: .5; cursor: default; }
|
|
577
|
-
.dsh-worktree-settings-selector:focus-visible { outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 2px; }
|
|
755
|
+
.dsh-worktree-settings-picker .dsh-plugin-settings-selector { max-width: 220px; color: var(--dsw-alias-label-primary); font-size: 14px; line-height: 22px; }
|
|
756
|
+
.dsh-worktree-settings-picker .dsh-plugin-settings-selector:focus-visible { outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
|
|
578
757
|
.dsh-worktree-settings [role=status], .dsh-worktree-settings [role=alert] { margin: 12px 0; font-size: 12px; line-height: 18px; }
|
|
579
758
|
.dsh-worktree-settings [role=status]:empty { margin: 0; }
|
|
580
759
|
.dsh-worktree-settings [role=alert] { color: var(--dsw-alias-state-error-primary); }
|
|
581
760
|
@media (max-width: 600px) {
|
|
582
|
-
.dsh-worktree-settings-row { flex-wrap: wrap; gap: 12px; }
|
|
583
|
-
.dsh-worktree-settings-text { flex-basis: 160px; }
|
|
761
|
+
.dsh-worktree-settings .dsh-plugin-settings-row { flex-wrap: wrap; gap: 12px; }
|
|
762
|
+
.dsh-worktree-settings .dsh-plugin-settings-text { flex-basis: 160px; }
|
|
584
763
|
.dsh-worktree-settings-input { flex-grow: 1; }
|
|
585
764
|
}
|
|
586
765
|
`;
|
|
@@ -699,7 +878,7 @@ const progressDefinition = {
|
|
|
699
878
|
anchorSeq: context.state.anchorSeq,
|
|
700
879
|
location: context.start.location,
|
|
701
880
|
visibility: "visible",
|
|
702
|
-
groupTree: "turn",
|
|
881
|
+
groupTree: context.state.progress.status === "completed" ? void 0 : "turn",
|
|
703
882
|
data: context.state.progress
|
|
704
883
|
};
|
|
705
884
|
}
|
|
@@ -711,7 +890,7 @@ function installProgress(ctx) {
|
|
|
711
890
|
key: "dungsil-worktree-progress",
|
|
712
891
|
inject: () => ({})
|
|
713
892
|
}, function Progress({ node }) {
|
|
714
|
-
const
|
|
893
|
+
const { active: language } = useLocaleSnapshot(ctx.locale);
|
|
715
894
|
const text = labels[language.startsWith("ko") ? "ko" : language.startsWith("zh") ? "zh" : "en"];
|
|
716
895
|
const progress = node.data;
|
|
717
896
|
const ended = node.location.kind === "turn" || node.location.kind === "step" ? node.location.turn.status === "closed" : false;
|
|
@@ -741,7 +920,7 @@ function installProgress(ctx) {
|
|
|
741
920
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
742
921
|
className: "dsh-worktree-progress-mark",
|
|
743
922
|
"aria-hidden": "true",
|
|
744
|
-
children: state === "completed" ?
|
|
923
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(state === "completed" ? _deepseek_ai_dsh_client_ui_primitives.IconCheckCircleOutlineRegular : state === "failed" ? _deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular : state === "cancelled" ? _deepseek_ai_dsh_client_ui_primitives.IconStopFillRegular : state === "running" ? _deepseek_ai_dsh_client_ui_primitives.IconLoadingOutlineRegular : _deepseek_ai_dsh_client_ui_primitives.IconClockOutlineRegular, { size: 14 })
|
|
745
924
|
}),
|
|
746
925
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }),
|
|
747
926
|
state !== "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -768,15 +947,26 @@ const inject = [
|
|
|
768
947
|
"uiConversation"
|
|
769
948
|
];
|
|
770
949
|
function apply(ctx) {
|
|
950
|
+
ctx.effect(() => installSettingsIcon(name, [
|
|
951
|
+
"en",
|
|
952
|
+
"ko",
|
|
953
|
+
"zh"
|
|
954
|
+
].map(settingsLabel), git_branch_default));
|
|
771
955
|
const connection = ctx.get("connection");
|
|
772
|
-
const subscribeLocale = (listener) => ctx.locale.subscribe(listener);
|
|
773
956
|
installProgress(ctx);
|
|
774
957
|
function Picker({ sessionId, useSession }) {
|
|
775
|
-
const language = (
|
|
958
|
+
const { active: language } = useLocaleSnapshot(ctx.locale);
|
|
776
959
|
const text = copy$1[language.startsWith("ko") ? "ko" : language.startsWith("zh") ? "zh" : "en"];
|
|
777
960
|
const unavailable = useSession((s) => s.running || s.removed || s.openState !== "open" || s.pendingSubmissions.length > 0);
|
|
778
|
-
const
|
|
779
|
-
|
|
961
|
+
const unavailableRef = (0, react.useRef)(unavailable);
|
|
962
|
+
unavailableRef.current = unavailable;
|
|
963
|
+
const unreadable = useSession((s) => s.removed || s.openState !== "open");
|
|
964
|
+
const unreadableRef = (0, react.useRef)(unreadable);
|
|
965
|
+
unreadableRef.current = unreadable;
|
|
966
|
+
const previousReadiness = (0, react.useRef)({
|
|
967
|
+
unreadable: true,
|
|
968
|
+
unavailable
|
|
969
|
+
});
|
|
780
970
|
const [view, setView] = (0, react.useState)();
|
|
781
971
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
782
972
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
@@ -784,11 +974,11 @@ function apply(ctx) {
|
|
|
784
974
|
const [changed, setChanged] = (0, react.useState)(false);
|
|
785
975
|
const [open, setOpen] = (0, react.useState)(false);
|
|
786
976
|
const pending = (0, react.useRef)(false);
|
|
977
|
+
const reloadRequested = (0, react.useRef)(false);
|
|
787
978
|
const needsRefresh = (0, react.useRef)(false);
|
|
788
979
|
const lifetime = (0, react.useRef)(null);
|
|
789
980
|
const trigger = (0, react.useRef)(null);
|
|
790
981
|
const errorDialog = (0, react.useRef)(null);
|
|
791
|
-
const errorTrigger = (0, react.useRef)(null);
|
|
792
982
|
const errorTitle = (0, react.useId)();
|
|
793
983
|
const errorDescription = (0, react.useId)();
|
|
794
984
|
const status = (0, react.useId)();
|
|
@@ -823,21 +1013,40 @@ function apply(ctx) {
|
|
|
823
1013
|
};
|
|
824
1014
|
const load = async (explicit = false) => {
|
|
825
1015
|
const controller = lifetime.current;
|
|
826
|
-
if (!controller || controller.signal.aborted ||
|
|
1016
|
+
if (!controller || controller.signal.aborted || unreadableRef.current || needsRefresh.current && !explicit) return;
|
|
1017
|
+
if (pending.current) {
|
|
1018
|
+
reloadRequested.current = true;
|
|
1019
|
+
return;
|
|
1020
|
+
}
|
|
1021
|
+
reloadRequested.current = false;
|
|
827
1022
|
pending.current = true;
|
|
828
1023
|
setLoading(true);
|
|
1024
|
+
let operation = "describe";
|
|
829
1025
|
try {
|
|
830
1026
|
const view = await request("describe", { sessionId }, controller.signal);
|
|
831
1027
|
if (controller.signal.aborted) return;
|
|
832
1028
|
setView(view);
|
|
1029
|
+
if (view.needsInitialization && !unavailableRef.current) {
|
|
1030
|
+
operation = "initialize";
|
|
1031
|
+
const initialized = await request("initialize", {
|
|
1032
|
+
sessionId,
|
|
1033
|
+
cwd: view.cwd
|
|
1034
|
+
}, controller.signal);
|
|
1035
|
+
if (controller.signal.aborted) return;
|
|
1036
|
+
setView(initialized);
|
|
1037
|
+
}
|
|
833
1038
|
needsRefresh.current = false;
|
|
834
1039
|
setError(void 0);
|
|
835
1040
|
} catch (cause) {
|
|
836
|
-
if (!controller.signal.aborted) recordFailure(
|
|
1041
|
+
if (!controller.signal.aborted && failureCode(cause) !== "busy") recordFailure(operation, cause);
|
|
837
1042
|
} finally {
|
|
838
1043
|
if (!controller.signal.aborted) {
|
|
839
1044
|
pending.current = false;
|
|
840
1045
|
setLoading(false);
|
|
1046
|
+
if (reloadRequested.current) {
|
|
1047
|
+
reloadRequested.current = false;
|
|
1048
|
+
load();
|
|
1049
|
+
}
|
|
841
1050
|
}
|
|
842
1051
|
}
|
|
843
1052
|
};
|
|
@@ -845,7 +1054,6 @@ function apply(ctx) {
|
|
|
845
1054
|
const controller = new AbortController();
|
|
846
1055
|
lifetime.current = controller;
|
|
847
1056
|
pending.current = false;
|
|
848
|
-
load();
|
|
849
1057
|
const focus = () => {
|
|
850
1058
|
load();
|
|
851
1059
|
};
|
|
@@ -861,9 +1069,13 @@ function apply(ctx) {
|
|
|
861
1069
|
};
|
|
862
1070
|
}, []);
|
|
863
1071
|
(0, react.useEffect)(() => {
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1072
|
+
const previous = previousReadiness.current;
|
|
1073
|
+
previousReadiness.current = {
|
|
1074
|
+
unreadable,
|
|
1075
|
+
unavailable
|
|
1076
|
+
};
|
|
1077
|
+
if (!unreadable && (previous.unreadable || previous.unavailable && !unavailable)) load();
|
|
1078
|
+
}, [unreadable, unavailable]);
|
|
867
1079
|
(0, react.useEffect)(() => {
|
|
868
1080
|
if (disabled) setOpen(false);
|
|
869
1081
|
}, [disabled]);
|
|
@@ -904,7 +1116,7 @@ function apply(ctx) {
|
|
|
904
1116
|
if (!detailError && errorDialog.current?.open) errorDialog.current.close();
|
|
905
1117
|
}, [error, creation?.failed]);
|
|
906
1118
|
const restoreErrorFocus = () => {
|
|
907
|
-
|
|
1119
|
+
trigger.current?.focus();
|
|
908
1120
|
};
|
|
909
1121
|
const current = currentWorktree(view);
|
|
910
1122
|
(0, react.useEffect)(() => {
|
|
@@ -916,79 +1128,86 @@ function apply(ctx) {
|
|
|
916
1128
|
view
|
|
917
1129
|
]);
|
|
918
1130
|
const branch = creation ? creation.failed ? text.mutationError : text.create : current ? current.branch ?? text.detached : text.unknown;
|
|
1131
|
+
const label = detailError ? errorLabel : view ? branch : loading ? text.loading : text.title;
|
|
919
1132
|
const notice = loading ? text.loading : busy ? text.busy : error ? errorLabel : unavailable ? text.wait : creation ? creation.failed ? text.creationError : text.reservationHint : changed ? text.changed : view?.worktrees.length === 0 ? text.empty : "";
|
|
920
1133
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
921
1134
|
className: "dsh-worktree",
|
|
922
1135
|
children: [
|
|
923
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
924
|
-
className: "dsh-worktree-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (
|
|
944
|
-
|
|
945
|
-
if (!creation || creation.failed) change("create");
|
|
946
|
-
} else if (id.startsWith("path:") && (creation || id !== `path:${current?.path}`)) change("switch", id.slice(5));
|
|
1136
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1137
|
+
className: "dsh-worktree-picker",
|
|
1138
|
+
open,
|
|
1139
|
+
side: "top",
|
|
1140
|
+
portal: true,
|
|
1141
|
+
listClassName: "dsh-worktree-menu",
|
|
1142
|
+
onClose: () => setOpen(false),
|
|
1143
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ComposerTrigger, {
|
|
1144
|
+
ref: trigger,
|
|
1145
|
+
className: "dsh-worktree-trigger",
|
|
1146
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {}),
|
|
1147
|
+
label,
|
|
1148
|
+
disabled: detailError ? loading || busy : disabled,
|
|
1149
|
+
"aria-label": `${text.title}: ${label}`,
|
|
1150
|
+
"aria-haspopup": detailError ? "dialog" : "menu",
|
|
1151
|
+
"aria-expanded": detailError ? void 0 : open,
|
|
1152
|
+
"aria-describedby": status,
|
|
1153
|
+
"aria-busy": loading || busy,
|
|
1154
|
+
title: label,
|
|
1155
|
+
onClick: () => {
|
|
1156
|
+
if (detailError) errorDialog.current?.showModal();
|
|
1157
|
+
else setOpen((value) => !value);
|
|
947
1158
|
},
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1159
|
+
onKeyDown: (event) => {
|
|
1160
|
+
if (!detailError && !disabled && !open && (event.key === "ArrowDown" || event.key === "ArrowUp")) {
|
|
1161
|
+
event.preventDefault();
|
|
1162
|
+
setOpen(true);
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
}),
|
|
1166
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1167
|
+
className: "dsh-worktree-pinned",
|
|
1168
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuItemButton, {
|
|
1169
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, {}),
|
|
1170
|
+
current: !!creation,
|
|
1171
|
+
onSelect: () => {
|
|
1172
|
+
setOpen(false);
|
|
1173
|
+
if (!creation || creation.failed) change("create");
|
|
1174
|
+
},
|
|
1175
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1176
|
+
className: "dsh-worktree-option",
|
|
1177
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: text.create }), creation && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {})]
|
|
1178
|
+
})
|
|
1179
|
+
}), view?.worktrees.slice(0, 1).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuItemButton, {
|
|
1180
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {}),
|
|
1181
|
+
current: !creation && current === item,
|
|
1182
|
+
onSelect: () => {
|
|
1183
|
+
setOpen(false);
|
|
1184
|
+
if (creation || current !== item) change("switch", item.path);
|
|
965
1185
|
},
|
|
966
|
-
children:
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
"
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1186
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1187
|
+
className: "dsh-worktree-option",
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.branch ?? text.detached }),
|
|
1190
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1191
|
+
className: "dsh-worktree-badge",
|
|
1192
|
+
children: text.primaryBranch
|
|
1193
|
+
}),
|
|
1194
|
+
!creation && current === item && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {})
|
|
1195
|
+
]
|
|
1196
|
+
})
|
|
1197
|
+
}, item.path))]
|
|
1198
|
+
}), view?.worktrees.slice(1).map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuItemButton, {
|
|
1199
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {}),
|
|
1200
|
+
current: !creation && current === item,
|
|
1201
|
+
separatorBefore: index === 0,
|
|
1202
|
+
onSelect: () => {
|
|
1203
|
+
setOpen(false);
|
|
1204
|
+
if (creation || current !== item) change("switch", item.path);
|
|
1205
|
+
},
|
|
1206
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1207
|
+
className: "dsh-worktree-option",
|
|
1208
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.branch ?? text.detached }), !creation && current === item && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {})]
|
|
982
1209
|
})
|
|
983
|
-
}
|
|
984
|
-
ref: errorTrigger,
|
|
985
|
-
type: "button",
|
|
986
|
-
className: "dsh-worktree-error-trigger",
|
|
987
|
-
"aria-haspopup": "dialog",
|
|
988
|
-
"aria-label": `${errorLabel}: ${text.errorTitle}`,
|
|
989
|
-
onClick: () => errorDialog.current?.showModal(),
|
|
990
|
-
children: errorLabel
|
|
991
|
-
})]
|
|
1210
|
+
}, item.path))]
|
|
992
1211
|
}),
|
|
993
1212
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
994
1213
|
id: status,
|
|
@@ -1046,12 +1265,7 @@ function apply(ctx) {
|
|
|
1046
1265
|
label: () => settingsLabel(ctx.locale.getSnapshot().active),
|
|
1047
1266
|
inject: () => ({ ctx })
|
|
1048
1267
|
}, WorktreeSettingsSection));
|
|
1049
|
-
ctx.effect(() =>
|
|
1050
|
-
const style = document.createElement("style");
|
|
1051
|
-
style.textContent = styles;
|
|
1052
|
-
document.head.append(style);
|
|
1053
|
-
return () => style.remove();
|
|
1054
|
-
}, "ui-worktree: composer styles");
|
|
1268
|
+
ctx.effect(() => installStyles(styles), "ui-worktree: composer styles");
|
|
1055
1269
|
}
|
|
1056
1270
|
exports.apply = apply;
|
|
1057
1271
|
exports.inject = inject;
|