@cerbur/clutch-dsh-worktree 0.1.1 → 0.1.3

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