@cerbur/clutch-dsh-worktree 0.1.2 → 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 +200 -57
- 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 +1003 -133
- 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: 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 text-transform: uppercase;\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-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";
|
|
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",
|
|
@@ -385,6 +466,104 @@ window.__ModuleLoader__.load({
|
|
|
385
466
|
});
|
|
386
467
|
}
|
|
387
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
|
|
388
567
|
//#region lib/client/navigation.js
|
|
389
568
|
/** Open an existing Session through DSH without touching the peer view mode. */
|
|
390
569
|
function openWorktreeSession(opener, sessionId) {
|
|
@@ -419,6 +598,13 @@ window.__ModuleLoader__.load({
|
|
|
419
598
|
bottom: rect.bottom
|
|
420
599
|
};
|
|
421
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
|
+
}
|
|
422
608
|
function resolveNativeSidebarRoot(sidebar) {
|
|
423
609
|
const directChild = sidebar.firstElementChild;
|
|
424
610
|
if (directChild === null) return void 0;
|
|
@@ -460,34 +646,37 @@ window.__ModuleLoader__.load({
|
|
|
460
646
|
setBounds(EMPTY_BOUNDS);
|
|
461
647
|
return;
|
|
462
648
|
}
|
|
649
|
+
const overlayElement = overlay;
|
|
650
|
+
const sidebarElement = sidebar;
|
|
651
|
+
const nativeRootElement = nativeRoot;
|
|
463
652
|
let frameHandle;
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
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;
|
|
468
661
|
if (nextWidth > 0) setWidth(nextWidth);
|
|
469
|
-
setBounds(computeOverlayBounds(asRect(
|
|
470
|
-
}
|
|
471
|
-
|
|
662
|
+
setBounds(computeOverlayBounds(asRect(overlayElement), newSession === void 0 ? void 0 : asRect(newSession), footer === null ? void 0 : asRect(footer)));
|
|
663
|
+
}
|
|
664
|
+
function scheduleUpdate() {
|
|
472
665
|
if (frameHandle !== void 0) return;
|
|
473
666
|
frameHandle = requestAnimationFrame(() => {
|
|
474
667
|
frameHandle = void 0;
|
|
475
668
|
update();
|
|
476
669
|
});
|
|
477
|
-
}
|
|
478
|
-
update();
|
|
670
|
+
}
|
|
479
671
|
const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(scheduleUpdate) : void 0;
|
|
480
672
|
for (const element of [
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
673
|
+
overlayElement,
|
|
674
|
+
sidebarElement,
|
|
675
|
+
nativeRootElement
|
|
484
676
|
]) resizeObserver?.observe(element);
|
|
485
|
-
|
|
486
|
-
const footer = nativeRoot.lastElementChild;
|
|
487
|
-
if (newSession !== void 0) resizeObserver?.observe(newSession);
|
|
488
|
-
if (footer !== null) resizeObserver?.observe(footer);
|
|
677
|
+
update();
|
|
489
678
|
const mutationObserver = typeof MutationObserver === "function" ? new MutationObserver(scheduleUpdate) : void 0;
|
|
490
|
-
mutationObserver?.observe(
|
|
679
|
+
mutationObserver?.observe(nativeRootElement, {
|
|
491
680
|
childList: true,
|
|
492
681
|
subtree: true
|
|
493
682
|
});
|
|
@@ -576,6 +765,7 @@ window.__ModuleLoader__.load({
|
|
|
576
765
|
case "WORKTREE_RPC_INVALID_RESULT": return t("error.invalidResult", { endpoint: detail(error, "endpoint") });
|
|
577
766
|
case "WORKSPACE_ORDER_UNAVAILABLE": return t("error.workspaceOrderingUnavailable");
|
|
578
767
|
case "SESSION_ORDER_UNAVAILABLE": return t("error.sessionOrderingUnavailable");
|
|
768
|
+
case "WORKTREE_ORDER_UNAVAILABLE": return t("error.worktreeOrderingUnavailable");
|
|
579
769
|
case "SESSION_CREATE_UNAVAILABLE": return t("error.sessionCreationUnavailable");
|
|
580
770
|
case "WORKTREE_CREATED_SESSION_UNAVAILABLE": return t("error.worktreeCreatedSessionUnavailable");
|
|
581
771
|
case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
|
|
@@ -586,21 +776,58 @@ window.__ModuleLoader__.load({
|
|
|
586
776
|
sessionId: detail(error, "sessionId"),
|
|
587
777
|
reason: reason(error, t)
|
|
588
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");
|
|
589
785
|
default: return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
|
|
590
786
|
}
|
|
591
787
|
}
|
|
592
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
|
|
593
814
|
//#region lib/client/worktree-view.js
|
|
594
815
|
/** A DSH Session exists even when the external Worktree binding needs repair. */
|
|
595
816
|
var WorktreeSessionBindingError = class extends Error {
|
|
596
|
-
code
|
|
597
|
-
retryable
|
|
817
|
+
code;
|
|
818
|
+
retryable;
|
|
819
|
+
details;
|
|
598
820
|
sessionId;
|
|
599
821
|
cause;
|
|
600
822
|
constructor(sessionId, cause) {
|
|
601
|
-
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);
|
|
602
825
|
super(reason);
|
|
603
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 : {};
|
|
604
831
|
this.sessionId = sessionId;
|
|
605
832
|
this.cause = cause;
|
|
606
833
|
}
|
|
@@ -611,10 +838,63 @@ window.__ModuleLoader__.load({
|
|
|
611
838
|
for (let index = 0; index < previous.length; index += 1) if (previous[index] !== next[index]) return next;
|
|
612
839
|
return previous;
|
|
613
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
|
+
}
|
|
614
871
|
/** Prefer the branch checked out by the DSH Workspace, then fall back to any local branch. */
|
|
615
872
|
function selectDefaultBaseBranch(branches) {
|
|
616
873
|
return branches.find((branch) => branch.isCurrent)?.name ?? branches[0]?.name ?? "";
|
|
617
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
|
+
}
|
|
618
898
|
function browserRandomUuid() {
|
|
619
899
|
const randomUUID = globalThis.crypto?.randomUUID;
|
|
620
900
|
if (typeof randomUUID === "function") return randomUUID.call(globalThis.crypto);
|
|
@@ -635,25 +915,62 @@ window.__ModuleLoader__.load({
|
|
|
635
915
|
function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
|
|
636
916
|
return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
|
|
637
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
|
+
}
|
|
638
929
|
/** Read all three Worktree projections needed by the surface in one refresh. */
|
|
639
930
|
async function loadWorktreeView(manager, workspaceId) {
|
|
640
|
-
const [
|
|
931
|
+
const [worktreesResult, branchesResult, bindingsResult] = await Promise.allSettled([
|
|
641
932
|
manager.listWorktrees({ workspaceId }),
|
|
642
933
|
manager.listBranches({ workspaceId }),
|
|
643
934
|
manager.listBindings({ workspaceId })
|
|
644
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
|
+
}
|
|
645
948
|
return {
|
|
646
|
-
worktrees,
|
|
647
|
-
branches,
|
|
648
|
-
bindings
|
|
949
|
+
worktrees: worktreesResult.value,
|
|
950
|
+
branches: branchesResult.value,
|
|
951
|
+
bindings: bindingsResult.value,
|
|
952
|
+
readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
|
|
649
953
|
};
|
|
650
954
|
}
|
|
651
955
|
/** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
|
|
652
|
-
async function loadWorktreeViews(manager, workspaceIds) {
|
|
653
|
-
|
|
956
|
+
async function loadWorktreeViews(manager, workspaceIds, options = {}) {
|
|
957
|
+
const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
|
|
654
958
|
workspaceId,
|
|
655
959
|
...await loadWorktreeView(manager, workspaceId)
|
|
656
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 };
|
|
657
974
|
}
|
|
658
975
|
/** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
|
|
659
976
|
async function executeWorktreeAction(manager, action) {
|
|
@@ -709,8 +1026,174 @@ window.__ModuleLoader__.load({
|
|
|
709
1026
|
retryable: true
|
|
710
1027
|
};
|
|
711
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
|
+
}
|
|
712
1188
|
//#endregion
|
|
713
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
|
+
}
|
|
714
1197
|
function toNativeWorktreeViewError(error) {
|
|
715
1198
|
const viewError = toWorktreeViewError(error);
|
|
716
1199
|
if (typeof error === "object" && error !== null) return viewError;
|
|
@@ -730,8 +1213,8 @@ window.__ModuleLoader__.load({
|
|
|
730
1213
|
if (stable !== previousRef.current) previousRef.current = stable;
|
|
731
1214
|
return previousRef.current;
|
|
732
1215
|
}
|
|
733
|
-
function sessionLabel(sessionId, sessions) {
|
|
734
|
-
return
|
|
1216
|
+
function sessionLabel(sessionId, sessions, t) {
|
|
1217
|
+
return sessionDisplayLabel(sessionId, sessions, t("session.new"));
|
|
735
1218
|
}
|
|
736
1219
|
function rowHalf(event) {
|
|
737
1220
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
@@ -746,10 +1229,10 @@ window.__ModuleLoader__.load({
|
|
|
746
1229
|
function workspaceMatches(workspace, view, sessions, query) {
|
|
747
1230
|
if (query.length === 0) return true;
|
|
748
1231
|
if (includesText(workspace.title, query)) return true;
|
|
749
|
-
if (workspace.sessionIds.some((sessionId) =>
|
|
1232
|
+
if (workspace.sessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return true;
|
|
750
1233
|
if (view === void 0) return false;
|
|
751
1234
|
if (view.worktrees.some((record) => includesText(record.branch, query) || includesText(record.absolutePath, query))) return true;
|
|
752
|
-
return view.bindings.some((binding) =>
|
|
1235
|
+
return view.bindings.some((binding) => sessionMatchesQuery(binding.sessionId, sessions, query));
|
|
753
1236
|
}
|
|
754
1237
|
/** Workspace row using the native DSH menu, fixed action column, and drag contract. */
|
|
755
1238
|
function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
|
|
@@ -857,13 +1340,36 @@ window.__ModuleLoader__.load({
|
|
|
857
1340
|
});
|
|
858
1341
|
}
|
|
859
1342
|
/** Shared Main/Worktree group row with parameterized icon, state, and actions. */
|
|
860
|
-
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 }) {
|
|
861
1344
|
const main = kind === "main";
|
|
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
|
+
};
|
|
862
1366
|
const row = (0, react_jsx_runtime.jsxs)("div", {
|
|
863
|
-
className: worktree_css_default.worktreeRow
|
|
1367
|
+
className: `${worktree_css_default.worktreeRow} ${markerClass}`,
|
|
864
1368
|
"data-main-group": main ? "true" : void 0,
|
|
865
1369
|
"data-main-expanded": main ? String(expanded) : void 0,
|
|
866
1370
|
"data-menu-open": menu?.open ? "true" : void 0,
|
|
1371
|
+
"data-worktree-drag": drag?.active ? "active" : void 0,
|
|
1372
|
+
...dragProps,
|
|
867
1373
|
onClick: onToggle,
|
|
868
1374
|
children: [
|
|
869
1375
|
(0, react_jsx_runtime.jsx)("button", {
|
|
@@ -954,7 +1460,7 @@ window.__ModuleLoader__.load({
|
|
|
954
1460
|
});
|
|
955
1461
|
}
|
|
956
1462
|
/** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
|
|
957
|
-
function WorktreeSessionRow({ t, sessionId, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
|
|
1463
|
+
function WorktreeSessionRow({ t, sessionId, blank, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
|
|
958
1464
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
959
1465
|
const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
960
1466
|
const sessionMenuItems = [
|
|
@@ -980,6 +1486,7 @@ window.__ModuleLoader__.load({
|
|
|
980
1486
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
981
1487
|
className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
|
|
982
1488
|
"data-session-id": sessionId,
|
|
1489
|
+
"data-session-blank": blank ? "true" : void 0,
|
|
983
1490
|
"data-session-drag": drag.active ? "active" : void 0,
|
|
984
1491
|
"data-menu-open": menuOpen || void 0,
|
|
985
1492
|
role: "treeitem",
|
|
@@ -1013,7 +1520,7 @@ window.__ModuleLoader__.load({
|
|
|
1013
1520
|
className: worktree_css_default.sessionLabel,
|
|
1014
1521
|
children: label
|
|
1015
1522
|
})]
|
|
1016
|
-
}), (0, react_jsx_runtime.jsx)("span", {
|
|
1523
|
+
}), !blank && (0, react_jsx_runtime.jsx)("span", {
|
|
1017
1524
|
className: worktree_css_default.rowActions,
|
|
1018
1525
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1019
1526
|
open: menuOpen,
|
|
@@ -1050,7 +1557,8 @@ window.__ModuleLoader__.load({
|
|
|
1050
1557
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
|
|
1051
1558
|
t,
|
|
1052
1559
|
sessionId,
|
|
1053
|
-
|
|
1560
|
+
blank: isBlankSession(sessionId, sessions),
|
|
1561
|
+
label: sessionLabel(sessionId, sessions, t),
|
|
1054
1562
|
drag: {
|
|
1055
1563
|
active: sameGroupDrag,
|
|
1056
1564
|
marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
|
|
@@ -1092,12 +1600,14 @@ window.__ModuleLoader__.load({
|
|
|
1092
1600
|
* Peer Worktree navigation surface. It keeps the original DSH Workspace mode
|
|
1093
1601
|
* intact and renders a browser-local Workspace → Worktree → Session projection.
|
|
1094
1602
|
*/
|
|
1095
|
-
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 }) {
|
|
1096
1604
|
const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
|
|
1097
1605
|
const sessions = useSessions((state) => state);
|
|
1098
1606
|
const workspaces = useWorkspaces((state) => state);
|
|
1099
1607
|
const workspaceIds = useStableWorkspaceIds(workspaces.items);
|
|
1100
1608
|
const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
|
|
1609
|
+
const readStateRef = (0, react.useRef)(readState);
|
|
1610
|
+
readStateRef.current = readState;
|
|
1101
1611
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
1102
1612
|
const [expandedWorkspaces, setExpandedWorkspaces] = (0, react.useState)({});
|
|
1103
1613
|
const [expandedMains, setExpandedMains] = (0, react.useState)({});
|
|
@@ -1127,36 +1637,52 @@ window.__ModuleLoader__.load({
|
|
|
1127
1637
|
const [sessionDrag, setSessionDrag] = (0, react.useState)();
|
|
1128
1638
|
const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)({});
|
|
1129
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());
|
|
1130
1643
|
const { ref, width, bounds } = useSidebarOverlayGeometry(mode === "worktree");
|
|
1131
1644
|
const collapsed = width <= 64;
|
|
1132
1645
|
const query = searchQuery.trim().toLocaleLowerCase();
|
|
1133
1646
|
const archivedSessionIds = workspaces.archivedSessionIds ?? [];
|
|
1134
|
-
const
|
|
1647
|
+
const pendingSessionArchived = pendingSessionBinding !== void 0 && archivedSessionIds.includes(pendingSessionBinding.sessionId);
|
|
1648
|
+
const refresh = (0, react.useCallback)(async (options = {}) => {
|
|
1135
1649
|
if (manager === void 0) {
|
|
1650
|
+
refreshGuard.current.invalidate();
|
|
1136
1651
|
setReadState(EMPTY_READ_STATE);
|
|
1137
1652
|
return;
|
|
1138
1653
|
}
|
|
1139
|
-
|
|
1654
|
+
const preserveCurrent = options.preserveCurrent === true;
|
|
1655
|
+
if (!preserveCurrent) setReadState({
|
|
1140
1656
|
status: "loading",
|
|
1141
1657
|
views: []
|
|
1142
1658
|
});
|
|
1143
|
-
|
|
1144
|
-
|
|
1659
|
+
await refreshGuard.current.run(() => loadWorktreeViews(manager, workspaceIds, {
|
|
1660
|
+
invalidateContext: options.invalidateContext !== false,
|
|
1661
|
+
invalidateWorktreeContext
|
|
1662
|
+
}), (views) => {
|
|
1145
1663
|
setReadState({
|
|
1146
1664
|
status: "ready",
|
|
1147
1665
|
views
|
|
1148
1666
|
});
|
|
1149
|
-
}
|
|
1667
|
+
}, (error) => {
|
|
1668
|
+
if (preserveCurrent) throw error;
|
|
1150
1669
|
setReadState({
|
|
1151
1670
|
status: "error",
|
|
1152
1671
|
views: [],
|
|
1153
1672
|
error: toWorktreeViewError(error)
|
|
1154
1673
|
});
|
|
1155
|
-
}
|
|
1156
|
-
}, [
|
|
1674
|
+
});
|
|
1675
|
+
}, [
|
|
1676
|
+
invalidateWorktreeContext,
|
|
1677
|
+
manager,
|
|
1678
|
+
workspaceIds
|
|
1679
|
+
]);
|
|
1157
1680
|
(0, react.useEffect)(() => {
|
|
1158
|
-
if (mode === "worktree") refresh();
|
|
1159
|
-
else
|
|
1681
|
+
if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
|
|
1682
|
+
else {
|
|
1683
|
+
refreshGuard.current.invalidate();
|
|
1684
|
+
setReadState(EMPTY_READ_STATE);
|
|
1685
|
+
}
|
|
1160
1686
|
}, [mode, refresh]);
|
|
1161
1687
|
(0, react.useEffect)(() => {
|
|
1162
1688
|
if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
|
|
@@ -1172,12 +1698,23 @@ window.__ModuleLoader__.load({
|
|
|
1172
1698
|
const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
|
|
1173
1699
|
const modalWorkspace = workspaces.items.find((workspace) => workspace.workspaceId === worktreeModalWorkspaceId);
|
|
1174
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]);
|
|
1175
1712
|
const runMutation = async (operation) => {
|
|
1176
1713
|
setActionPending(true);
|
|
1177
1714
|
setActionError(void 0);
|
|
1178
1715
|
try {
|
|
1179
1716
|
await operation();
|
|
1180
|
-
await refresh();
|
|
1717
|
+
await refresh({ preserveCurrent: true });
|
|
1181
1718
|
} catch (error) {
|
|
1182
1719
|
setActionError(toWorktreeViewError(error));
|
|
1183
1720
|
} finally {
|
|
@@ -1303,6 +1840,29 @@ window.__ModuleLoader__.load({
|
|
|
1303
1840
|
setActionError(toWorktreeViewError(error));
|
|
1304
1841
|
});
|
|
1305
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
|
+
};
|
|
1306
1866
|
const openSessionRename = (sessionId, currentTitle) => {
|
|
1307
1867
|
setSessionRenameTarget({
|
|
1308
1868
|
sessionId,
|
|
@@ -1372,7 +1932,7 @@ window.__ModuleLoader__.load({
|
|
|
1372
1932
|
};
|
|
1373
1933
|
const submitWorktree = async () => {
|
|
1374
1934
|
const worktreeName = newBranch.trim();
|
|
1375
|
-
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;
|
|
1376
1936
|
const input = {
|
|
1377
1937
|
workspaceId: modalWorkspace.workspaceId,
|
|
1378
1938
|
branch: selectedBranch,
|
|
@@ -1393,7 +1953,7 @@ window.__ModuleLoader__.load({
|
|
|
1393
1953
|
};
|
|
1394
1954
|
setWorktreeModalWorkspaceId(void 0);
|
|
1395
1955
|
if (createSessionCallback === void 0) {
|
|
1396
|
-
await refresh();
|
|
1956
|
+
await refresh({ preserveCurrent: true });
|
|
1397
1957
|
setActionError({
|
|
1398
1958
|
code: "WORKTREE_CREATED_SESSION_UNAVAILABLE",
|
|
1399
1959
|
message: "",
|
|
@@ -1408,14 +1968,15 @@ window.__ModuleLoader__.load({
|
|
|
1408
1968
|
};
|
|
1409
1969
|
try {
|
|
1410
1970
|
await createSessionCallback(sessionInput);
|
|
1971
|
+
await invalidateWorktreeContext?.(createdWorktree.workspaceId);
|
|
1411
1972
|
} catch (error) {
|
|
1412
|
-
if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
|
|
1973
|
+
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
1413
1974
|
...sessionInput,
|
|
1414
1975
|
sessionId: error.sessionId
|
|
1415
1976
|
});
|
|
1416
1977
|
throw error;
|
|
1417
1978
|
}
|
|
1418
|
-
await refresh();
|
|
1979
|
+
await refresh({ preserveCurrent: true });
|
|
1419
1980
|
} catch (error) {
|
|
1420
1981
|
setActionError(toWorktreeViewError(error));
|
|
1421
1982
|
} finally {
|
|
@@ -1436,9 +1997,10 @@ window.__ModuleLoader__.load({
|
|
|
1436
1997
|
setPendingSessionBinding(void 0);
|
|
1437
1998
|
try {
|
|
1438
1999
|
await createSessionCallback(input);
|
|
1439
|
-
await
|
|
2000
|
+
await invalidateWorktreeContext?.(input.workspaceId);
|
|
2001
|
+
await refresh({ preserveCurrent: true });
|
|
1440
2002
|
} catch (error) {
|
|
1441
|
-
if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
|
|
2003
|
+
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
1442
2004
|
...input,
|
|
1443
2005
|
sessionId: error.sessionId
|
|
1444
2006
|
});
|
|
@@ -1448,21 +2010,25 @@ window.__ModuleLoader__.load({
|
|
|
1448
2010
|
}
|
|
1449
2011
|
};
|
|
1450
2012
|
const retrySessionBinding = async () => {
|
|
1451
|
-
if (manager === void 0 || pendingSessionBinding === void 0) return;
|
|
2013
|
+
if (manager === void 0 || pendingSessionBinding === void 0 || pendingSessionArchived) return;
|
|
2014
|
+
const pending = pendingSessionBinding;
|
|
1452
2015
|
setActionPending(true);
|
|
1453
2016
|
setActionError(void 0);
|
|
1454
2017
|
try {
|
|
1455
|
-
await
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
2018
|
+
await retryWorktreeSessionBinding({
|
|
2019
|
+
manager,
|
|
2020
|
+
pending,
|
|
2021
|
+
archived: false,
|
|
2022
|
+
ensureSessionWorkspace: (workspaceId, sessionId) => {
|
|
2023
|
+
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2024
|
+
},
|
|
2025
|
+
openSession
|
|
1459
2026
|
});
|
|
1460
|
-
const sessionId = pendingSessionBinding.sessionId;
|
|
1461
2027
|
setPendingSessionBinding(void 0);
|
|
1462
|
-
|
|
1463
|
-
await
|
|
1464
|
-
openSession(sessionId);
|
|
2028
|
+
await refresh({ preserveCurrent: true });
|
|
2029
|
+
await invalidateWorktreeContext?.(pending.workspaceId);
|
|
1465
2030
|
} catch (error) {
|
|
2031
|
+
if (error instanceof WorktreeSessionBindingError && !error.retryable) setPendingSessionBinding(void 0);
|
|
1466
2032
|
setActionError(toWorktreeViewError(error));
|
|
1467
2033
|
} finally {
|
|
1468
2034
|
setActionPending(false);
|
|
@@ -1556,7 +2122,7 @@ window.__ModuleLoader__.load({
|
|
|
1556
2122
|
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
1557
2123
|
type: "button",
|
|
1558
2124
|
className: worktree_css_default.actionButton,
|
|
1559
|
-
disabled: actionPending,
|
|
2125
|
+
disabled: actionPending || pendingSessionArchived,
|
|
1560
2126
|
onClick: () => {
|
|
1561
2127
|
retrySessionBinding();
|
|
1562
2128
|
},
|
|
@@ -1612,14 +2178,17 @@ window.__ModuleLoader__.load({
|
|
|
1612
2178
|
children: t("workspace.noMatches")
|
|
1613
2179
|
}) : visibleWorkspaces.map((workspace) => {
|
|
1614
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 });
|
|
1615
2183
|
const expanded = expandedWorkspaces[workspace.workspaceId] !== false;
|
|
1616
2184
|
const workspaceMatchesQuery = includesText(workspace.title, query);
|
|
1617
2185
|
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
1618
2186
|
const bindings = view?.bindings ?? [];
|
|
1619
|
-
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));
|
|
1620
2188
|
const mainExpanded = expandedMains[workspace.workspaceId] !== false;
|
|
1621
2189
|
const mainGroupKey = `main:${workspace.workspaceId}`;
|
|
1622
2190
|
const worktrees = view?.worktrees ?? [];
|
|
2191
|
+
const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
|
|
1623
2192
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
1624
2193
|
className: worktree_css_default.workspaceGroup,
|
|
1625
2194
|
"data-workspace-id": workspace.workspaceId,
|
|
@@ -1682,7 +2251,7 @@ window.__ModuleLoader__.load({
|
|
|
1682
2251
|
(0, react_jsx_runtime.jsx)(WorktreeGroupRow, {
|
|
1683
2252
|
t,
|
|
1684
2253
|
kind: "main",
|
|
1685
|
-
label:
|
|
2254
|
+
label: mainLabel,
|
|
1686
2255
|
expanded: mainExpanded,
|
|
1687
2256
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
1688
2257
|
workspaceTitle: workspace.title,
|
|
@@ -1744,10 +2313,10 @@ window.__ModuleLoader__.load({
|
|
|
1744
2313
|
children: t("worktree.noWorktrees")
|
|
1745
2314
|
}),
|
|
1746
2315
|
worktrees.map((record) => {
|
|
1747
|
-
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);
|
|
1748
2317
|
const worktreeMatchesQuery = workspaceMatchesQuery || includesText(record.branch, query) || includesText(record.absolutePath, query);
|
|
1749
|
-
if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) =>
|
|
1750
|
-
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));
|
|
1751
2320
|
const worktreeGroupKey = `worktree:${record.worktreeId}`;
|
|
1752
2321
|
const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
|
|
1753
2322
|
const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
|
|
@@ -1759,6 +2328,7 @@ window.__ModuleLoader__.load({
|
|
|
1759
2328
|
t,
|
|
1760
2329
|
kind: "worktree",
|
|
1761
2330
|
label: record.branch,
|
|
2331
|
+
worktreeId: record.worktreeId,
|
|
1762
2332
|
expanded: worktreeExpanded,
|
|
1763
2333
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
1764
2334
|
workspaceTitle: workspace.title,
|
|
@@ -1767,7 +2337,7 @@ window.__ModuleLoader__.load({
|
|
|
1767
2337
|
onToggle: () => {
|
|
1768
2338
|
toggleWorktree(record.worktreeId);
|
|
1769
2339
|
},
|
|
1770
|
-
onCreateSession: record.status === "active" ? () => {
|
|
2340
|
+
onCreateSession: record.status === "active" && record.health !== "repair" ? () => {
|
|
1771
2341
|
createSession({
|
|
1772
2342
|
workspaceId: record.workspaceId,
|
|
1773
2343
|
worktreeId: record.worktreeId,
|
|
@@ -1785,7 +2355,39 @@ window.__ModuleLoader__.load({
|
|
|
1785
2355
|
setWorktreeRemoval(record);
|
|
1786
2356
|
setActionError(void 0);
|
|
1787
2357
|
}
|
|
1788
|
-
} : 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
|
+
}
|
|
1789
2391
|
}), worktreeExpanded && (0, react_jsx_runtime.jsx)(WorktreeSessionGroup, {
|
|
1790
2392
|
t,
|
|
1791
2393
|
groupKey: worktreeGroupKey,
|
|
@@ -1974,7 +2576,7 @@ window.__ModuleLoader__.load({
|
|
|
1974
2576
|
children: formatWorktreeViewError(workspaceDeleteError, t)
|
|
1975
2577
|
})
|
|
1976
2578
|
}),
|
|
1977
|
-
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, {
|
|
1978
2580
|
open: worktreeModalWorkspaceId !== void 0,
|
|
1979
2581
|
onClose: () => {
|
|
1980
2582
|
if (actionPending) return;
|
|
@@ -1998,48 +2600,50 @@ window.__ModuleLoader__.load({
|
|
|
1998
2600
|
},
|
|
1999
2601
|
children: t("worktree.create")
|
|
2000
2602
|
})] }),
|
|
2001
|
-
children: [
|
|
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
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
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
|
+
})
|
|
2043
2647
|
}),
|
|
2044
2648
|
worktreeRemoval !== void 0 && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
2045
2649
|
open: worktreeRemoval !== void 0,
|
|
@@ -2071,6 +2675,7 @@ window.__ModuleLoader__.load({
|
|
|
2071
2675
|
worktreeId: target.worktreeId
|
|
2072
2676
|
}
|
|
2073
2677
|
});
|
|
2678
|
+
await invalidateWorktreeContext?.(target.workspaceId);
|
|
2074
2679
|
setWorktreeRemoval(void 0);
|
|
2075
2680
|
});
|
|
2076
2681
|
},
|
|
@@ -2081,6 +2686,240 @@ window.__ModuleLoader__.load({
|
|
|
2081
2686
|
});
|
|
2082
2687
|
}
|
|
2083
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
|
|
2084
2923
|
//#region lib/client/view-mode-store.js
|
|
2085
2924
|
/** Create one root-scoped, browser-local view-mode store for the two slot entries. */
|
|
2086
2925
|
function createWorktreeViewStore() {
|
|
@@ -2122,17 +2961,24 @@ window.__ModuleLoader__.load({
|
|
|
2122
2961
|
let bindings = [];
|
|
2123
2962
|
let disposed = false;
|
|
2124
2963
|
let applying = false;
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2127
|
-
const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
|
|
2128
|
-
if (sameWorkspaceItems(current, next)) return;
|
|
2964
|
+
const nativeSet = list.set;
|
|
2965
|
+
const write = (next) => {
|
|
2129
2966
|
applying = true;
|
|
2130
2967
|
try {
|
|
2131
|
-
|
|
2968
|
+
nativeSet(next);
|
|
2132
2969
|
} finally {
|
|
2133
2970
|
applying = false;
|
|
2134
2971
|
}
|
|
2135
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
|
+
};
|
|
2136
2982
|
const replay = () => {
|
|
2137
2983
|
if (disposed || applying) return;
|
|
2138
2984
|
apply(bindings);
|
|
@@ -2160,6 +3006,7 @@ window.__ModuleLoader__.load({
|
|
|
2160
3006
|
bindings = [];
|
|
2161
3007
|
disposed = true;
|
|
2162
3008
|
unsubscribe();
|
|
3009
|
+
list.set = nativeSet;
|
|
2163
3010
|
}
|
|
2164
3011
|
};
|
|
2165
3012
|
}
|
|
@@ -2185,8 +3032,16 @@ window.__ModuleLoader__.load({
|
|
|
2185
3032
|
const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
|
|
2186
3033
|
const sessions = ctx.sessions;
|
|
2187
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
|
+
});
|
|
2188
3041
|
ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
|
|
2189
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();
|
|
2190
3045
|
const viewStore = createWorktreeViewStore();
|
|
2191
3046
|
const ensureSessionWorkspace = (workspaceId, sessionId) => {
|
|
2192
3047
|
virtualWorkspaceMembership.ensure({
|
|
@@ -2197,6 +3052,24 @@ window.__ModuleLoader__.load({
|
|
|
2197
3052
|
const syncSessionWorkspaces = (bindings) => {
|
|
2198
3053
|
virtualWorkspaceMembership.sync(bindings);
|
|
2199
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));
|
|
2200
3073
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
2201
3074
|
name: "sidebar.footer.action",
|
|
2202
3075
|
id: "clutch-dsh-worktree-mode-action",
|
|
@@ -2211,22 +3084,14 @@ window.__ModuleLoader__.load({
|
|
|
2211
3084
|
locale: WORKTREE_NS,
|
|
2212
3085
|
inject: () => ({
|
|
2213
3086
|
available: true,
|
|
3087
|
+
hooks: { worktreeContext: contextProjection.store },
|
|
2214
3088
|
manager,
|
|
2215
3089
|
createWorkspace: async () => {
|
|
2216
3090
|
const workspacePath = await ctx.workspaces.pickDirectory();
|
|
2217
3091
|
if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
|
|
2218
3092
|
},
|
|
2219
|
-
createSessionForWorktree: (input) =>
|
|
2220
|
-
|
|
2221
|
-
createSession: (sessionInput) => sessions.create(sessionInput),
|
|
2222
|
-
manager,
|
|
2223
|
-
beforeOpen: (sessionId) => {
|
|
2224
|
-
ensureSessionWorkspace(input.workspaceId, sessionId);
|
|
2225
|
-
},
|
|
2226
|
-
openSession: (sessionId) => {
|
|
2227
|
-
ctx.sessions.open(sessionId);
|
|
2228
|
-
}
|
|
2229
|
-
}),
|
|
3093
|
+
createSessionForWorktree: (input) => worktreeSessionConnector.create(input),
|
|
3094
|
+
invalidateWorktreeContext: (workspaceId) => contextProjection.invalidate(workspaceId),
|
|
2230
3095
|
createMainSession: (workspaceId) => {
|
|
2231
3096
|
ctx.workspaces.startSession(workspaceId);
|
|
2232
3097
|
},
|
|
@@ -2242,6 +3107,11 @@ window.__ModuleLoader__.load({
|
|
|
2242
3107
|
insertSessionBefore: async (workspaceId, sessionId, beforeSessionId) => {
|
|
2243
3108
|
await ctx.workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId);
|
|
2244
3109
|
},
|
|
3110
|
+
insertWorktreeBefore: (workspaceId, worktreeId, beforeWorktreeId) => manager.insertWorktreeBefore({
|
|
3111
|
+
workspaceId,
|
|
3112
|
+
worktreeId,
|
|
3113
|
+
beforeWorktreeId
|
|
3114
|
+
}),
|
|
2245
3115
|
renameSession: async (sessionId, title) => {
|
|
2246
3116
|
const session = ctx.sessions.binding(sessionId)?.session;
|
|
2247
3117
|
if (session === void 0) throw new Error(`unknown session "${sessionId}"`);
|
|
@@ -2263,7 +3133,7 @@ window.__ModuleLoader__.load({
|
|
|
2263
3133
|
ctx.sessions.open(sessionId);
|
|
2264
3134
|
}
|
|
2265
3135
|
})
|
|
2266
|
-
},
|
|
3136
|
+
}, WorktreeOverlay));
|
|
2267
3137
|
}
|
|
2268
3138
|
//#endregion
|
|
2269
3139
|
exports.WORKTREE_CONNECTION_CHANNEL = WORKTREE_CONNECTION_CHANNEL;
|