@cerbur/clutch-dsh-worktree 0.1.1 → 0.1.3
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 +20 -5
- package/lib/client/WorktreeContext.d.ts +15 -0
- package/lib/client/WorktreeContext.d.ts.map +1 -0
- package/lib/client/WorktreeContext.js +19 -0
- package/lib/client/WorktreeContext.js.map +1 -0
- package/lib/client/WorktreeHeroContext.d.ts +10 -0
- package/lib/client/WorktreeHeroContext.d.ts.map +1 -0
- package/lib/client/WorktreeHeroContext.js +128 -0
- package/lib/client/WorktreeHeroContext.js.map +1 -0
- package/lib/client/WorktreeOverlay.d.ts +6 -0
- package/lib/client/WorktreeOverlay.d.ts.map +1 -0
- package/lib/client/WorktreeOverlay.js +8 -0
- package/lib/client/WorktreeOverlay.js.map +1 -0
- package/lib/client/WorktreeSurface.d.ts +3 -1
- package/lib/client/WorktreeSurface.d.ts.map +1 -1
- package/lib/client/WorktreeSurface.js +204 -58
- package/lib/client/WorktreeSurface.js.map +1 -1
- package/lib/client/entry.d.ts +1 -1
- package/lib/client/entry.d.ts.map +1 -1
- package/lib/client/entry.js +41 -14
- package/lib/client/entry.js.map +1 -1
- package/lib/client/locales.d.ts +30 -0
- package/lib/client/locales.d.ts.map +1 -1
- package/lib/client/locales.js +32 -2
- package/lib/client/locales.js.map +1 -1
- package/lib/client/session-view.d.ts +21 -0
- package/lib/client/session-view.d.ts.map +1 -0
- package/lib/client/session-view.js +26 -0
- package/lib/client/session-view.js.map +1 -0
- package/lib/client/sidebar-overlay-geometry.d.ts +1 -0
- package/lib/client/sidebar-overlay-geometry.d.ts.map +1 -1
- package/lib/client/sidebar-overlay-geometry.js +28 -17
- package/lib/client/sidebar-overlay-geometry.js.map +1 -1
- package/lib/client/virtual-workspace-membership.d.ts.map +1 -1
- package/lib/client/virtual-workspace-membership.js +17 -6
- package/lib/client/virtual-workspace-membership.js.map +1 -1
- package/lib/client/worktree-connection.d.ts +1 -0
- package/lib/client/worktree-connection.d.ts.map +1 -1
- package/lib/client/worktree-connection.js +4 -0
- package/lib/client/worktree-connection.js.map +1 -1
- package/lib/client/worktree-context-store.d.ts +45 -0
- package/lib/client/worktree-context-store.d.ts.map +1 -0
- package/lib/client/worktree-context-store.js +199 -0
- package/lib/client/worktree-context-store.js.map +1 -0
- package/lib/client/worktree-context.d.ts +32 -0
- package/lib/client/worktree-context.d.ts.map +1 -0
- package/lib/client/worktree-context.js +51 -0
- package/lib/client/worktree-context.js.map +1 -0
- package/lib/client/worktree-error-copy.d.ts.map +1 -1
- package/lib/client/worktree-error-copy.js +14 -0
- package/lib/client/worktree-error-copy.js.map +1 -1
- package/lib/client/worktree-session.d.ts +83 -0
- package/lib/client/worktree-session.d.ts.map +1 -0
- package/lib/client/worktree-session.js +185 -0
- package/lib/client/worktree-session.js.map +1 -0
- package/lib/client/worktree-view.d.ts +37 -3
- package/lib/client/worktree-view.d.ts.map +1 -1
- package/lib/client/worktree-view.js +145 -7
- package/lib/client/worktree-view.js.map +1 -1
- package/lib/client.js +1015 -134
- package/lib/client.js.map +1 -1
- package/lib/contract/index.contract.js +2 -0
- package/lib/contract/index.contract.js.map +1 -1
- package/lib/contract/index.d.ts +17 -2
- package/lib/contract/index.d.ts.map +1 -1
- package/lib/contract/index.js +2 -0
- package/lib/contract/index.js.map +1 -1
- package/lib/host/remote.d.ts.map +1 -1
- package/lib/host/remote.js +1 -0
- package/lib/host/remote.js.map +1 -1
- package/lib/host/service.d.ts +6 -1
- package/lib/host/service.d.ts.map +1 -1
- package/lib/host/service.js +6 -0
- package/lib/host/service.js.map +1 -1
- package/lib/manage/manager.d.ts +6 -1
- package/lib/manage/manager.d.ts.map +1 -1
- package/lib/manage/manager.js +12 -1
- package/lib/manage/manager.js.map +1 -1
- package/lib/provider/sidecar.d.ts +2 -1
- package/lib/provider/sidecar.d.ts.map +1 -1
- package/lib/provider/sidecar.js +40 -0
- package/lib/provider/sidecar.js.map +1 -1
- package/lib/provider/types.d.ts +2 -1
- package/lib/provider/types.d.ts.map +1 -1
- package/lib/provider/types.js.map +1 -1
- package/lib/typert.host.js +60 -18
- package/lib/typert.remote-client.d.ts +3 -1
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +60 -18
- package/package.json +6 -2
package/lib/client.js
CHANGED
|
@@ -4,10 +4,10 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
7
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
9
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
10
|
let react = require("react");
|
|
10
|
-
let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
11
11
|
//#region lib/client/locales.js
|
|
12
12
|
const WORKTREE_NS = "worktree";
|
|
13
13
|
const zh = {
|
|
@@ -15,6 +15,8 @@ window.__ModuleLoader__.load({
|
|
|
15
15
|
"mode.exit": "退出 Worktree 模式",
|
|
16
16
|
"mode.label": "Worktree",
|
|
17
17
|
"mode.navigation": "Worktree 导航",
|
|
18
|
+
"context.main": "当前分支:{name}",
|
|
19
|
+
"context.worktree": "Worktree:{name}",
|
|
18
20
|
"workspace.rename": "重命名",
|
|
19
21
|
"workspace.delete": "删除",
|
|
20
22
|
"workspace.expand": "展开 {name}",
|
|
@@ -30,7 +32,8 @@ window.__ModuleLoader__.load({
|
|
|
30
32
|
"workspace.deleteTitle": "删除工作区",
|
|
31
33
|
"workspace.deleteDescription": "删除“{name}”?这只会移除 DSH 工作区注册。目录、会话和 Git Worktree 会保留。",
|
|
32
34
|
"worktree.title": "Worktree",
|
|
33
|
-
"worktree.main": "
|
|
35
|
+
"worktree.main": "本地",
|
|
36
|
+
"worktree.mainWithBranch": "本地({branch})",
|
|
34
37
|
"worktree.detached": "已分离 Worktree",
|
|
35
38
|
"worktree.repair": "Worktree 需要修复",
|
|
36
39
|
"worktree.ready": "活动 Worktree 已就绪",
|
|
@@ -46,9 +49,14 @@ window.__ModuleLoader__.load({
|
|
|
46
49
|
"worktree.baseBranch": "Worktree 基线分支",
|
|
47
50
|
"worktree.noLocalBranch": "没有本地分支",
|
|
48
51
|
"worktree.noBranches": "此工作区中没有找到本地分支。",
|
|
52
|
+
"worktree.setup.noRepository": "此 Workspace 不是 Git 仓库。请在 Workspace 目录执行以下命令:",
|
|
53
|
+
"worktree.setup.noInitialCommit": "此 Git 仓库还没有首次 commit。请先执行以下命令:",
|
|
54
|
+
"worktree.setup.noLocalBranch": "此 Git 仓库没有本地分支。请先创建一个本地分支:",
|
|
55
|
+
"worktree.setup.commands": "可复制的命令",
|
|
49
56
|
"worktree.name": "Worktree 名称",
|
|
50
57
|
"worktree.create": "创建 Worktree",
|
|
51
58
|
"session.options": "会话选项:{name}",
|
|
59
|
+
"session.new": "新会话",
|
|
52
60
|
"session.rename": "重命名会话",
|
|
53
61
|
"session.fork": "Fork 会话",
|
|
54
62
|
"session.archive": "归档会话",
|
|
@@ -73,6 +81,7 @@ window.__ModuleLoader__.load({
|
|
|
73
81
|
"error.invalidResult": "Worktree endpoint {endpoint} 返回了无效结果,请重试请求。",
|
|
74
82
|
"error.workspaceOrderingUnavailable": "工作区排序不可用,请重新连接后重试。",
|
|
75
83
|
"error.sessionOrderingUnavailable": "会话排序不可用,请重新连接后重试。",
|
|
84
|
+
"error.worktreeOrderingUnavailable": "Worktree 排序不可用,请重新连接后重试。",
|
|
76
85
|
"error.worktreeCreatedSessionUnavailable": "Worktree 已创建,但 Session 创建不可用,请重新连接后重试。",
|
|
77
86
|
"error.sessionCreationUnavailable": "Session 创建不可用,请重新连接后重试。",
|
|
78
87
|
"error.worktreeRecordMissing": "Worktree 创建未返回 Worktree 记录,请重试请求。",
|
|
@@ -80,6 +89,12 @@ window.__ModuleLoader__.load({
|
|
|
80
89
|
"error.workspaceDeleteUnavailable": "工作区删除不可用,请重新连接后重试。",
|
|
81
90
|
"error.sessionRenameUnavailable": "会话重命名不可用,请重新连接后重试。",
|
|
82
91
|
"error.sessionBindingFailed": "Session {sessionId} 已创建,但 Worktree 绑定失败:{reason}",
|
|
92
|
+
"error.sessionAlreadyBound": "Session 已绑定到其他 Worktree,未创建新的 Session。",
|
|
93
|
+
"error.sessionListNotReady": "Session 列表尚未就绪,请重试。",
|
|
94
|
+
"error.sessionFactsIncomplete": "Session 信息尚未完整,请重试。",
|
|
95
|
+
"error.worktreeSessionRepairRequired": "当前 Worktree 的 Session 绑定需要修复,请重试。",
|
|
96
|
+
"error.worktreeSessionUnavailable": "当前 Worktree 不可用,请重试。",
|
|
97
|
+
"error.sessionArchived": "该 Session 已归档,无法重试绑定。",
|
|
83
98
|
"branch.current": "(当前)",
|
|
84
99
|
"branch.checkedOut": "(已检出)"
|
|
85
100
|
};
|
|
@@ -88,6 +103,8 @@ window.__ModuleLoader__.load({
|
|
|
88
103
|
"mode.exit": "Exit Worktree mode",
|
|
89
104
|
"mode.label": "Worktree",
|
|
90
105
|
"mode.navigation": "Worktree navigation",
|
|
106
|
+
"context.main": "Current branch: {name}",
|
|
107
|
+
"context.worktree": "Worktree: {name}",
|
|
91
108
|
"workspace.rename": "Rename",
|
|
92
109
|
"workspace.delete": "Delete",
|
|
93
110
|
"workspace.expand": "Expand {name}",
|
|
@@ -103,7 +120,8 @@ window.__ModuleLoader__.load({
|
|
|
103
120
|
"workspace.deleteTitle": "Delete Workspace",
|
|
104
121
|
"workspace.deleteDescription": "Delete {name}? This removes only the DSH Workspace registration. The directory, Sessions, and Git Worktrees will be retained.",
|
|
105
122
|
"worktree.title": "Worktrees",
|
|
106
|
-
"worktree.main": "
|
|
123
|
+
"worktree.main": "Local",
|
|
124
|
+
"worktree.mainWithBranch": "Local ({branch})",
|
|
107
125
|
"worktree.detached": "Detached Worktree",
|
|
108
126
|
"worktree.repair": "Worktree needs repair",
|
|
109
127
|
"worktree.ready": "Active Worktree ready",
|
|
@@ -119,9 +137,14 @@ window.__ModuleLoader__.load({
|
|
|
119
137
|
"worktree.baseBranch": "Worktree base branch",
|
|
120
138
|
"worktree.noLocalBranch": "No local branch",
|
|
121
139
|
"worktree.noBranches": "No local branches found in this Workspace.",
|
|
140
|
+
"worktree.setup.noRepository": "This Workspace is not a Git repository. Run these commands in the Workspace directory:",
|
|
141
|
+
"worktree.setup.noInitialCommit": "This Git repository has no initial commit. Run these commands first:",
|
|
142
|
+
"worktree.setup.noLocalBranch": "This Git repository has no local branch. Create one first:",
|
|
143
|
+
"worktree.setup.commands": "Copyable commands",
|
|
122
144
|
"worktree.name": "Worktree name",
|
|
123
145
|
"worktree.create": "Create Worktree",
|
|
124
146
|
"session.options": "Session options for {name}",
|
|
147
|
+
"session.new": "New Session",
|
|
125
148
|
"session.rename": "Rename session",
|
|
126
149
|
"session.fork": "Fork session",
|
|
127
150
|
"session.archive": "Archive session",
|
|
@@ -146,6 +169,7 @@ window.__ModuleLoader__.load({
|
|
|
146
169
|
"error.invalidResult": "Worktree endpoint {endpoint} returned an invalid result; retry the request.",
|
|
147
170
|
"error.workspaceOrderingUnavailable": "Workspace ordering is unavailable; retry after reconnecting.",
|
|
148
171
|
"error.sessionOrderingUnavailable": "Session ordering is unavailable; retry after reconnecting.",
|
|
172
|
+
"error.worktreeOrderingUnavailable": "Worktree ordering is unavailable; retry after reconnecting.",
|
|
149
173
|
"error.worktreeCreatedSessionUnavailable": "Worktree created, but Session creation is unavailable; retry after reconnecting.",
|
|
150
174
|
"error.sessionCreationUnavailable": "Session creation is unavailable; retry after reconnecting.",
|
|
151
175
|
"error.worktreeRecordMissing": "Worktree creation returned no Worktree record; retry the request.",
|
|
@@ -153,6 +177,12 @@ window.__ModuleLoader__.load({
|
|
|
153
177
|
"error.workspaceDeleteUnavailable": "Workspace delete is unavailable; retry after reconnecting.",
|
|
154
178
|
"error.sessionRenameUnavailable": "Session rename is unavailable; retry after reconnecting.",
|
|
155
179
|
"error.sessionBindingFailed": "Session {sessionId} was created, but Worktree binding failed: {reason}",
|
|
180
|
+
"error.sessionAlreadyBound": "The Session is already bound to another Worktree; no new Session was created.",
|
|
181
|
+
"error.sessionListNotReady": "The Session list is not ready yet; retry the request.",
|
|
182
|
+
"error.sessionFactsIncomplete": "Session facts are incomplete; retry the request.",
|
|
183
|
+
"error.worktreeSessionRepairRequired": "The current Worktree Session binding needs repair; retry the request.",
|
|
184
|
+
"error.worktreeSessionUnavailable": "The current Worktree is unavailable; retry the request.",
|
|
185
|
+
"error.sessionArchived": "This Session is archived and cannot be retried for binding.",
|
|
156
186
|
"branch.current": " (current)",
|
|
157
187
|
"branch.checkedOut": " (checked out)"
|
|
158
188
|
};
|
|
@@ -169,6 +199,7 @@ window.__ModuleLoader__.load({
|
|
|
169
199
|
listBranches: "worktreeManager/listBranches",
|
|
170
200
|
createWorktree: "worktreeManager/createWorktree",
|
|
171
201
|
removeWorktree: "worktreeManager/removeWorktree",
|
|
202
|
+
insertWorktreeBefore: "worktreeManager/insertWorktreeBefore",
|
|
172
203
|
listBindings: "worktreeManager/listBindings",
|
|
173
204
|
bindSession: "worktreeManager/bindSession"
|
|
174
205
|
});
|
|
@@ -275,6 +306,9 @@ window.__ModuleLoader__.load({
|
|
|
275
306
|
async removeWorktree(input) {
|
|
276
307
|
await invoke("removeWorktree", input);
|
|
277
308
|
},
|
|
309
|
+
async insertWorktreeBefore(input) {
|
|
310
|
+
return invoke("insertWorktreeBefore", input);
|
|
311
|
+
},
|
|
278
312
|
listBindings: (input) => invoke("listBindings", input),
|
|
279
313
|
bindSession: (input) => invoke("bindSession", input),
|
|
280
314
|
dispose() {
|
|
@@ -286,8 +320,53 @@ window.__ModuleLoader__.load({
|
|
|
286
320
|
};
|
|
287
321
|
}
|
|
288
322
|
//#endregion
|
|
323
|
+
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/Documents/Code/clutch-dsh/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
|
|
324
|
+
const css$1 = ".-cerbur-clutch-dsh-worktree-headerContext {\n display: inline-flex;\n min-width: 0;\n height: 22px;\n align-items: center;\n gap: 4px;\n max-width: 180px;\n overflow: hidden;\n border-radius: 6px;\n padding: 0 2px 0 0;\n background: var(--dsw-alias-fill-tsp-secondary);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 22px;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-contextIcon {\n flex: none;\n opacity: 0.7;\n}\n\n.-cerbur-clutch-dsh-worktree-contextLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContext {\n position: absolute;\n z-index: 1;\n display: inline-flex;\n box-sizing: border-box;\n max-width: 260px;\n min-height: 22px;\n align-items: center;\n overflow: hidden;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n padding: 0 8px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 20px;\n pointer-events: none;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n";
|
|
325
|
+
const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
|
|
326
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
|
|
327
|
+
const tag = document.createElement("style");
|
|
328
|
+
tag.dataset.plugin = "@cerbur/clutch-dsh-worktree";
|
|
329
|
+
tag.dataset.pluginCss = styleId$1;
|
|
330
|
+
tag.textContent = css$1;
|
|
331
|
+
document.head.appendChild(tag);
|
|
332
|
+
}
|
|
333
|
+
var worktree_context_css_default = {
|
|
334
|
+
"headerContext": "-cerbur-clutch-dsh-worktree-headerContext",
|
|
335
|
+
"contextIcon": "-cerbur-clutch-dsh-worktree-contextIcon",
|
|
336
|
+
"contextLabel": "-cerbur-clutch-dsh-worktree-contextLabel",
|
|
337
|
+
"heroContext": "-cerbur-clutch-dsh-worktree-heroContext"
|
|
338
|
+
};
|
|
339
|
+
//#endregion
|
|
340
|
+
//#region lib/client/WorktreeContext.js
|
|
341
|
+
function WorktreeContextLabel({ value, t }) {
|
|
342
|
+
if (value.kind === "none") return null;
|
|
343
|
+
const ariaLabel = value.kind === "main" ? t("context.main", { name: value.label }) : t("context.worktree", { name: value.label });
|
|
344
|
+
return (0, react_jsx_runtime.jsxs)("span", {
|
|
345
|
+
className: worktree_context_css_default.headerContext,
|
|
346
|
+
title: value.label,
|
|
347
|
+
"aria-label": ariaLabel,
|
|
348
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {
|
|
349
|
+
size: 14,
|
|
350
|
+
className: worktree_context_css_default.contextIcon,
|
|
351
|
+
"aria-hidden": "true"
|
|
352
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
353
|
+
className: worktree_context_css_default.contextLabel,
|
|
354
|
+
children: value.label
|
|
355
|
+
})]
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
/** Render the current branch or active Worktree branch beside the Session title. */
|
|
359
|
+
function WorktreeHeaderContext({ sessionId, useWorktreeContext, t }) {
|
|
360
|
+
const state = useWorktreeContext((snapshot) => snapshot);
|
|
361
|
+
if (state.sessionId !== sessionId) return null;
|
|
362
|
+
return (0, react_jsx_runtime.jsx)(WorktreeContextLabel, {
|
|
363
|
+
value: state.value,
|
|
364
|
+
t
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
//#endregion
|
|
289
368
|
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/Documents/Code/clutch-dsh/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
|
|
290
|
-
const css = ".-cerbur-clutch-dsh-worktree-action {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n width: calc(100% + 4px);\n height: 42px;\n margin: 4px -2px;\n box-sizing: border-box;\n border: 0;\n border-radius: 12px;\n padding: 0 10px 0 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n text-align: left;\n overflow: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-action:hover,\n.-cerbur-clutch-dsh-worktree-action[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-action[data-collapsed='true'] {\n width: 36px;\n height: 36px;\n margin: 8px 0 10px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border-radius: 50%;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n overflow: hidden;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-surface {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n min-width: 56px;\n overflow: hidden;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-specific-sidebar-fill);\n color: var(--dsw-alias-label-primary);\n pointer-events: auto;\n transition: width var(--ds-transition-duration-slow) var(--ds-ease-in-out);\n}\n\n.-cerbur-clutch-dsh-worktree-wideContent {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-wideContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-railContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-railContent {\n display: flex;\n flex: 1;\n align-items: flex-start;\n justify-content: center;\n padding-top: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton,\n.-cerbur-clutch-dsh-worktree-closeButton {\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton {\n width: 36px;\n height: 36px;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton:hover,\n.-cerbur-clutch-dsh-worktree-closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: none;\n min-height: 44px;\n padding: 6px 10px;\n box-sizing: border-box;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-title {\n min-width: 0;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n flex: none;\n width: 28px;\n height: 28px;\n font-size: 18px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-modeButton[data-active='true'] {\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspacePicker {\n display: block;\n width: calc(100% - 20px);\n margin: 6px 10px 8px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceLabel {\n display: block;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n padding: 0 10px 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-content:focus-visible {\n outline: 2px solid var(--dsw-alias-border-l3);\n outline-offset: -2px;\n}\n\n.-cerbur-clutch-dsh-worktree-error {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n width: 100%;\n padding: 6px 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-recoveryActions {\n display: grid;\n gap: 6px;\n margin-top: 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton:disabled,\n.-cerbur-clutch-dsh-worktree-actionButton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.-cerbur-clutch-dsh-worktree-actions {\n display: grid;\n gap: 6px;\n margin-top: 10px;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n display: grid;\n gap: 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionSelect {\n min-width: 0;\n padding: 5px 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-section {\n margin: 12px 0 0;\n}\n\n.-cerbur-clutch-dsh-worktree-sectionTitle {\n margin: 0 2px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-empty,\n.-cerbur-clutch-dsh-worktree-message {\n margin: 0;\n padding: 8px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-message[data-error='true'] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktree,\n.-cerbur-clutch-dsh-worktree-session {\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 6px 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree {\n cursor: default;\n}\n\n.-cerbur-clutch-dsh-worktree-session {\n cursor: pointer;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree:hover,\n.-cerbur-clutch-dsh-worktree-session:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeLabel,\n.-cerbur-clutch-dsh-worktree-sessionLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-status {\n flex: none;\n margin-left: auto;\n padding-left: 8px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchRow {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchIcon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n min-width: 0;\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n outline: none;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n width: 100%;\n padding: 6px 8px;\n font-size: 13px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput:focus,\n.-cerbur-clutch-dsh-worktree-actionSelect:focus {\n border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n margin-right: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 24px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeGuide {\n flex: none;\n width: 20px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
|
|
369
|
+
const css = ".-cerbur-clutch-dsh-worktree-action {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n width: calc(100% + 4px);\n height: 42px;\n margin: 4px -2px;\n box-sizing: border-box;\n border: 0;\n border-radius: 12px;\n padding: 0 10px 0 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n text-align: left;\n overflow: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-action:hover,\n.-cerbur-clutch-dsh-worktree-action[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-action[data-collapsed='true'] {\n width: 36px;\n height: 36px;\n margin: 8px 0 10px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border-radius: 50%;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n overflow: hidden;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-surface {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n min-width: 56px;\n overflow: hidden;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-specific-sidebar-fill);\n color: var(--dsw-alias-label-primary);\n pointer-events: auto;\n transition: width var(--ds-transition-duration-slow) var(--ds-ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .-cerbur-clutch-dsh-worktree-surface {\n transition: none;\n }\n}\n\n.-cerbur-clutch-dsh-worktree-wideContent {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-wideContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-railContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-railContent {\n display: flex;\n flex: 1;\n align-items: flex-start;\n justify-content: center;\n padding-top: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton,\n.-cerbur-clutch-dsh-worktree-closeButton {\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton {\n width: 36px;\n height: 36px;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton:hover,\n.-cerbur-clutch-dsh-worktree-closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: none;\n min-height: 44px;\n padding: 6px 10px;\n box-sizing: border-box;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-title {\n min-width: 0;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n flex: none;\n width: 28px;\n height: 28px;\n font-size: 18px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-modeButton[data-active='true'] {\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspacePicker {\n display: block;\n width: calc(100% - 20px);\n margin: 6px 10px 8px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceLabel {\n display: block;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n padding: 0 10px 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-content:focus-visible {\n outline: 2px solid var(--dsw-alias-border-l3);\n outline-offset: -2px;\n}\n\n.-cerbur-clutch-dsh-worktree-error {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n width: 100%;\n padding: 6px 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-recoveryActions {\n display: grid;\n gap: 6px;\n margin-top: 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton:disabled,\n.-cerbur-clutch-dsh-worktree-actionButton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.-cerbur-clutch-dsh-worktree-actions {\n display: grid;\n gap: 6px;\n margin-top: 10px;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n display: grid;\n gap: 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionSelect {\n min-width: 0;\n padding: 5px 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-section {\n margin: 12px 0 0;\n}\n\n.-cerbur-clutch-dsh-worktree-sectionTitle {\n margin: 0 2px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-empty,\n.-cerbur-clutch-dsh-worktree-message {\n margin: 0;\n padding: 8px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-gitReadiness {\n display: grid;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-commandBlock {\n margin: 6px 0 0;\n padding: 8px;\n overflow-x: auto;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-secondary);\n font: 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace;\n white-space: pre-wrap;\n}\n\n.-cerbur-clutch-dsh-worktree-message[data-error='true'] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktree,\n.-cerbur-clutch-dsh-worktree-session {\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 6px 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree {\n cursor: default;\n}\n\n.-cerbur-clutch-dsh-worktree-session {\n cursor: pointer;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree:hover,\n.-cerbur-clutch-dsh-worktree-session:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeLabel,\n.-cerbur-clutch-dsh-worktree-sessionLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-status {\n flex: none;\n margin-left: auto;\n padding-left: 8px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchRow {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchIcon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n min-width: 0;\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n outline: none;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n width: 100%;\n padding: 6px 8px;\n font-size: 13px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput:focus,\n.-cerbur-clutch-dsh-worktree-actionSelect:focus {\n border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 24px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeGuide {\n flex: none;\n width: 20px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
|
|
291
370
|
const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
|
|
292
371
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
|
|
293
372
|
const tag = document.createElement("style");
|
|
@@ -320,6 +399,8 @@ window.__ModuleLoader__.load({
|
|
|
320
399
|
"sectionTitle": "-cerbur-clutch-dsh-worktree-sectionTitle",
|
|
321
400
|
"empty": "-cerbur-clutch-dsh-worktree-empty",
|
|
322
401
|
"message": "-cerbur-clutch-dsh-worktree-message",
|
|
402
|
+
"gitReadiness": "-cerbur-clutch-dsh-worktree-gitReadiness",
|
|
403
|
+
"commandBlock": "-cerbur-clutch-dsh-worktree-commandBlock",
|
|
323
404
|
"worktree": "-cerbur-clutch-dsh-worktree-worktree",
|
|
324
405
|
"session": "-cerbur-clutch-dsh-worktree-session",
|
|
325
406
|
"worktreeLabel": "-cerbur-clutch-dsh-worktree-worktreeLabel",
|
|
@@ -340,6 +421,7 @@ window.__ModuleLoader__.load({
|
|
|
340
421
|
"disclosureButton": "-cerbur-clutch-dsh-worktree-disclosureButton",
|
|
341
422
|
"worktreeState": "-cerbur-clutch-dsh-worktree-worktreeState",
|
|
342
423
|
"workspaceTitle": "-cerbur-clutch-dsh-worktree-workspaceTitle",
|
|
424
|
+
"worktreeHoverTitle": "-cerbur-clutch-dsh-worktree-worktreeHoverTitle",
|
|
343
425
|
"treeActionSlot": "-cerbur-clutch-dsh-worktree-treeActionSlot",
|
|
344
426
|
"workspaceActions": "-cerbur-clutch-dsh-worktree-workspaceActions",
|
|
345
427
|
"menuAction": "-cerbur-clutch-dsh-worktree-menuAction",
|
|
@@ -384,6 +466,104 @@ window.__ModuleLoader__.load({
|
|
|
384
466
|
});
|
|
385
467
|
}
|
|
386
468
|
//#endregion
|
|
469
|
+
//#region lib/client/WorktreeHeroContext.js
|
|
470
|
+
function labelFor(state) {
|
|
471
|
+
if (state.status !== "ready" || state.workspaceTitle === void 0 || state.value.kind === "none") return;
|
|
472
|
+
return `${state.workspaceTitle} (${state.value.label})`;
|
|
473
|
+
}
|
|
474
|
+
function elementWithClassSuffix(root, suffix) {
|
|
475
|
+
const candidates = root.querySelectorAll("[class]");
|
|
476
|
+
for (const candidate of candidates) if ([...candidate.classList].some((token) => token === suffix || token.endsWith(`_${suffix}`))) return candidate;
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
function headlineElement(root) {
|
|
480
|
+
return elementWithClassSuffix(root, "previewBadge") ?? elementWithClassSuffix(root, "headlineText") ?? elementWithClassSuffix(root, "headline");
|
|
481
|
+
}
|
|
482
|
+
function positionedAncestor(element) {
|
|
483
|
+
if (element.offsetParent instanceof HTMLElement) return element.offsetParent;
|
|
484
|
+
for (let ancestor = element.parentElement; ancestor !== null; ancestor = ancestor.parentElement) if (getComputedStyle(ancestor).position !== "static") return ancestor;
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
function measurePlacement(element) {
|
|
488
|
+
const hero = document.querySelector("[data-phase=\"hero\"]");
|
|
489
|
+
const overlay = positionedAncestor(element);
|
|
490
|
+
const headline = hero === null ? null : headlineElement(hero);
|
|
491
|
+
if (hero === null || headline === null || overlay === null) return null;
|
|
492
|
+
const anchor = headline.getBoundingClientRect();
|
|
493
|
+
const frame = overlay.getBoundingClientRect();
|
|
494
|
+
const width = element.getBoundingClientRect().width;
|
|
495
|
+
const afterHeadlineLeft = anchor.right - frame.left + 8;
|
|
496
|
+
const fitsAfterHeadline = afterHeadlineLeft + width <= frame.width - 8;
|
|
497
|
+
return {
|
|
498
|
+
left: fitsAfterHeadline ? afterHeadlineLeft : Math.max(8, frame.width - width - 8),
|
|
499
|
+
top: fitsAfterHeadline ? Math.max(8, anchor.top - frame.top + (anchor.height - 22) / 2) : Math.max(8, anchor.bottom - frame.top + 8)
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function contextAriaLabel(state, t) {
|
|
503
|
+
if (state.value.kind === "main") return t("context.main", { name: state.value.label });
|
|
504
|
+
if (state.value.kind === "worktree") return t("context.worktree", { name: state.value.label });
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Browser-local Hero suffix. It intentionally uses the frame overlay because
|
|
508
|
+
* rc.8 exposes no additive slot beside the native Hero headline.
|
|
509
|
+
*/
|
|
510
|
+
function WorktreeHeroContext({ useWorktreeContext, t }) {
|
|
511
|
+
const state = useWorktreeContext((snapshot) => snapshot);
|
|
512
|
+
const label = labelFor(state);
|
|
513
|
+
const [placement, setPlacement] = (0, react.useState)(null);
|
|
514
|
+
const measure = (0, react.useCallback)((element) => {
|
|
515
|
+
if (element === null) {
|
|
516
|
+
setPlacement(null);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
setPlacement(measurePlacement(element));
|
|
520
|
+
}, []);
|
|
521
|
+
(0, react.useLayoutEffect)(() => {
|
|
522
|
+
if (typeof document === "undefined" || typeof window === "undefined") return void 0;
|
|
523
|
+
const element = document.querySelector("[data-worktree-hero-context]");
|
|
524
|
+
if (element === null) return void 0;
|
|
525
|
+
let frameRequest;
|
|
526
|
+
const schedule = () => {
|
|
527
|
+
if (frameRequest !== void 0) window.cancelAnimationFrame(frameRequest);
|
|
528
|
+
frameRequest = window.requestAnimationFrame(() => {
|
|
529
|
+
frameRequest = void 0;
|
|
530
|
+
measure(element);
|
|
531
|
+
});
|
|
532
|
+
};
|
|
533
|
+
const mutationObserver = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(schedule);
|
|
534
|
+
mutationObserver?.observe(document.body, {
|
|
535
|
+
subtree: true,
|
|
536
|
+
childList: true,
|
|
537
|
+
attributes: true,
|
|
538
|
+
attributeFilter: ["class", "data-phase"]
|
|
539
|
+
});
|
|
540
|
+
const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(schedule);
|
|
541
|
+
resizeObserver?.observe(positionedAncestor(element) ?? element);
|
|
542
|
+
window.addEventListener("resize", schedule);
|
|
543
|
+
schedule();
|
|
544
|
+
return () => {
|
|
545
|
+
if (frameRequest !== void 0) window.cancelAnimationFrame(frameRequest);
|
|
546
|
+
mutationObserver?.disconnect();
|
|
547
|
+
resizeObserver?.disconnect();
|
|
548
|
+
window.removeEventListener("resize", schedule);
|
|
549
|
+
};
|
|
550
|
+
}, [label, measure]);
|
|
551
|
+
const ariaLabel = contextAriaLabel(state, t);
|
|
552
|
+
if (label === void 0) return null;
|
|
553
|
+
return (0, react_jsx_runtime.jsx)("span", {
|
|
554
|
+
ref: measure,
|
|
555
|
+
className: worktree_context_css_default.heroContext,
|
|
556
|
+
"data-worktree-hero-context": true,
|
|
557
|
+
"aria-label": ariaLabel,
|
|
558
|
+
title: label,
|
|
559
|
+
style: placement === null ? { visibility: "hidden" } : {
|
|
560
|
+
left: `${placement.left}px`,
|
|
561
|
+
top: `${placement.top}px`
|
|
562
|
+
},
|
|
563
|
+
children: label
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
//#endregion
|
|
387
567
|
//#region lib/client/navigation.js
|
|
388
568
|
/** Open an existing Session through DSH without touching the peer view mode. */
|
|
389
569
|
function openWorktreeSession(opener, sessionId) {
|
|
@@ -418,6 +598,13 @@ window.__ModuleLoader__.load({
|
|
|
418
598
|
bottom: rect.bottom
|
|
419
599
|
};
|
|
420
600
|
}
|
|
601
|
+
function syncObservedElement(observer, previous, next) {
|
|
602
|
+
const nextElement = next ?? void 0;
|
|
603
|
+
if (previous === nextElement) return previous;
|
|
604
|
+
if (previous !== void 0) observer?.unobserve(previous);
|
|
605
|
+
if (nextElement !== void 0) observer?.observe(nextElement);
|
|
606
|
+
return nextElement;
|
|
607
|
+
}
|
|
421
608
|
function resolveNativeSidebarRoot(sidebar) {
|
|
422
609
|
const directChild = sidebar.firstElementChild;
|
|
423
610
|
if (directChild === null) return void 0;
|
|
@@ -459,34 +646,37 @@ window.__ModuleLoader__.load({
|
|
|
459
646
|
setBounds(EMPTY_BOUNDS);
|
|
460
647
|
return;
|
|
461
648
|
}
|
|
649
|
+
const overlayElement = overlay;
|
|
650
|
+
const sidebarElement = sidebar;
|
|
651
|
+
const nativeRootElement = nativeRoot;
|
|
462
652
|
let frameHandle;
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const
|
|
653
|
+
let observedNewSession;
|
|
654
|
+
let observedFooter;
|
|
655
|
+
function update() {
|
|
656
|
+
const newSession = findNewSessionAnchor(nativeRootElement);
|
|
657
|
+
const footer = nativeRootElement.lastElementChild;
|
|
658
|
+
observedNewSession = syncObservedElement(resizeObserver, observedNewSession, newSession);
|
|
659
|
+
observedFooter = syncObservedElement(resizeObserver, observedFooter, footer);
|
|
660
|
+
const nextWidth = sidebarElement.getBoundingClientRect().width;
|
|
467
661
|
if (nextWidth > 0) setWidth(nextWidth);
|
|
468
|
-
setBounds(computeOverlayBounds(asRect(
|
|
469
|
-
}
|
|
470
|
-
|
|
662
|
+
setBounds(computeOverlayBounds(asRect(overlayElement), newSession === void 0 ? void 0 : asRect(newSession), footer === null ? void 0 : asRect(footer)));
|
|
663
|
+
}
|
|
664
|
+
function scheduleUpdate() {
|
|
471
665
|
if (frameHandle !== void 0) return;
|
|
472
666
|
frameHandle = requestAnimationFrame(() => {
|
|
473
667
|
frameHandle = void 0;
|
|
474
668
|
update();
|
|
475
669
|
});
|
|
476
|
-
}
|
|
477
|
-
update();
|
|
670
|
+
}
|
|
478
671
|
const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(scheduleUpdate) : void 0;
|
|
479
672
|
for (const element of [
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
673
|
+
overlayElement,
|
|
674
|
+
sidebarElement,
|
|
675
|
+
nativeRootElement
|
|
483
676
|
]) resizeObserver?.observe(element);
|
|
484
|
-
|
|
485
|
-
const footer = nativeRoot.lastElementChild;
|
|
486
|
-
if (newSession !== void 0) resizeObserver?.observe(newSession);
|
|
487
|
-
if (footer !== null) resizeObserver?.observe(footer);
|
|
677
|
+
update();
|
|
488
678
|
const mutationObserver = typeof MutationObserver === "function" ? new MutationObserver(scheduleUpdate) : void 0;
|
|
489
|
-
mutationObserver?.observe(
|
|
679
|
+
mutationObserver?.observe(nativeRootElement, {
|
|
490
680
|
childList: true,
|
|
491
681
|
subtree: true
|
|
492
682
|
});
|
|
@@ -575,6 +765,7 @@ window.__ModuleLoader__.load({
|
|
|
575
765
|
case "WORKTREE_RPC_INVALID_RESULT": return t("error.invalidResult", { endpoint: detail(error, "endpoint") });
|
|
576
766
|
case "WORKSPACE_ORDER_UNAVAILABLE": return t("error.workspaceOrderingUnavailable");
|
|
577
767
|
case "SESSION_ORDER_UNAVAILABLE": return t("error.sessionOrderingUnavailable");
|
|
768
|
+
case "WORKTREE_ORDER_UNAVAILABLE": return t("error.worktreeOrderingUnavailable");
|
|
578
769
|
case "SESSION_CREATE_UNAVAILABLE": return t("error.sessionCreationUnavailable");
|
|
579
770
|
case "WORKTREE_CREATED_SESSION_UNAVAILABLE": return t("error.worktreeCreatedSessionUnavailable");
|
|
580
771
|
case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
|
|
@@ -585,21 +776,58 @@ window.__ModuleLoader__.load({
|
|
|
585
776
|
sessionId: detail(error, "sessionId"),
|
|
586
777
|
reason: reason(error, t)
|
|
587
778
|
});
|
|
779
|
+
case "SESSION_ALREADY_BOUND": return t("error.sessionAlreadyBound");
|
|
780
|
+
case "SESSION_LIST_NOT_READY": return t("error.sessionListNotReady");
|
|
781
|
+
case "SESSION_FACTS_INCOMPLETE": return t("error.sessionFactsIncomplete");
|
|
782
|
+
case "WORKTREE_SESSION_REPAIR_REQUIRED": return t("error.worktreeSessionRepairRequired");
|
|
783
|
+
case "WORKTREE_SESSION_UNAVAILABLE": return t("error.worktreeSessionUnavailable");
|
|
784
|
+
case "SESSION_ARCHIVED": return t("error.sessionArchived");
|
|
588
785
|
default: return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
|
|
589
786
|
}
|
|
590
787
|
}
|
|
591
788
|
//#endregion
|
|
789
|
+
//#region lib/client/session-view.js
|
|
790
|
+
/** Read the native blank flag without inferring blankness from title or id. */
|
|
791
|
+
function isBlankSession(sessionId, sessions) {
|
|
792
|
+
return sessions.byId[sessionId]?.blank === true;
|
|
793
|
+
}
|
|
794
|
+
/** Native tree visibility: ordinary rows plus the currently selected blank row. */
|
|
795
|
+
function isVisibleSession(sessionId, sessions) {
|
|
796
|
+
return !isBlankSession(sessionId, sessions) || sessions.current === sessionId;
|
|
797
|
+
}
|
|
798
|
+
/** Filter a group without mutating its source order. */
|
|
799
|
+
function filterVisibleSessionIds(sessionIds, sessions) {
|
|
800
|
+
return sessionIds.filter((sessionId) => isVisibleSession(sessionId, sessions));
|
|
801
|
+
}
|
|
802
|
+
/** Resolve a row title while keeping the blank label outside the DSH summary. */
|
|
803
|
+
function sessionDisplayLabel(sessionId, sessions, blankLabel) {
|
|
804
|
+
const summary = sessions.byId[sessionId];
|
|
805
|
+
return summary?.blank === true ? blankLabel : summary?.displayTitle ?? sessionId;
|
|
806
|
+
}
|
|
807
|
+
/** Match only durable Session titles or the final diagnostic id fallback. */
|
|
808
|
+
function sessionMatchesQuery(sessionId, sessions, normalizedQuery) {
|
|
809
|
+
const summary = sessions.byId[sessionId];
|
|
810
|
+
if (summary?.blank === true) return false;
|
|
811
|
+
return (summary?.displayTitle ?? sessionId).toLocaleLowerCase().includes(normalizedQuery);
|
|
812
|
+
}
|
|
813
|
+
//#endregion
|
|
592
814
|
//#region lib/client/worktree-view.js
|
|
593
815
|
/** A DSH Session exists even when the external Worktree binding needs repair. */
|
|
594
816
|
var WorktreeSessionBindingError = class extends Error {
|
|
595
|
-
code
|
|
596
|
-
retryable
|
|
817
|
+
code;
|
|
818
|
+
retryable;
|
|
819
|
+
details;
|
|
597
820
|
sessionId;
|
|
598
821
|
cause;
|
|
599
822
|
constructor(sessionId, cause) {
|
|
600
|
-
const
|
|
823
|
+
const candidate = typeof cause === "object" && cause !== null ? cause : void 0;
|
|
824
|
+
const reason = cause instanceof Error ? cause.message : typeof candidate?.message === "string" ? candidate.message : String(cause);
|
|
601
825
|
super(reason);
|
|
602
826
|
this.name = "WorktreeSessionBindingError";
|
|
827
|
+
const conflict = candidate?.code === "SESSION_ALREADY_BOUND";
|
|
828
|
+
this.code = conflict ? "SESSION_ALREADY_BOUND" : "SESSION_BINDING_FAILED";
|
|
829
|
+
this.retryable = conflict ? false : candidate?.retryable !== false;
|
|
830
|
+
this.details = typeof candidate?.details === "object" && candidate.details !== null && !Array.isArray(candidate.details) ? candidate.details : {};
|
|
603
831
|
this.sessionId = sessionId;
|
|
604
832
|
this.cause = cause;
|
|
605
833
|
}
|
|
@@ -610,10 +838,63 @@ window.__ModuleLoader__.load({
|
|
|
610
838
|
for (let index = 0; index < previous.length; index += 1) if (previous[index] !== next[index]) return next;
|
|
611
839
|
return previous;
|
|
612
840
|
}
|
|
841
|
+
/** Keep only the most recently started Worktree surface refresh authoritative. */
|
|
842
|
+
function createWorktreeRefreshGuard() {
|
|
843
|
+
let latestGeneration = 0;
|
|
844
|
+
const begin = () => {
|
|
845
|
+
latestGeneration += 1;
|
|
846
|
+
return latestGeneration;
|
|
847
|
+
};
|
|
848
|
+
const isCurrent = (generation) => generation === latestGeneration;
|
|
849
|
+
const invalidate = () => {
|
|
850
|
+
latestGeneration += 1;
|
|
851
|
+
};
|
|
852
|
+
return {
|
|
853
|
+
begin,
|
|
854
|
+
isCurrent,
|
|
855
|
+
invalidate,
|
|
856
|
+
async run(load, onSuccess, onError) {
|
|
857
|
+
const generation = begin();
|
|
858
|
+
let value;
|
|
859
|
+
try {
|
|
860
|
+
value = await load();
|
|
861
|
+
} catch (error) {
|
|
862
|
+
if (!isCurrent(generation)) return;
|
|
863
|
+
onError(error);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (!isCurrent(generation)) return;
|
|
867
|
+
onSuccess(value);
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
}
|
|
613
871
|
/** Prefer the branch checked out by the DSH Workspace, then fall back to any local branch. */
|
|
614
872
|
function selectDefaultBaseBranch(branches) {
|
|
615
873
|
return branches.find((branch) => branch.isCurrent)?.name ?? branches[0]?.name ?? "";
|
|
616
874
|
}
|
|
875
|
+
/** Keep a valid user choice across branch-list refreshes, otherwise choose the current branch. */
|
|
876
|
+
function reconcileBaseBranchSelection(selectedBranch, branches) {
|
|
877
|
+
if (branches.some((branch) => branch.name === selectedBranch)) return selectedBranch;
|
|
878
|
+
return selectDefaultBaseBranch(branches);
|
|
879
|
+
}
|
|
880
|
+
/** Return copyable, read-only setup commands for a Git readiness state. */
|
|
881
|
+
function worktreeSetupCommands(status) {
|
|
882
|
+
switch (status) {
|
|
883
|
+
case "noRepository": return [
|
|
884
|
+
"git init",
|
|
885
|
+
"printf \"# README\\n\" > README.md",
|
|
886
|
+
"git add README.md",
|
|
887
|
+
"git commit -m \"Initial commit\""
|
|
888
|
+
];
|
|
889
|
+
case "noInitialCommit": return [
|
|
890
|
+
"printf \"# README\\n\" > README.md",
|
|
891
|
+
"git add README.md",
|
|
892
|
+
"git commit -m \"Initial commit\""
|
|
893
|
+
];
|
|
894
|
+
case "noLocalBranch": return ["git switch -c main"];
|
|
895
|
+
case "ready": return [];
|
|
896
|
+
}
|
|
897
|
+
}
|
|
617
898
|
function browserRandomUuid() {
|
|
618
899
|
const randomUUID = globalThis.crypto?.randomUUID;
|
|
619
900
|
if (typeof randomUUID === "function") return randomUUID.call(globalThis.crypto);
|
|
@@ -634,25 +915,62 @@ window.__ModuleLoader__.load({
|
|
|
634
915
|
function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
|
|
635
916
|
return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
|
|
636
917
|
}
|
|
918
|
+
function readinessFromBranchError(error) {
|
|
919
|
+
const viewError = toWorktreeViewError(error);
|
|
920
|
+
if (viewError.code === "WORKSPACE_NOT_GIT_REPOSITORY") return {
|
|
921
|
+
status: "noRepository",
|
|
922
|
+
error: viewError
|
|
923
|
+
};
|
|
924
|
+
if (viewError.code === "WORKTREE_REQUIRES_INITIAL_COMMIT") return {
|
|
925
|
+
status: "noInitialCommit",
|
|
926
|
+
error: viewError
|
|
927
|
+
};
|
|
928
|
+
}
|
|
637
929
|
/** Read all three Worktree projections needed by the surface in one refresh. */
|
|
638
930
|
async function loadWorktreeView(manager, workspaceId) {
|
|
639
|
-
const [
|
|
931
|
+
const [worktreesResult, branchesResult, bindingsResult] = await Promise.allSettled([
|
|
640
932
|
manager.listWorktrees({ workspaceId }),
|
|
641
933
|
manager.listBranches({ workspaceId }),
|
|
642
934
|
manager.listBindings({ workspaceId })
|
|
643
935
|
]);
|
|
936
|
+
if (worktreesResult.status === "rejected") throw worktreesResult.reason;
|
|
937
|
+
if (bindingsResult.status === "rejected") throw bindingsResult.reason;
|
|
938
|
+
if (branchesResult.status === "rejected") {
|
|
939
|
+
const readiness = readinessFromBranchError(branchesResult.reason);
|
|
940
|
+
if (readiness !== void 0) return {
|
|
941
|
+
worktrees: worktreesResult.value,
|
|
942
|
+
branches: [],
|
|
943
|
+
bindings: bindingsResult.value,
|
|
944
|
+
readiness
|
|
945
|
+
};
|
|
946
|
+
throw branchesResult.reason;
|
|
947
|
+
}
|
|
644
948
|
return {
|
|
645
|
-
worktrees,
|
|
646
|
-
branches,
|
|
647
|
-
bindings
|
|
949
|
+
worktrees: worktreesResult.value,
|
|
950
|
+
branches: branchesResult.value,
|
|
951
|
+
bindings: bindingsResult.value,
|
|
952
|
+
readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
|
|
648
953
|
};
|
|
649
954
|
}
|
|
650
955
|
/** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
|
|
651
|
-
async function loadWorktreeViews(manager, workspaceIds) {
|
|
652
|
-
|
|
956
|
+
async function loadWorktreeViews(manager, workspaceIds, options = {}) {
|
|
957
|
+
const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
|
|
653
958
|
workspaceId,
|
|
654
959
|
...await loadWorktreeView(manager, workspaceId)
|
|
655
960
|
})));
|
|
961
|
+
if (options.invalidateContext !== false) await options.invalidateWorktreeContext?.();
|
|
962
|
+
return views;
|
|
963
|
+
}
|
|
964
|
+
/** Resolve a row-half drop target to native-style optional before-anchor semantics. */
|
|
965
|
+
function resolveWorktreeMove(worktreeIds, sourceWorktreeId, targetWorktreeId, half) {
|
|
966
|
+
const sourceIndex = worktreeIds.indexOf(sourceWorktreeId);
|
|
967
|
+
const targetIndex = worktreeIds.indexOf(targetWorktreeId);
|
|
968
|
+
if (sourceIndex === -1 || targetIndex === -1) return void 0;
|
|
969
|
+
const beforeWorktreeId = half === "before" ? targetWorktreeId : worktreeIds[targetIndex + 1];
|
|
970
|
+
if (beforeWorktreeId === sourceWorktreeId) return void 0;
|
|
971
|
+
const anchorIndex = beforeWorktreeId === void 0 ? worktreeIds.length : worktreeIds.indexOf(beforeWorktreeId);
|
|
972
|
+
if (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1) return void 0;
|
|
973
|
+
return beforeWorktreeId === void 0 ? {} : { beforeWorktreeId };
|
|
656
974
|
}
|
|
657
975
|
/** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
|
|
658
976
|
async function executeWorktreeAction(manager, action) {
|
|
@@ -708,8 +1026,174 @@ window.__ModuleLoader__.load({
|
|
|
708
1026
|
retryable: true
|
|
709
1027
|
};
|
|
710
1028
|
}
|
|
1029
|
+
/** Keep ordering mutation/refresh failures reachable from the surface Retry control. */
|
|
1030
|
+
function toRetryableWorktreeOrderError(error) {
|
|
1031
|
+
return {
|
|
1032
|
+
...toWorktreeViewError(error),
|
|
1033
|
+
retryable: true
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
//#endregion
|
|
1037
|
+
//#region lib/client/worktree-session.js
|
|
1038
|
+
var WorktreeSessionActionError = class extends Error {
|
|
1039
|
+
code;
|
|
1040
|
+
retryable;
|
|
1041
|
+
details;
|
|
1042
|
+
constructor(code, message, retryable, details = {}) {
|
|
1043
|
+
super(message);
|
|
1044
|
+
this.code = code;
|
|
1045
|
+
this.retryable = retryable;
|
|
1046
|
+
this.name = "WorktreeSessionActionError";
|
|
1047
|
+
this.details = details;
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
function resolveWorktreeSessionAction(input) {
|
|
1051
|
+
if (input.target.status !== "active" || input.target.health === "repair") return {
|
|
1052
|
+
kind: "reject",
|
|
1053
|
+
reason: "worktree-not-available"
|
|
1054
|
+
};
|
|
1055
|
+
if (input.sessions.phase !== "ready") return {
|
|
1056
|
+
kind: "wait",
|
|
1057
|
+
reason: "sessions-not-ready"
|
|
1058
|
+
};
|
|
1059
|
+
const targetBinding = input.bindings.find((binding) => binding.worktreeId === input.target.worktreeId && binding.status === "active");
|
|
1060
|
+
if (targetBinding !== void 0) {
|
|
1061
|
+
const summary = input.sessions.byId[targetBinding.sessionId];
|
|
1062
|
+
if (summary === void 0) return {
|
|
1063
|
+
kind: "repair",
|
|
1064
|
+
reason: "active-binding-session-missing",
|
|
1065
|
+
sessionId: targetBinding.sessionId
|
|
1066
|
+
};
|
|
1067
|
+
if (summary.cwd !== input.target.absolutePath) return {
|
|
1068
|
+
kind: "repair",
|
|
1069
|
+
reason: "active-binding-cwd-mismatch",
|
|
1070
|
+
sessionId: targetBinding.sessionId
|
|
1071
|
+
};
|
|
1072
|
+
if (summary.blank === true && !input.archivedSessionIds.includes(targetBinding.sessionId)) return {
|
|
1073
|
+
kind: "open-bound",
|
|
1074
|
+
sessionId: targetBinding.sessionId
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
for (const sessionId of input.sessions.ids) {
|
|
1078
|
+
const summary = input.sessions.byId[sessionId];
|
|
1079
|
+
if (summary === void 0 || summary.blank === void 0 || summary.blank === true && summary.cwd === void 0) return {
|
|
1080
|
+
kind: "wait",
|
|
1081
|
+
reason: "session-facts-incomplete"
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
for (const sessionId of input.sessions.ids) {
|
|
1085
|
+
const summary = input.sessions.byId[sessionId];
|
|
1086
|
+
if (summary?.blank !== true || summary.cwd !== input.target.absolutePath || input.archivedSessionIds.includes(sessionId)) continue;
|
|
1087
|
+
if (!input.bindings.some((binding) => binding.sessionId === sessionId)) return {
|
|
1088
|
+
kind: "bind-existing",
|
|
1089
|
+
sessionId
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
return { kind: "create" };
|
|
1093
|
+
}
|
|
1094
|
+
function actionError(action) {
|
|
1095
|
+
switch (action.kind) {
|
|
1096
|
+
case "wait": return new WorktreeSessionActionError(action.reason === "sessions-not-ready" ? "SESSION_LIST_NOT_READY" : "SESSION_FACTS_INCOMPLETE", "", true);
|
|
1097
|
+
case "repair": return new WorktreeSessionActionError("WORKTREE_SESSION_REPAIR_REQUIRED", action.reason, true, { ...action.sessionId === void 0 ? {} : { sessionId: action.sessionId } });
|
|
1098
|
+
case "reject": return new WorktreeSessionActionError("WORKTREE_SESSION_UNAVAILABLE", action.reason, false);
|
|
1099
|
+
default: return new WorktreeSessionActionError("WORKTREE_SESSION_ACTION_FAILED", "", true);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
async function retryWorktreeSessionBinding(input) {
|
|
1103
|
+
if (input.archived) throw new WorktreeSessionActionError("SESSION_ARCHIVED", "", false, { sessionId: input.pending.sessionId });
|
|
1104
|
+
try {
|
|
1105
|
+
await input.manager.bindSession({
|
|
1106
|
+
workspaceId: input.pending.workspaceId,
|
|
1107
|
+
worktreeId: input.pending.worktreeId,
|
|
1108
|
+
sessionId: input.pending.sessionId
|
|
1109
|
+
});
|
|
1110
|
+
} catch (error) {
|
|
1111
|
+
throw new WorktreeSessionBindingError(input.pending.sessionId, error);
|
|
1112
|
+
}
|
|
1113
|
+
input.ensureSessionWorkspace(input.pending.workspaceId, input.pending.sessionId);
|
|
1114
|
+
input.openSession(input.pending.sessionId);
|
|
1115
|
+
return input.pending.sessionId;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Browser-only Worktree `+` connector. It owns the read/resolve/bind/create/open
|
|
1119
|
+
* sequence and coalesces repeated calls for one Worktree within one Client fiber.
|
|
1120
|
+
*/
|
|
1121
|
+
function createWorktreeSessionConnector(options) {
|
|
1122
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
1123
|
+
let disposed = false;
|
|
1124
|
+
const run = async (input) => {
|
|
1125
|
+
const [worktrees, bindings] = await Promise.all([options.manager.listWorktrees({ workspaceId: input.workspaceId }), options.manager.listBindings({ workspaceId: input.workspaceId })]);
|
|
1126
|
+
if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
|
|
1127
|
+
const target = worktrees.find((record) => record.worktreeId === input.worktreeId);
|
|
1128
|
+
if (target === void 0 || target.absolutePath !== input.cwd) throw new WorktreeSessionActionError("WORKTREE_SESSION_REPAIR_REQUIRED", "worktree target unavailable", true);
|
|
1129
|
+
const action = resolveWorktreeSessionAction({
|
|
1130
|
+
target,
|
|
1131
|
+
sessions: options.sessions.getSnapshot(),
|
|
1132
|
+
archivedSessionIds: options.archivedSessionIds(),
|
|
1133
|
+
bindings
|
|
1134
|
+
});
|
|
1135
|
+
if (action.kind === "open-bound") {
|
|
1136
|
+
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1137
|
+
if (!disposed) options.openSession(action.sessionId);
|
|
1138
|
+
return action.sessionId;
|
|
1139
|
+
}
|
|
1140
|
+
if (action.kind === "bind-existing") {
|
|
1141
|
+
try {
|
|
1142
|
+
await options.manager.bindSession({
|
|
1143
|
+
workspaceId: input.workspaceId,
|
|
1144
|
+
worktreeId: input.worktreeId,
|
|
1145
|
+
sessionId: action.sessionId
|
|
1146
|
+
});
|
|
1147
|
+
} catch (error) {
|
|
1148
|
+
throw new WorktreeSessionBindingError(action.sessionId, error);
|
|
1149
|
+
}
|
|
1150
|
+
if (!disposed) {
|
|
1151
|
+
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1152
|
+
if (!disposed) options.openSession(action.sessionId);
|
|
1153
|
+
}
|
|
1154
|
+
return action.sessionId;
|
|
1155
|
+
}
|
|
1156
|
+
if (action.kind !== "create") throw actionError(action);
|
|
1157
|
+
if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
|
|
1158
|
+
return createSessionForWorktree({
|
|
1159
|
+
...input,
|
|
1160
|
+
createSession: options.createSession,
|
|
1161
|
+
manager: options.manager,
|
|
1162
|
+
beforeOpen: (sessionId) => {
|
|
1163
|
+
if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
|
|
1164
|
+
options.ensureSessionWorkspace(input.workspaceId, sessionId);
|
|
1165
|
+
},
|
|
1166
|
+
openSession: (sessionId) => {
|
|
1167
|
+
if (!disposed) options.openSession(sessionId);
|
|
1168
|
+
}
|
|
1169
|
+
});
|
|
1170
|
+
};
|
|
1171
|
+
return {
|
|
1172
|
+
create(input) {
|
|
1173
|
+
const key = `${input.workspaceId}\u0000${input.worktreeId}`;
|
|
1174
|
+
const current = inFlight.get(key);
|
|
1175
|
+
if (current !== void 0) return current;
|
|
1176
|
+
const promise = run(input).finally(() => {
|
|
1177
|
+
if (inFlight.get(key) === promise) inFlight.delete(key);
|
|
1178
|
+
});
|
|
1179
|
+
inFlight.set(key, promise);
|
|
1180
|
+
return promise;
|
|
1181
|
+
},
|
|
1182
|
+
dispose() {
|
|
1183
|
+
disposed = true;
|
|
1184
|
+
inFlight.clear();
|
|
1185
|
+
}
|
|
1186
|
+
};
|
|
1187
|
+
}
|
|
711
1188
|
//#endregion
|
|
712
1189
|
//#region lib/client/WorktreeSurface.js
|
|
1190
|
+
function worktreeSetupMessage(status, t) {
|
|
1191
|
+
switch (status) {
|
|
1192
|
+
case "noRepository": return t("worktree.setup.noRepository");
|
|
1193
|
+
case "noInitialCommit": return t("worktree.setup.noInitialCommit");
|
|
1194
|
+
case "noLocalBranch": return t("worktree.setup.noLocalBranch");
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
713
1197
|
function toNativeWorktreeViewError(error) {
|
|
714
1198
|
const viewError = toWorktreeViewError(error);
|
|
715
1199
|
if (typeof error === "object" && error !== null) return viewError;
|
|
@@ -729,8 +1213,8 @@ window.__ModuleLoader__.load({
|
|
|
729
1213
|
if (stable !== previousRef.current) previousRef.current = stable;
|
|
730
1214
|
return previousRef.current;
|
|
731
1215
|
}
|
|
732
|
-
function sessionLabel(sessionId, sessions) {
|
|
733
|
-
return
|
|
1216
|
+
function sessionLabel(sessionId, sessions, t) {
|
|
1217
|
+
return sessionDisplayLabel(sessionId, sessions, t("session.new"));
|
|
734
1218
|
}
|
|
735
1219
|
function rowHalf(event) {
|
|
736
1220
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
@@ -745,10 +1229,10 @@ window.__ModuleLoader__.load({
|
|
|
745
1229
|
function workspaceMatches(workspace, view, sessions, query) {
|
|
746
1230
|
if (query.length === 0) return true;
|
|
747
1231
|
if (includesText(workspace.title, query)) return true;
|
|
748
|
-
if (workspace.sessionIds.some((sessionId) =>
|
|
1232
|
+
if (workspace.sessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return true;
|
|
749
1233
|
if (view === void 0) return false;
|
|
750
1234
|
if (view.worktrees.some((record) => includesText(record.branch, query) || includesText(record.absolutePath, query))) return true;
|
|
751
|
-
return view.bindings.some((binding) =>
|
|
1235
|
+
return view.bindings.some((binding) => sessionMatchesQuery(binding.sessionId, sessions, query));
|
|
752
1236
|
}
|
|
753
1237
|
/** Workspace row using the native DSH menu, fixed action column, and drag contract. */
|
|
754
1238
|
function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
|
|
@@ -856,13 +1340,36 @@ window.__ModuleLoader__.load({
|
|
|
856
1340
|
});
|
|
857
1341
|
}
|
|
858
1342
|
/** Shared Main/Worktree group row with parameterized icon, state, and actions. */
|
|
859
|
-
function WorktreeGroupRow({ t, kind, label, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu }) {
|
|
1343
|
+
function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
|
|
860
1344
|
const main = kind === "main";
|
|
861
|
-
|
|
862
|
-
|
|
1345
|
+
const markerClass = drag?.marker === "before" ? worktree_css_default.dropBefore : drag?.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
1346
|
+
const dragProps = drag === void 0 ? {} : {
|
|
1347
|
+
draggable: true,
|
|
1348
|
+
onDragStart: (event) => {
|
|
1349
|
+
event.dataTransfer.effectAllowed = "move";
|
|
1350
|
+
event.dataTransfer.setData("text/plain", worktreeId ?? label);
|
|
1351
|
+
drag.start();
|
|
1352
|
+
},
|
|
1353
|
+
onDragEnd: drag.end,
|
|
1354
|
+
onDragOver: (event) => {
|
|
1355
|
+
if (!drag.active) return;
|
|
1356
|
+
event.preventDefault();
|
|
1357
|
+
event.dataTransfer.dropEffect = "move";
|
|
1358
|
+
drag.hover(rowHalf(event));
|
|
1359
|
+
},
|
|
1360
|
+
onDrop: (event) => {
|
|
1361
|
+
if (!drag.active) return;
|
|
1362
|
+
event.preventDefault();
|
|
1363
|
+
drag.drop(rowHalf(event));
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
const row = (0, react_jsx_runtime.jsxs)("div", {
|
|
1367
|
+
className: `${worktree_css_default.worktreeRow} ${markerClass}`,
|
|
863
1368
|
"data-main-group": main ? "true" : void 0,
|
|
864
1369
|
"data-main-expanded": main ? String(expanded) : void 0,
|
|
865
1370
|
"data-menu-open": menu?.open ? "true" : void 0,
|
|
1371
|
+
"data-worktree-drag": drag?.active ? "active" : void 0,
|
|
1372
|
+
...dragProps,
|
|
866
1373
|
onClick: onToggle,
|
|
867
1374
|
children: [
|
|
868
1375
|
(0, react_jsx_runtime.jsx)("button", {
|
|
@@ -941,9 +1448,19 @@ window.__ModuleLoader__.load({
|
|
|
941
1448
|
})
|
|
942
1449
|
]
|
|
943
1450
|
});
|
|
1451
|
+
if (main) return row;
|
|
1452
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
1453
|
+
anchor: row,
|
|
1454
|
+
content: (0, react_jsx_runtime.jsx)("div", {
|
|
1455
|
+
className: worktree_css_default.worktreeHoverTitle,
|
|
1456
|
+
children: label
|
|
1457
|
+
}),
|
|
1458
|
+
openDelayMs: 500,
|
|
1459
|
+
disabled: menu?.open === true
|
|
1460
|
+
});
|
|
944
1461
|
}
|
|
945
1462
|
/** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
|
|
946
|
-
function WorktreeSessionRow({ t, sessionId, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
|
|
1463
|
+
function WorktreeSessionRow({ t, sessionId, blank, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
|
|
947
1464
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
948
1465
|
const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
949
1466
|
const sessionMenuItems = [
|
|
@@ -969,6 +1486,7 @@ window.__ModuleLoader__.load({
|
|
|
969
1486
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
970
1487
|
className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
|
|
971
1488
|
"data-session-id": sessionId,
|
|
1489
|
+
"data-session-blank": blank ? "true" : void 0,
|
|
972
1490
|
"data-session-drag": drag.active ? "active" : void 0,
|
|
973
1491
|
"data-menu-open": menuOpen || void 0,
|
|
974
1492
|
role: "treeitem",
|
|
@@ -1002,7 +1520,7 @@ window.__ModuleLoader__.load({
|
|
|
1002
1520
|
className: worktree_css_default.sessionLabel,
|
|
1003
1521
|
children: label
|
|
1004
1522
|
})]
|
|
1005
|
-
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1523
|
+
}), !blank && (0, react_jsx_runtime.jsx)("span", {
|
|
1006
1524
|
className: worktree_css_default.rowActions,
|
|
1007
1525
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1008
1526
|
open: menuOpen,
|
|
@@ -1039,7 +1557,8 @@ window.__ModuleLoader__.load({
|
|
|
1039
1557
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
|
|
1040
1558
|
t,
|
|
1041
1559
|
sessionId,
|
|
1042
|
-
|
|
1560
|
+
blank: isBlankSession(sessionId, sessions),
|
|
1561
|
+
label: sessionLabel(sessionId, sessions, t),
|
|
1043
1562
|
drag: {
|
|
1044
1563
|
active: sameGroupDrag,
|
|
1045
1564
|
marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
|
|
@@ -1081,12 +1600,14 @@ window.__ModuleLoader__.load({
|
|
|
1081
1600
|
* Peer Worktree navigation surface. It keeps the original DSH Workspace mode
|
|
1082
1601
|
* intact and renders a browser-local Workspace → Worktree → Session projection.
|
|
1083
1602
|
*/
|
|
1084
|
-
function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
|
|
1603
|
+
function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
|
|
1085
1604
|
const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
|
|
1086
1605
|
const sessions = useSessions((state) => state);
|
|
1087
1606
|
const workspaces = useWorkspaces((state) => state);
|
|
1088
1607
|
const workspaceIds = useStableWorkspaceIds(workspaces.items);
|
|
1089
1608
|
const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
|
|
1609
|
+
const readStateRef = (0, react.useRef)(readState);
|
|
1610
|
+
readStateRef.current = readState;
|
|
1090
1611
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
1091
1612
|
const [expandedWorkspaces, setExpandedWorkspaces] = (0, react.useState)({});
|
|
1092
1613
|
const [expandedMains, setExpandedMains] = (0, react.useState)({});
|
|
@@ -1116,36 +1637,52 @@ window.__ModuleLoader__.load({
|
|
|
1116
1637
|
const [sessionDrag, setSessionDrag] = (0, react.useState)();
|
|
1117
1638
|
const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)({});
|
|
1118
1639
|
const sessionDropCommitted = (0, react.useRef)(false);
|
|
1640
|
+
const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
|
|
1641
|
+
const worktreeDropCommitted = (0, react.useRef)(false);
|
|
1642
|
+
const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
|
|
1119
1643
|
const { ref, width, bounds } = useSidebarOverlayGeometry(mode === "worktree");
|
|
1120
1644
|
const collapsed = width <= 64;
|
|
1121
1645
|
const query = searchQuery.trim().toLocaleLowerCase();
|
|
1122
1646
|
const archivedSessionIds = workspaces.archivedSessionIds ?? [];
|
|
1123
|
-
const
|
|
1647
|
+
const pendingSessionArchived = pendingSessionBinding !== void 0 && archivedSessionIds.includes(pendingSessionBinding.sessionId);
|
|
1648
|
+
const refresh = (0, react.useCallback)(async (options = {}) => {
|
|
1124
1649
|
if (manager === void 0) {
|
|
1650
|
+
refreshGuard.current.invalidate();
|
|
1125
1651
|
setReadState(EMPTY_READ_STATE);
|
|
1126
1652
|
return;
|
|
1127
1653
|
}
|
|
1128
|
-
|
|
1654
|
+
const preserveCurrent = options.preserveCurrent === true;
|
|
1655
|
+
if (!preserveCurrent) setReadState({
|
|
1129
1656
|
status: "loading",
|
|
1130
1657
|
views: []
|
|
1131
1658
|
});
|
|
1132
|
-
|
|
1133
|
-
|
|
1659
|
+
await refreshGuard.current.run(() => loadWorktreeViews(manager, workspaceIds, {
|
|
1660
|
+
invalidateContext: options.invalidateContext !== false,
|
|
1661
|
+
invalidateWorktreeContext
|
|
1662
|
+
}), (views) => {
|
|
1134
1663
|
setReadState({
|
|
1135
1664
|
status: "ready",
|
|
1136
1665
|
views
|
|
1137
1666
|
});
|
|
1138
|
-
}
|
|
1667
|
+
}, (error) => {
|
|
1668
|
+
if (preserveCurrent) throw error;
|
|
1139
1669
|
setReadState({
|
|
1140
1670
|
status: "error",
|
|
1141
1671
|
views: [],
|
|
1142
1672
|
error: toWorktreeViewError(error)
|
|
1143
1673
|
});
|
|
1144
|
-
}
|
|
1145
|
-
}, [
|
|
1674
|
+
});
|
|
1675
|
+
}, [
|
|
1676
|
+
invalidateWorktreeContext,
|
|
1677
|
+
manager,
|
|
1678
|
+
workspaceIds
|
|
1679
|
+
]);
|
|
1146
1680
|
(0, react.useEffect)(() => {
|
|
1147
|
-
if (mode === "worktree") refresh();
|
|
1148
|
-
else
|
|
1681
|
+
if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
|
|
1682
|
+
else {
|
|
1683
|
+
refreshGuard.current.invalidate();
|
|
1684
|
+
setReadState(EMPTY_READ_STATE);
|
|
1685
|
+
}
|
|
1149
1686
|
}, [mode, refresh]);
|
|
1150
1687
|
(0, react.useEffect)(() => {
|
|
1151
1688
|
if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
|
|
@@ -1161,12 +1698,23 @@ window.__ModuleLoader__.load({
|
|
|
1161
1698
|
const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
|
|
1162
1699
|
const modalWorkspace = workspaces.items.find((workspace) => workspace.workspaceId === worktreeModalWorkspaceId);
|
|
1163
1700
|
const modalView = worktreeModalWorkspaceId === void 0 ? void 0 : viewByWorkspace.get(worktreeModalWorkspaceId);
|
|
1701
|
+
const modalReadiness = modalView?.readiness;
|
|
1702
|
+
const modalSetupStatus = modalView === void 0 ? void 0 : modalReadiness?.status === "ready" ? modalView.branches.length === 0 ? "noLocalBranch" : void 0 : modalReadiness?.status;
|
|
1703
|
+
const modalCanCreate = modalSetupStatus === void 0 && modalReadiness?.status === "ready";
|
|
1704
|
+
(0, react.useEffect)(() => {
|
|
1705
|
+
if (worktreeModalWorkspaceId === void 0 || modalView === void 0) return;
|
|
1706
|
+
if (modalView.readiness.status !== "ready") {
|
|
1707
|
+
setSelectedBranch("");
|
|
1708
|
+
return;
|
|
1709
|
+
}
|
|
1710
|
+
setSelectedBranch((current) => reconcileBaseBranchSelection(current, modalView.branches));
|
|
1711
|
+
}, [modalView, worktreeModalWorkspaceId]);
|
|
1164
1712
|
const runMutation = async (operation) => {
|
|
1165
1713
|
setActionPending(true);
|
|
1166
1714
|
setActionError(void 0);
|
|
1167
1715
|
try {
|
|
1168
1716
|
await operation();
|
|
1169
|
-
await refresh();
|
|
1717
|
+
await refresh({ preserveCurrent: true });
|
|
1170
1718
|
} catch (error) {
|
|
1171
1719
|
setActionError(toWorktreeViewError(error));
|
|
1172
1720
|
} finally {
|
|
@@ -1292,6 +1840,29 @@ window.__ModuleLoader__.load({
|
|
|
1292
1840
|
setActionError(toWorktreeViewError(error));
|
|
1293
1841
|
});
|
|
1294
1842
|
};
|
|
1843
|
+
const commitWorktreeDrag = (activeDrag, over, worktreeIds, workspaceId) => {
|
|
1844
|
+
if (worktreeDropCommitted.current) return;
|
|
1845
|
+
worktreeDropCommitted.current = true;
|
|
1846
|
+
setWorktreeDrag(void 0);
|
|
1847
|
+
if (activeDrag.workspaceId !== workspaceId) return;
|
|
1848
|
+
const move = resolveWorktreeMove(worktreeIds, activeDrag.worktreeId, over.worktreeId, over.half);
|
|
1849
|
+
if (move === void 0) return;
|
|
1850
|
+
if (insertWorktreeBefore === void 0) {
|
|
1851
|
+
setActionError({
|
|
1852
|
+
code: "WORKTREE_ORDER_UNAVAILABLE",
|
|
1853
|
+
message: "",
|
|
1854
|
+
retryable: true
|
|
1855
|
+
});
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
setActionError(void 0);
|
|
1859
|
+
insertWorktreeBefore(workspaceId, activeDrag.worktreeId, move.beforeWorktreeId).then(() => refresh({
|
|
1860
|
+
preserveCurrent: true,
|
|
1861
|
+
invalidateContext: false
|
|
1862
|
+
})).catch((error) => {
|
|
1863
|
+
setActionError(toRetryableWorktreeOrderError(error));
|
|
1864
|
+
});
|
|
1865
|
+
};
|
|
1295
1866
|
const openSessionRename = (sessionId, currentTitle) => {
|
|
1296
1867
|
setSessionRenameTarget({
|
|
1297
1868
|
sessionId,
|
|
@@ -1361,7 +1932,7 @@ window.__ModuleLoader__.load({
|
|
|
1361
1932
|
};
|
|
1362
1933
|
const submitWorktree = async () => {
|
|
1363
1934
|
const worktreeName = newBranch.trim();
|
|
1364
|
-
if (manager === void 0 || modalWorkspace === void 0 || selectedBranch.length === 0 || worktreeName.length === 0) return;
|
|
1935
|
+
if (manager === void 0 || modalWorkspace === void 0 || !modalCanCreate || selectedBranch.length === 0 || worktreeName.length === 0) return;
|
|
1365
1936
|
const input = {
|
|
1366
1937
|
workspaceId: modalWorkspace.workspaceId,
|
|
1367
1938
|
branch: selectedBranch,
|
|
@@ -1382,7 +1953,7 @@ window.__ModuleLoader__.load({
|
|
|
1382
1953
|
};
|
|
1383
1954
|
setWorktreeModalWorkspaceId(void 0);
|
|
1384
1955
|
if (createSessionCallback === void 0) {
|
|
1385
|
-
await refresh();
|
|
1956
|
+
await refresh({ preserveCurrent: true });
|
|
1386
1957
|
setActionError({
|
|
1387
1958
|
code: "WORKTREE_CREATED_SESSION_UNAVAILABLE",
|
|
1388
1959
|
message: "",
|
|
@@ -1397,14 +1968,15 @@ window.__ModuleLoader__.load({
|
|
|
1397
1968
|
};
|
|
1398
1969
|
try {
|
|
1399
1970
|
await createSessionCallback(sessionInput);
|
|
1971
|
+
await invalidateWorktreeContext?.(createdWorktree.workspaceId);
|
|
1400
1972
|
} catch (error) {
|
|
1401
|
-
if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
|
|
1973
|
+
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
1402
1974
|
...sessionInput,
|
|
1403
1975
|
sessionId: error.sessionId
|
|
1404
1976
|
});
|
|
1405
1977
|
throw error;
|
|
1406
1978
|
}
|
|
1407
|
-
await refresh();
|
|
1979
|
+
await refresh({ preserveCurrent: true });
|
|
1408
1980
|
} catch (error) {
|
|
1409
1981
|
setActionError(toWorktreeViewError(error));
|
|
1410
1982
|
} finally {
|
|
@@ -1425,9 +1997,10 @@ window.__ModuleLoader__.load({
|
|
|
1425
1997
|
setPendingSessionBinding(void 0);
|
|
1426
1998
|
try {
|
|
1427
1999
|
await createSessionCallback(input);
|
|
1428
|
-
await
|
|
2000
|
+
await invalidateWorktreeContext?.(input.workspaceId);
|
|
2001
|
+
await refresh({ preserveCurrent: true });
|
|
1429
2002
|
} catch (error) {
|
|
1430
|
-
if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
|
|
2003
|
+
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
1431
2004
|
...input,
|
|
1432
2005
|
sessionId: error.sessionId
|
|
1433
2006
|
});
|
|
@@ -1437,21 +2010,25 @@ window.__ModuleLoader__.load({
|
|
|
1437
2010
|
}
|
|
1438
2011
|
};
|
|
1439
2012
|
const retrySessionBinding = async () => {
|
|
1440
|
-
if (manager === void 0 || pendingSessionBinding === void 0) return;
|
|
2013
|
+
if (manager === void 0 || pendingSessionBinding === void 0 || pendingSessionArchived) return;
|
|
2014
|
+
const pending = pendingSessionBinding;
|
|
1441
2015
|
setActionPending(true);
|
|
1442
2016
|
setActionError(void 0);
|
|
1443
2017
|
try {
|
|
1444
|
-
await
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
2018
|
+
await retryWorktreeSessionBinding({
|
|
2019
|
+
manager,
|
|
2020
|
+
pending,
|
|
2021
|
+
archived: false,
|
|
2022
|
+
ensureSessionWorkspace: (workspaceId, sessionId) => {
|
|
2023
|
+
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2024
|
+
},
|
|
2025
|
+
openSession
|
|
1448
2026
|
});
|
|
1449
|
-
const sessionId = pendingSessionBinding.sessionId;
|
|
1450
2027
|
setPendingSessionBinding(void 0);
|
|
1451
|
-
|
|
1452
|
-
await
|
|
1453
|
-
openSession(sessionId);
|
|
2028
|
+
await refresh({ preserveCurrent: true });
|
|
2029
|
+
await invalidateWorktreeContext?.(pending.workspaceId);
|
|
1454
2030
|
} catch (error) {
|
|
2031
|
+
if (error instanceof WorktreeSessionBindingError && !error.retryable) setPendingSessionBinding(void 0);
|
|
1455
2032
|
setActionError(toWorktreeViewError(error));
|
|
1456
2033
|
} finally {
|
|
1457
2034
|
setActionPending(false);
|
|
@@ -1545,7 +2122,7 @@ window.__ModuleLoader__.load({
|
|
|
1545
2122
|
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
1546
2123
|
type: "button",
|
|
1547
2124
|
className: worktree_css_default.actionButton,
|
|
1548
|
-
disabled: actionPending,
|
|
2125
|
+
disabled: actionPending || pendingSessionArchived,
|
|
1549
2126
|
onClick: () => {
|
|
1550
2127
|
retrySessionBinding();
|
|
1551
2128
|
},
|
|
@@ -1601,14 +2178,17 @@ window.__ModuleLoader__.load({
|
|
|
1601
2178
|
children: t("workspace.noMatches")
|
|
1602
2179
|
}) : visibleWorkspaces.map((workspace) => {
|
|
1603
2180
|
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
2181
|
+
const currentBranch = view?.branches.find((branch) => branch.isCurrent)?.name;
|
|
2182
|
+
const mainLabel = currentBranch === void 0 ? t("worktree.main") : t("worktree.mainWithBranch", { branch: currentBranch });
|
|
1604
2183
|
const expanded = expandedWorkspaces[workspace.workspaceId] !== false;
|
|
1605
2184
|
const workspaceMatchesQuery = includesText(workspace.title, query);
|
|
1606
2185
|
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
1607
2186
|
const bindings = view?.bindings ?? [];
|
|
1608
|
-
const visibleMainSessionIds = unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]).filter((sessionId) => workspaceMatchesQuery ||
|
|
2187
|
+
const visibleMainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions).filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
1609
2188
|
const mainExpanded = expandedMains[workspace.workspaceId] !== false;
|
|
1610
2189
|
const mainGroupKey = `main:${workspace.workspaceId}`;
|
|
1611
2190
|
const worktrees = view?.worktrees ?? [];
|
|
2191
|
+
const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
|
|
1612
2192
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
1613
2193
|
className: worktree_css_default.workspaceGroup,
|
|
1614
2194
|
"data-workspace-id": workspace.workspaceId,
|
|
@@ -1671,7 +2251,7 @@ window.__ModuleLoader__.load({
|
|
|
1671
2251
|
(0, react_jsx_runtime.jsx)(WorktreeGroupRow, {
|
|
1672
2252
|
t,
|
|
1673
2253
|
kind: "main",
|
|
1674
|
-
label:
|
|
2254
|
+
label: mainLabel,
|
|
1675
2255
|
expanded: mainExpanded,
|
|
1676
2256
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
1677
2257
|
workspaceTitle: workspace.title,
|
|
@@ -1733,10 +2313,10 @@ window.__ModuleLoader__.load({
|
|
|
1733
2313
|
children: t("worktree.noWorktrees")
|
|
1734
2314
|
}),
|
|
1735
2315
|
worktrees.map((record) => {
|
|
1736
|
-
const worktreeSessionIds = filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds);
|
|
2316
|
+
const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
|
|
1737
2317
|
const worktreeMatchesQuery = workspaceMatchesQuery || includesText(record.branch, query) || includesText(record.absolutePath, query);
|
|
1738
|
-
if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) =>
|
|
1739
|
-
const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery ||
|
|
2318
|
+
if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return null;
|
|
2319
|
+
const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
1740
2320
|
const worktreeGroupKey = `worktree:${record.worktreeId}`;
|
|
1741
2321
|
const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
|
|
1742
2322
|
const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
|
|
@@ -1748,6 +2328,7 @@ window.__ModuleLoader__.load({
|
|
|
1748
2328
|
t,
|
|
1749
2329
|
kind: "worktree",
|
|
1750
2330
|
label: record.branch,
|
|
2331
|
+
worktreeId: record.worktreeId,
|
|
1751
2332
|
expanded: worktreeExpanded,
|
|
1752
2333
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
1753
2334
|
workspaceTitle: workspace.title,
|
|
@@ -1756,7 +2337,7 @@ window.__ModuleLoader__.load({
|
|
|
1756
2337
|
onToggle: () => {
|
|
1757
2338
|
toggleWorktree(record.worktreeId);
|
|
1758
2339
|
},
|
|
1759
|
-
onCreateSession: record.status === "active" ? () => {
|
|
2340
|
+
onCreateSession: record.status === "active" && record.health !== "repair" ? () => {
|
|
1760
2341
|
createSession({
|
|
1761
2342
|
workspaceId: record.workspaceId,
|
|
1762
2343
|
worktreeId: record.worktreeId,
|
|
@@ -1774,7 +2355,39 @@ window.__ModuleLoader__.load({
|
|
|
1774
2355
|
setWorktreeRemoval(record);
|
|
1775
2356
|
setActionError(void 0);
|
|
1776
2357
|
}
|
|
1777
|
-
} : void 0
|
|
2358
|
+
} : void 0,
|
|
2359
|
+
drag: {
|
|
2360
|
+
active: sameWorkspaceWorktreeDrag,
|
|
2361
|
+
marker: worktreeDrag?.over?.worktreeId === record.worktreeId ? worktreeDrag.over.half : null,
|
|
2362
|
+
start: () => {
|
|
2363
|
+
worktreeDropCommitted.current = false;
|
|
2364
|
+
setWorktreeDrag({
|
|
2365
|
+
workspaceId: workspace.workspaceId,
|
|
2366
|
+
worktreeId: record.worktreeId,
|
|
2367
|
+
over: null
|
|
2368
|
+
});
|
|
2369
|
+
},
|
|
2370
|
+
hover: (half) => {
|
|
2371
|
+
setWorktreeDrag((current) => current === void 0 || current.workspaceId !== workspace.workspaceId ? current : {
|
|
2372
|
+
...current,
|
|
2373
|
+
over: {
|
|
2374
|
+
worktreeId: record.worktreeId,
|
|
2375
|
+
half
|
|
2376
|
+
}
|
|
2377
|
+
});
|
|
2378
|
+
},
|
|
2379
|
+
drop: (half) => {
|
|
2380
|
+
if (worktreeDrag === void 0) return;
|
|
2381
|
+
commitWorktreeDrag(worktreeDrag, {
|
|
2382
|
+
worktreeId: record.worktreeId,
|
|
2383
|
+
half
|
|
2384
|
+
}, worktrees.map((candidate) => candidate.worktreeId), workspace.workspaceId);
|
|
2385
|
+
},
|
|
2386
|
+
end: () => {
|
|
2387
|
+
setWorktreeDrag(void 0);
|
|
2388
|
+
worktreeDropCommitted.current = false;
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
1778
2391
|
}), worktreeExpanded && (0, react_jsx_runtime.jsx)(WorktreeSessionGroup, {
|
|
1779
2392
|
t,
|
|
1780
2393
|
groupKey: worktreeGroupKey,
|
|
@@ -1963,7 +2576,7 @@ window.__ModuleLoader__.load({
|
|
|
1963
2576
|
children: formatWorktreeViewError(workspaceDeleteError, t)
|
|
1964
2577
|
})
|
|
1965
2578
|
}),
|
|
1966
|
-
worktreeModalWorkspaceId !== void 0 && modalWorkspace !== void 0 && (0, react_jsx_runtime.
|
|
2579
|
+
worktreeModalWorkspaceId !== void 0 && modalWorkspace !== void 0 && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1967
2580
|
open: worktreeModalWorkspaceId !== void 0,
|
|
1968
2581
|
onClose: () => {
|
|
1969
2582
|
if (actionPending) return;
|
|
@@ -1987,48 +2600,50 @@ window.__ModuleLoader__.load({
|
|
|
1987
2600
|
},
|
|
1988
2601
|
children: t("worktree.create")
|
|
1989
2602
|
})] }),
|
|
1990
|
-
children: [
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2603
|
+
children: modalCanCreate ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
2604
|
+
className: worktree_css_default.modalField,
|
|
2605
|
+
children: [t("worktree.baseBranch"), (0, react_jsx_runtime.jsx)("select", {
|
|
2606
|
+
className: worktree_css_default.actionSelect,
|
|
2607
|
+
"aria-label": t("worktree.baseBranch"),
|
|
2608
|
+
value: selectedBranch,
|
|
2609
|
+
disabled: actionPending,
|
|
2610
|
+
onChange: (event) => {
|
|
2611
|
+
setSelectedBranch(event.currentTarget.value);
|
|
2612
|
+
},
|
|
2613
|
+
children: modalView?.branches.map((branch) => (0, react_jsx_runtime.jsxs)("option", {
|
|
2614
|
+
value: branch.name,
|
|
2615
|
+
children: [
|
|
2616
|
+
branch.name,
|
|
2617
|
+
branch.isCurrent ? t("branch.current") : "",
|
|
2618
|
+
branch.checkedOut ? t("branch.checkedOut") : ""
|
|
2619
|
+
]
|
|
2620
|
+
}, branch.name))
|
|
2621
|
+
})]
|
|
2622
|
+
}), (0, react_jsx_runtime.jsxs)("label", {
|
|
2623
|
+
className: worktree_css_default.modalField,
|
|
2624
|
+
children: [t("worktree.name"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
2625
|
+
className: worktree_css_default.renameInput,
|
|
2626
|
+
"aria-label": t("worktree.name"),
|
|
2627
|
+
value: newBranch,
|
|
2628
|
+
placeholder: "dsh/12345678",
|
|
2629
|
+
disabled: actionPending,
|
|
2630
|
+
onChange: (event) => {
|
|
2631
|
+
setNewBranch(event.currentTarget.value);
|
|
2632
|
+
}
|
|
2633
|
+
})]
|
|
2634
|
+
})] }) : (0, react_jsx_runtime.jsxs)("div", {
|
|
2635
|
+
className: worktree_css_default.gitReadiness,
|
|
2636
|
+
"data-worktree-readiness": modalSetupStatus ?? "loading",
|
|
2637
|
+
role: "alert",
|
|
2638
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
2639
|
+
className: worktree_css_default.message,
|
|
2640
|
+
children: modalSetupStatus === void 0 ? t("status.loading") : worktreeSetupMessage(modalSetupStatus, t)
|
|
2641
|
+
}), modalSetupStatus !== void 0 && (0, react_jsx_runtime.jsx)("pre", {
|
|
2642
|
+
className: worktree_css_default.commandBlock,
|
|
2643
|
+
"aria-label": t("worktree.setup.commands"),
|
|
2644
|
+
children: worktreeSetupCommands(modalSetupStatus).join("\n")
|
|
2645
|
+
})]
|
|
2646
|
+
})
|
|
2032
2647
|
}),
|
|
2033
2648
|
worktreeRemoval !== void 0 && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2034
2649
|
open: worktreeRemoval !== void 0,
|
|
@@ -2060,6 +2675,7 @@ window.__ModuleLoader__.load({
|
|
|
2060
2675
|
worktreeId: target.worktreeId
|
|
2061
2676
|
}
|
|
2062
2677
|
});
|
|
2678
|
+
await invalidateWorktreeContext?.(target.workspaceId);
|
|
2063
2679
|
setWorktreeRemoval(void 0);
|
|
2064
2680
|
});
|
|
2065
2681
|
},
|
|
@@ -2070,6 +2686,240 @@ window.__ModuleLoader__.load({
|
|
|
2070
2686
|
});
|
|
2071
2687
|
}
|
|
2072
2688
|
//#endregion
|
|
2689
|
+
//#region lib/client/WorktreeOverlay.js
|
|
2690
|
+
/** Compose the independent Hero context and Worktree navigation overlays. */
|
|
2691
|
+
function WorktreeOverlay(props) {
|
|
2692
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(WorktreeHeroContext, { ...props }), (0, react_jsx_runtime.jsx)(WorktreeSurface, { ...props })] });
|
|
2693
|
+
}
|
|
2694
|
+
//#endregion
|
|
2695
|
+
//#region lib/client/worktree-context.js
|
|
2696
|
+
const none = (reason) => ({
|
|
2697
|
+
kind: "none",
|
|
2698
|
+
reason
|
|
2699
|
+
});
|
|
2700
|
+
/** Resolve the branch or active Worktree label for one current DSH Session. */
|
|
2701
|
+
function resolveWorktreeSessionContext(input) {
|
|
2702
|
+
const sessionId = input.currentSessionId;
|
|
2703
|
+
if (sessionId === void 0 && input.currentWorkspaceId === void 0) return none("no-session");
|
|
2704
|
+
const workspace = sessionId === void 0 ? input.workspaces.find(({ workspaceId }) => workspaceId === input.currentWorkspaceId) : input.workspaces.find(({ sessionIds }) => sessionIds.includes(sessionId));
|
|
2705
|
+
if (workspace === void 0) return none("unbound");
|
|
2706
|
+
const binding = sessionId === void 0 ? void 0 : input.bindings.find((candidate) => candidate.sessionId === sessionId);
|
|
2707
|
+
if (binding !== void 0) {
|
|
2708
|
+
if (binding.workspaceId !== workspace.workspaceId) return none("workspace-mismatch");
|
|
2709
|
+
if (binding.status === "detached") return none("detached");
|
|
2710
|
+
const record = input.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId);
|
|
2711
|
+
if (record === void 0 || record.workspaceId !== workspace.workspaceId) return none(record === void 0 ? "stale" : "workspace-mismatch");
|
|
2712
|
+
if (record.status !== "active") return none("stale");
|
|
2713
|
+
if (record.health === "repair") return none("repair");
|
|
2714
|
+
if (record.branch.length === 0) return none("not-ready");
|
|
2715
|
+
return {
|
|
2716
|
+
kind: "worktree",
|
|
2717
|
+
workspaceId: workspace.workspaceId,
|
|
2718
|
+
worktreeId: record.worktreeId,
|
|
2719
|
+
label: record.branch,
|
|
2720
|
+
source: "active-binding"
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
const currentBranch = input.branches.find(({ isCurrent }) => isCurrent);
|
|
2724
|
+
if (currentBranch === void 0 || currentBranch.name.length === 0) return none("not-ready");
|
|
2725
|
+
return {
|
|
2726
|
+
kind: "main",
|
|
2727
|
+
workspaceId: workspace.workspaceId,
|
|
2728
|
+
label: currentBranch.name,
|
|
2729
|
+
source: "current-branch"
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
//#endregion
|
|
2733
|
+
//#region lib/client/worktree-context-store.js
|
|
2734
|
+
const notReady = () => ({
|
|
2735
|
+
kind: "none",
|
|
2736
|
+
reason: "not-ready"
|
|
2737
|
+
});
|
|
2738
|
+
function scheduledRefresh() {
|
|
2739
|
+
let resolve;
|
|
2740
|
+
return {
|
|
2741
|
+
promise: new Promise((resolvePromise) => {
|
|
2742
|
+
resolve = resolvePromise;
|
|
2743
|
+
}),
|
|
2744
|
+
resolve
|
|
2745
|
+
};
|
|
2746
|
+
}
|
|
2747
|
+
function identityFrom(sessions, workspaces) {
|
|
2748
|
+
const sessionId = sessions.getSnapshot().current;
|
|
2749
|
+
if (sessionId === void 0) return { workspaceId: workspaces.getSnapshot().recentWorkspaceId };
|
|
2750
|
+
return {
|
|
2751
|
+
sessionId,
|
|
2752
|
+
workspaceId: workspaces.getSnapshot().items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
/**
|
|
2756
|
+
* Build one browser-local current-Session projection shared by the header
|
|
2757
|
+
* consumer. Superseded requests may still finish on the transport, but their
|
|
2758
|
+
* results never become visible in the current snapshot.
|
|
2759
|
+
*/
|
|
2760
|
+
function createWorktreeContextProjection(input) {
|
|
2761
|
+
const store = input.storeFactory({
|
|
2762
|
+
status: "idle",
|
|
2763
|
+
value: notReady()
|
|
2764
|
+
});
|
|
2765
|
+
let disposed = false;
|
|
2766
|
+
let generation = 0;
|
|
2767
|
+
let scheduled = false;
|
|
2768
|
+
let scheduleTicket = 0;
|
|
2769
|
+
let scheduledCompletion;
|
|
2770
|
+
let latestRefresh = Promise.resolve();
|
|
2771
|
+
const setPending = (identity) => {
|
|
2772
|
+
if (identity.workspaceId === void 0) {
|
|
2773
|
+
store.set({
|
|
2774
|
+
status: "ready",
|
|
2775
|
+
value: resolveWorktreeSessionContext({
|
|
2776
|
+
currentSessionId: identity.sessionId,
|
|
2777
|
+
currentWorkspaceId: identity.workspaceId,
|
|
2778
|
+
workspaces: input.workspaces.getSnapshot().items,
|
|
2779
|
+
branches: [],
|
|
2780
|
+
worktrees: [],
|
|
2781
|
+
bindings: []
|
|
2782
|
+
})
|
|
2783
|
+
});
|
|
2784
|
+
return;
|
|
2785
|
+
}
|
|
2786
|
+
const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === identity.workspaceId);
|
|
2787
|
+
store.set({
|
|
2788
|
+
status: "loading",
|
|
2789
|
+
...identity.sessionId === void 0 ? {} : { sessionId: identity.sessionId },
|
|
2790
|
+
workspaceId: identity.workspaceId,
|
|
2791
|
+
workspaceTitle: workspace?.title,
|
|
2792
|
+
value: notReady()
|
|
2793
|
+
});
|
|
2794
|
+
};
|
|
2795
|
+
const matchesCurrent = (request, requestGeneration) => {
|
|
2796
|
+
if (disposed || generation !== requestGeneration) return false;
|
|
2797
|
+
const current = identityFrom(input.sessions, input.workspaces);
|
|
2798
|
+
return current.sessionId === request.sessionId && current.workspaceId === request.workspaceId;
|
|
2799
|
+
};
|
|
2800
|
+
const runRefresh = async () => {
|
|
2801
|
+
if (disposed) return;
|
|
2802
|
+
const requestGeneration = ++generation;
|
|
2803
|
+
const identity = identityFrom(input.sessions, input.workspaces);
|
|
2804
|
+
setPending(identity);
|
|
2805
|
+
if (identity.workspaceId === void 0) return;
|
|
2806
|
+
const request = {
|
|
2807
|
+
sessionId: identity.sessionId,
|
|
2808
|
+
workspaceId: identity.workspaceId
|
|
2809
|
+
};
|
|
2810
|
+
try {
|
|
2811
|
+
const data = await loadWorktreeView(input.manager, request.workspaceId);
|
|
2812
|
+
if (!matchesCurrent(request, requestGeneration)) return;
|
|
2813
|
+
const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId);
|
|
2814
|
+
if ("error" in data.readiness) {
|
|
2815
|
+
store.set({
|
|
2816
|
+
status: "error",
|
|
2817
|
+
...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
|
|
2818
|
+
workspaceId: request.workspaceId,
|
|
2819
|
+
workspaceTitle: workspace?.title,
|
|
2820
|
+
value: notReady(),
|
|
2821
|
+
error: data.readiness.error
|
|
2822
|
+
});
|
|
2823
|
+
return;
|
|
2824
|
+
}
|
|
2825
|
+
store.set({
|
|
2826
|
+
status: "ready",
|
|
2827
|
+
...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
|
|
2828
|
+
workspaceId: request.workspaceId,
|
|
2829
|
+
workspaceTitle: workspace?.title,
|
|
2830
|
+
value: resolveWorktreeSessionContext({
|
|
2831
|
+
currentSessionId: request.sessionId,
|
|
2832
|
+
currentWorkspaceId: request.workspaceId,
|
|
2833
|
+
workspaces: input.workspaces.getSnapshot().items,
|
|
2834
|
+
branches: data.branches,
|
|
2835
|
+
worktrees: data.worktrees,
|
|
2836
|
+
bindings: data.bindings
|
|
2837
|
+
})
|
|
2838
|
+
});
|
|
2839
|
+
} catch (error) {
|
|
2840
|
+
if (!matchesCurrent(request, requestGeneration)) return;
|
|
2841
|
+
store.set({
|
|
2842
|
+
status: "error",
|
|
2843
|
+
...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
|
|
2844
|
+
workspaceId: request.workspaceId,
|
|
2845
|
+
workspaceTitle: input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId)?.title,
|
|
2846
|
+
value: notReady(),
|
|
2847
|
+
error: toWorktreeViewError(error)
|
|
2848
|
+
});
|
|
2849
|
+
}
|
|
2850
|
+
};
|
|
2851
|
+
const cancelScheduledRefresh = () => {
|
|
2852
|
+
scheduleTicket += 1;
|
|
2853
|
+
scheduled = false;
|
|
2854
|
+
const completion = scheduledCompletion;
|
|
2855
|
+
scheduledCompletion = void 0;
|
|
2856
|
+
completion?.resolve();
|
|
2857
|
+
};
|
|
2858
|
+
const refresh = () => {
|
|
2859
|
+
cancelScheduledRefresh();
|
|
2860
|
+
const completion = runRefresh();
|
|
2861
|
+
latestRefresh = completion;
|
|
2862
|
+
return completion;
|
|
2863
|
+
};
|
|
2864
|
+
const scheduleRefresh = () => {
|
|
2865
|
+
if (disposed) return;
|
|
2866
|
+
generation += 1;
|
|
2867
|
+
if (scheduled) return;
|
|
2868
|
+
setPending(identityFrom(input.sessions, input.workspaces));
|
|
2869
|
+
scheduled = true;
|
|
2870
|
+
const ticket = ++scheduleTicket;
|
|
2871
|
+
const completion = scheduledRefresh();
|
|
2872
|
+
scheduledCompletion = completion;
|
|
2873
|
+
latestRefresh = completion.promise;
|
|
2874
|
+
queueMicrotask(() => {
|
|
2875
|
+
if (disposed || ticket !== scheduleTicket) {
|
|
2876
|
+
completion.resolve();
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
scheduled = false;
|
|
2880
|
+
runRefresh().finally(() => {
|
|
2881
|
+
if (scheduledCompletion === completion) scheduledCompletion = void 0;
|
|
2882
|
+
completion.resolve();
|
|
2883
|
+
});
|
|
2884
|
+
});
|
|
2885
|
+
};
|
|
2886
|
+
const waitForLatestRefresh = async (workspaceId) => {
|
|
2887
|
+
let observed;
|
|
2888
|
+
while (!disposed) {
|
|
2889
|
+
if (workspaceId !== void 0 && identityFrom(input.sessions, input.workspaces).workspaceId !== workspaceId) return;
|
|
2890
|
+
const completion = latestRefresh;
|
|
2891
|
+
if (completion === observed) return;
|
|
2892
|
+
observed = completion;
|
|
2893
|
+
await completion;
|
|
2894
|
+
}
|
|
2895
|
+
};
|
|
2896
|
+
const unsubscribeSessions = input.sessions.subscribe(scheduleRefresh);
|
|
2897
|
+
const unsubscribeWorkspaces = input.workspaces.subscribe(scheduleRefresh);
|
|
2898
|
+
return {
|
|
2899
|
+
store,
|
|
2900
|
+
refresh,
|
|
2901
|
+
async invalidate(workspaceId) {
|
|
2902
|
+
if (disposed) return;
|
|
2903
|
+
const identity = identityFrom(input.sessions, input.workspaces);
|
|
2904
|
+
if (workspaceId !== void 0 && workspaceId !== identity.workspaceId) return;
|
|
2905
|
+
await refresh();
|
|
2906
|
+
await waitForLatestRefresh(workspaceId ?? identity.workspaceId);
|
|
2907
|
+
},
|
|
2908
|
+
dispose() {
|
|
2909
|
+
if (disposed) return;
|
|
2910
|
+
disposed = true;
|
|
2911
|
+
generation += 1;
|
|
2912
|
+
cancelScheduledRefresh();
|
|
2913
|
+
unsubscribeSessions();
|
|
2914
|
+
unsubscribeWorkspaces();
|
|
2915
|
+
store.set({
|
|
2916
|
+
status: "idle",
|
|
2917
|
+
value: notReady()
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
//#endregion
|
|
2073
2923
|
//#region lib/client/view-mode-store.js
|
|
2074
2924
|
/** Create one root-scoped, browser-local view-mode store for the two slot entries. */
|
|
2075
2925
|
function createWorktreeViewStore() {
|
|
@@ -2111,17 +2961,24 @@ window.__ModuleLoader__.load({
|
|
|
2111
2961
|
let bindings = [];
|
|
2112
2962
|
let disposed = false;
|
|
2113
2963
|
let applying = false;
|
|
2114
|
-
const
|
|
2115
|
-
|
|
2116
|
-
const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
|
|
2117
|
-
if (sameWorkspaceItems(current, next)) return;
|
|
2964
|
+
const nativeSet = list.set;
|
|
2965
|
+
const write = (next) => {
|
|
2118
2966
|
applying = true;
|
|
2119
2967
|
try {
|
|
2120
|
-
|
|
2968
|
+
nativeSet(next);
|
|
2121
2969
|
} finally {
|
|
2122
2970
|
applying = false;
|
|
2123
2971
|
}
|
|
2124
2972
|
};
|
|
2973
|
+
list.set = (next) => {
|
|
2974
|
+
write(projectVirtualWorkspaceMembership(next, bindings, bindings));
|
|
2975
|
+
};
|
|
2976
|
+
const apply = (nextBindings) => {
|
|
2977
|
+
const current = list.getSnapshot();
|
|
2978
|
+
const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
|
|
2979
|
+
if (sameWorkspaceItems(current, next)) return;
|
|
2980
|
+
write(next);
|
|
2981
|
+
};
|
|
2125
2982
|
const replay = () => {
|
|
2126
2983
|
if (disposed || applying) return;
|
|
2127
2984
|
apply(bindings);
|
|
@@ -2149,6 +3006,7 @@ window.__ModuleLoader__.load({
|
|
|
2149
3006
|
bindings = [];
|
|
2150
3007
|
disposed = true;
|
|
2151
3008
|
unsubscribe();
|
|
3009
|
+
list.set = nativeSet;
|
|
2152
3010
|
}
|
|
2153
3011
|
};
|
|
2154
3012
|
}
|
|
@@ -2174,8 +3032,16 @@ window.__ModuleLoader__.load({
|
|
|
2174
3032
|
const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
|
|
2175
3033
|
const sessions = ctx.sessions;
|
|
2176
3034
|
const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
|
|
3035
|
+
const contextProjection = createWorktreeContextProjection({
|
|
3036
|
+
sessions: ctx.sessions.list,
|
|
3037
|
+
workspaces: ctx.workspaces.list,
|
|
3038
|
+
manager,
|
|
3039
|
+
storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
|
|
3040
|
+
});
|
|
2177
3041
|
ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
|
|
2178
3042
|
ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
|
|
3043
|
+
ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
|
|
3044
|
+
contextProjection.refresh();
|
|
2179
3045
|
const viewStore = createWorktreeViewStore();
|
|
2180
3046
|
const ensureSessionWorkspace = (workspaceId, sessionId) => {
|
|
2181
3047
|
virtualWorkspaceMembership.ensure({
|
|
@@ -2186,6 +3052,24 @@ window.__ModuleLoader__.load({
|
|
|
2186
3052
|
const syncSessionWorkspaces = (bindings) => {
|
|
2187
3053
|
virtualWorkspaceMembership.sync(bindings);
|
|
2188
3054
|
};
|
|
3055
|
+
const worktreeSessionConnector = createWorktreeSessionConnector({
|
|
3056
|
+
manager,
|
|
3057
|
+
sessions: ctx.sessions.list,
|
|
3058
|
+
archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
|
|
3059
|
+
createSession: async (input) => String(await sessions.create(input)),
|
|
3060
|
+
ensureSessionWorkspace,
|
|
3061
|
+
openSession: (sessionId) => {
|
|
3062
|
+
ctx.sessions.open(sessionId);
|
|
3063
|
+
}
|
|
3064
|
+
});
|
|
3065
|
+
ctx.effect(() => () => worktreeSessionConnector.dispose(), "clutch-dsh-worktree: Worktree Session connector cleanup");
|
|
3066
|
+
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
3067
|
+
name: "conversation.session.header.actions",
|
|
3068
|
+
id: "clutch-dsh-worktree-context-header",
|
|
3069
|
+
order: -5,
|
|
3070
|
+
locale: WORKTREE_NS,
|
|
3071
|
+
inject: () => ({ hooks: { worktreeContext: contextProjection.store } })
|
|
3072
|
+
}, WorktreeHeaderContext));
|
|
2189
3073
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
2190
3074
|
name: "sidebar.footer.action",
|
|
2191
3075
|
id: "clutch-dsh-worktree-mode-action",
|
|
@@ -2200,22 +3084,14 @@ window.__ModuleLoader__.load({
|
|
|
2200
3084
|
locale: WORKTREE_NS,
|
|
2201
3085
|
inject: () => ({
|
|
2202
3086
|
available: true,
|
|
3087
|
+
hooks: { worktreeContext: contextProjection.store },
|
|
2203
3088
|
manager,
|
|
2204
3089
|
createWorkspace: async () => {
|
|
2205
3090
|
const workspacePath = await ctx.workspaces.pickDirectory();
|
|
2206
3091
|
if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
|
|
2207
3092
|
},
|
|
2208
|
-
createSessionForWorktree: (input) =>
|
|
2209
|
-
|
|
2210
|
-
createSession: (sessionInput) => sessions.create(sessionInput),
|
|
2211
|
-
manager,
|
|
2212
|
-
beforeOpen: (sessionId) => {
|
|
2213
|
-
ensureSessionWorkspace(input.workspaceId, sessionId);
|
|
2214
|
-
},
|
|
2215
|
-
openSession: (sessionId) => {
|
|
2216
|
-
ctx.sessions.open(sessionId);
|
|
2217
|
-
}
|
|
2218
|
-
}),
|
|
3093
|
+
createSessionForWorktree: (input) => worktreeSessionConnector.create(input),
|
|
3094
|
+
invalidateWorktreeContext: (workspaceId) => contextProjection.invalidate(workspaceId),
|
|
2219
3095
|
createMainSession: (workspaceId) => {
|
|
2220
3096
|
ctx.workspaces.startSession(workspaceId);
|
|
2221
3097
|
},
|
|
@@ -2231,6 +3107,11 @@ window.__ModuleLoader__.load({
|
|
|
2231
3107
|
insertSessionBefore: async (workspaceId, sessionId, beforeSessionId) => {
|
|
2232
3108
|
await ctx.workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId);
|
|
2233
3109
|
},
|
|
3110
|
+
insertWorktreeBefore: (workspaceId, worktreeId, beforeWorktreeId) => manager.insertWorktreeBefore({
|
|
3111
|
+
workspaceId,
|
|
3112
|
+
worktreeId,
|
|
3113
|
+
beforeWorktreeId
|
|
3114
|
+
}),
|
|
2234
3115
|
renameSession: async (sessionId, title) => {
|
|
2235
3116
|
const session = ctx.sessions.binding(sessionId)?.session;
|
|
2236
3117
|
if (session === void 0) throw new Error(`unknown session "${sessionId}"`);
|
|
@@ -2252,7 +3133,7 @@ window.__ModuleLoader__.load({
|
|
|
2252
3133
|
ctx.sessions.open(sessionId);
|
|
2253
3134
|
}
|
|
2254
3135
|
})
|
|
2255
|
-
},
|
|
3136
|
+
}, WorktreeOverlay));
|
|
2256
3137
|
}
|
|
2257
3138
|
//#endregion
|
|
2258
3139
|
exports.WORKTREE_CONNECTION_CHANNEL = WORKTREE_CONNECTION_CHANNEL;
|