@cerbur/clutch-dsh-worktree 0.1.2 → 0.1.4

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 (143) hide show
  1. package/README.md +247 -92
  2. package/README.zh.md +297 -0
  3. package/lib/client/WorktreeContext.d.ts +15 -0
  4. package/lib/client/WorktreeContext.d.ts.map +1 -0
  5. package/lib/client/WorktreeContext.js +19 -0
  6. package/lib/client/WorktreeContext.js.map +1 -0
  7. package/lib/client/WorktreeHeroContext.d.ts +10 -0
  8. package/lib/client/WorktreeHeroContext.d.ts.map +1 -0
  9. package/lib/client/WorktreeHeroContext.js +128 -0
  10. package/lib/client/WorktreeHeroContext.js.map +1 -0
  11. package/lib/client/WorktreeOverlay.d.ts +6 -0
  12. package/lib/client/WorktreeOverlay.d.ts.map +1 -0
  13. package/lib/client/WorktreeOverlay.js +8 -0
  14. package/lib/client/WorktreeOverlay.js.map +1 -0
  15. package/lib/client/WorktreeSurface.d.ts +3 -29
  16. package/lib/client/WorktreeSurface.d.ts.map +1 -1
  17. package/lib/client/WorktreeSurface.js +170 -314
  18. package/lib/client/WorktreeSurface.js.map +1 -1
  19. package/lib/client/entry.d.ts +1 -1
  20. package/lib/client/entry.d.ts.map +1 -1
  21. package/lib/client/entry.js +41 -14
  22. package/lib/client/entry.js.map +1 -1
  23. package/lib/client/locales.d.ts +30 -0
  24. package/lib/client/locales.d.ts.map +1 -1
  25. package/lib/client/locales.js +32 -2
  26. package/lib/client/locales.js.map +1 -1
  27. package/lib/client/session-view.d.ts +21 -0
  28. package/lib/client/session-view.d.ts.map +1 -0
  29. package/lib/client/session-view.js +26 -0
  30. package/lib/client/session-view.js.map +1 -0
  31. package/lib/client/sidebar-overlay-geometry.d.ts +1 -0
  32. package/lib/client/sidebar-overlay-geometry.d.ts.map +1 -1
  33. package/lib/client/sidebar-overlay-geometry.js +28 -17
  34. package/lib/client/sidebar-overlay-geometry.js.map +1 -1
  35. package/lib/client/virtual-workspace-membership.d.ts.map +1 -1
  36. package/lib/client/virtual-workspace-membership.js +17 -6
  37. package/lib/client/virtual-workspace-membership.js.map +1 -1
  38. package/lib/client/worktree-connection.d.ts +1 -0
  39. package/lib/client/worktree-connection.d.ts.map +1 -1
  40. package/lib/client/worktree-connection.js +4 -0
  41. package/lib/client/worktree-connection.js.map +1 -1
  42. package/lib/client/worktree-context-store.d.ts +45 -0
  43. package/lib/client/worktree-context-store.d.ts.map +1 -0
  44. package/lib/client/worktree-context-store.js +199 -0
  45. package/lib/client/worktree-context-store.js.map +1 -0
  46. package/lib/client/worktree-context.d.ts +32 -0
  47. package/lib/client/worktree-context.d.ts.map +1 -0
  48. package/lib/client/worktree-context.js +51 -0
  49. package/lib/client/worktree-context.js.map +1 -0
  50. package/lib/client/worktree-error-copy.d.ts.map +1 -1
  51. package/lib/client/worktree-error-copy.js +14 -0
  52. package/lib/client/worktree-error-copy.js.map +1 -1
  53. package/lib/client/worktree-session.d.ts +83 -0
  54. package/lib/client/worktree-session.d.ts.map +1 -0
  55. package/lib/client/worktree-session.js +185 -0
  56. package/lib/client/worktree-session.js.map +1 -0
  57. package/lib/client/worktree-surface-dialogs.d.ts +7 -0
  58. package/lib/client/worktree-surface-dialogs.d.ts.map +1 -0
  59. package/lib/client/worktree-surface-dialogs.js +86 -0
  60. package/lib/client/worktree-surface-dialogs.js.map +1 -0
  61. package/lib/client/worktree-surface-rows.d.ts +9 -0
  62. package/lib/client/worktree-surface-rows.d.ts.map +1 -0
  63. package/lib/client/worktree-surface-rows.js +223 -0
  64. package/lib/client/worktree-surface-rows.js.map +1 -0
  65. package/lib/client/worktree-surface-selectors.d.ts +9 -0
  66. package/lib/client/worktree-surface-selectors.d.ts.map +1 -0
  67. package/lib/client/worktree-surface-selectors.js +28 -0
  68. package/lib/client/worktree-surface-selectors.js.map +1 -0
  69. package/lib/client/worktree-surface-types.d.ts +233 -0
  70. package/lib/client/worktree-surface-types.d.ts.map +1 -0
  71. package/lib/client/worktree-surface-types.js +2 -0
  72. package/lib/client/worktree-surface-types.js.map +1 -0
  73. package/lib/client/worktree-view-actions.d.ts +34 -0
  74. package/lib/client/worktree-view-actions.d.ts.map +1 -0
  75. package/lib/client/worktree-view-actions.js +69 -0
  76. package/lib/client/worktree-view-actions.js.map +1 -0
  77. package/lib/client/worktree-view-errors.d.ts +20 -0
  78. package/lib/client/worktree-view-errors.d.ts.map +1 -0
  79. package/lib/client/worktree-view-errors.js +65 -0
  80. package/lib/client/worktree-view-errors.js.map +1 -0
  81. package/lib/client/worktree-view-read.d.ts +48 -0
  82. package/lib/client/worktree-view-read.d.ts.map +1 -0
  83. package/lib/client/worktree-view-read.js +134 -0
  84. package/lib/client/worktree-view-read.js.map +1 -0
  85. package/lib/client/worktree-view.d.ts +4 -63
  86. package/lib/client/worktree-view.d.ts.map +1 -1
  87. package/lib/client/worktree-view.js +4 -125
  88. package/lib/client/worktree-view.js.map +1 -1
  89. package/lib/client.js +1313 -363
  90. package/lib/client.js.map +1 -1
  91. package/lib/contract/index.contract.js +2 -0
  92. package/lib/contract/index.contract.js.map +1 -1
  93. package/lib/contract/index.d.ts +17 -2
  94. package/lib/contract/index.d.ts.map +1 -1
  95. package/lib/contract/index.js +2 -0
  96. package/lib/contract/index.js.map +1 -1
  97. package/lib/host/remote.d.ts.map +1 -1
  98. package/lib/host/remote.js +1 -0
  99. package/lib/host/remote.js.map +1 -1
  100. package/lib/host/service.d.ts +6 -1
  101. package/lib/host/service.d.ts.map +1 -1
  102. package/lib/host/service.js +6 -0
  103. package/lib/host/service.js.map +1 -1
  104. package/lib/manage/manager-context.d.ts +11 -0
  105. package/lib/manage/manager-context.d.ts.map +1 -0
  106. package/lib/manage/manager-context.js +2 -0
  107. package/lib/manage/manager-context.js.map +1 -0
  108. package/lib/manage/manager-sessions.d.ts +18 -0
  109. package/lib/manage/manager-sessions.d.ts.map +1 -0
  110. package/lib/manage/manager-sessions.js +91 -0
  111. package/lib/manage/manager-sessions.js.map +1 -0
  112. package/lib/manage/manager-support.d.ts +18 -0
  113. package/lib/manage/manager-support.d.ts.map +1 -0
  114. package/lib/manage/manager-support.js +174 -0
  115. package/lib/manage/manager-support.js.map +1 -0
  116. package/lib/manage/manager-worktrees.d.ts +27 -0
  117. package/lib/manage/manager-worktrees.d.ts.map +1 -0
  118. package/lib/manage/manager-worktrees.js +259 -0
  119. package/lib/manage/manager-worktrees.js.map +1 -0
  120. package/lib/manage/manager.d.ts +25 -62
  121. package/lib/manage/manager.d.ts.map +1 -1
  122. package/lib/manage/manager.js +32 -554
  123. package/lib/manage/manager.js.map +1 -1
  124. package/lib/provider/sidecar-persistence.d.ts +18 -0
  125. package/lib/provider/sidecar-persistence.d.ts.map +1 -0
  126. package/lib/provider/sidecar-persistence.js +162 -0
  127. package/lib/provider/sidecar-persistence.js.map +1 -0
  128. package/lib/provider/sidecar-schema.d.ts +6 -0
  129. package/lib/provider/sidecar-schema.d.ts.map +1 -0
  130. package/lib/provider/sidecar-schema.js +123 -0
  131. package/lib/provider/sidecar-schema.js.map +1 -0
  132. package/lib/provider/sidecar.d.ts +12 -68
  133. package/lib/provider/sidecar.d.ts.map +1 -1
  134. package/lib/provider/sidecar.js +61 -346
  135. package/lib/provider/sidecar.js.map +1 -1
  136. package/lib/provider/types.d.ts +2 -1
  137. package/lib/provider/types.d.ts.map +1 -1
  138. package/lib/provider/types.js.map +1 -1
  139. package/lib/typert.host.js +60 -18
  140. package/lib/typert.remote-client.d.ts +3 -1
  141. package/lib/typert.remote-client.d.ts.map +1 -1
  142. package/lib/typert.remote-client.js +60 -18
  143. 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: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 24px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeGuide {\n flex: none;\n width: 20px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
369
+ const css = ".-cerbur-clutch-dsh-worktree-action {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n width: calc(100% + 4px);\n height: 42px;\n margin: 4px -2px;\n box-sizing: border-box;\n border: 0;\n border-radius: 12px;\n padding: 0 10px 0 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n text-align: left;\n overflow: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-action:hover,\n.-cerbur-clutch-dsh-worktree-action[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-action[data-collapsed='true'] {\n width: 36px;\n height: 36px;\n margin: 8px 0 10px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border-radius: 50%;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n overflow: hidden;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-surface {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n min-width: 56px;\n overflow: hidden;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-specific-sidebar-fill);\n color: var(--dsw-alias-label-primary);\n pointer-events: auto;\n transition: width var(--ds-transition-duration-slow) var(--ds-ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .-cerbur-clutch-dsh-worktree-surface {\n transition: none;\n }\n}\n\n.-cerbur-clutch-dsh-worktree-wideContent {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-wideContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-railContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-railContent {\n display: flex;\n flex: 1;\n align-items: flex-start;\n justify-content: center;\n padding-top: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton,\n.-cerbur-clutch-dsh-worktree-closeButton {\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton {\n width: 36px;\n height: 36px;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-railButton:hover,\n.-cerbur-clutch-dsh-worktree-closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: none;\n min-height: 44px;\n padding: 6px 10px;\n box-sizing: border-box;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-title {\n min-width: 0;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n flex: none;\n width: 28px;\n height: 28px;\n font-size: 18px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-modeButton[data-active='true'] {\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspacePicker {\n display: block;\n width: calc(100% - 20px);\n margin: 6px 10px 8px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceLabel {\n display: block;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n padding: 0 10px 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-content:focus-visible {\n outline: 2px solid var(--dsw-alias-border-l3);\n outline-offset: -2px;\n}\n\n.-cerbur-clutch-dsh-worktree-error {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n width: 100%;\n padding: 6px 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-recoveryActions {\n display: grid;\n gap: 6px;\n margin-top: 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton:disabled,\n.-cerbur-clutch-dsh-worktree-actionButton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.-cerbur-clutch-dsh-worktree-actions {\n display: grid;\n gap: 6px;\n margin-top: 10px;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n display: grid;\n gap: 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionSelect {\n min-width: 0;\n padding: 5px 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-section {\n margin: 12px 0 0;\n}\n\n.-cerbur-clutch-dsh-worktree-sectionTitle {\n margin: 0 2px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-empty,\n.-cerbur-clutch-dsh-worktree-message {\n margin: 0;\n padding: 8px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-gitReadiness {\n display: grid;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-commandBlock {\n margin: 6px 0 0;\n padding: 8px;\n overflow-x: auto;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-secondary);\n font: 11px/16px ui-monospace, SFMono-Regular, Menlo, monospace;\n white-space: pre-wrap;\n}\n\n.-cerbur-clutch-dsh-worktree-message[data-error='true'] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktree,\n.-cerbur-clutch-dsh-worktree-session {\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 6px 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree {\n cursor: default;\n}\n\n.-cerbur-clutch-dsh-worktree-session {\n cursor: pointer;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree:hover,\n.-cerbur-clutch-dsh-worktree-session:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeLabel,\n.-cerbur-clutch-dsh-worktree-sessionLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-status {\n flex: none;\n margin-left: auto;\n padding-left: 8px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchRow {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchIcon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n min-width: 0;\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n outline: none;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n width: 100%;\n padding: 6px 8px;\n font-size: 13px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput:focus,\n.-cerbur-clutch-dsh-worktree-actionSelect:focus {\n border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 24px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeGuide {\n flex: none;\n width: 20px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
291
370
  const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
292
371
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
293
372
  const tag = document.createElement("style");
@@ -320,6 +399,8 @@ window.__ModuleLoader__.load({
320
399
  "sectionTitle": "-cerbur-clutch-dsh-worktree-sectionTitle",
321
400
  "empty": "-cerbur-clutch-dsh-worktree-empty",
322
401
  "message": "-cerbur-clutch-dsh-worktree-message",
402
+ "gitReadiness": "-cerbur-clutch-dsh-worktree-gitReadiness",
403
+ "commandBlock": "-cerbur-clutch-dsh-worktree-commandBlock",
323
404
  "worktree": "-cerbur-clutch-dsh-worktree-worktree",
324
405
  "session": "-cerbur-clutch-dsh-worktree-session",
325
406
  "worktreeLabel": "-cerbur-clutch-dsh-worktree-worktreeLabel",
@@ -385,6 +466,104 @@ window.__ModuleLoader__.load({
385
466
  });
386
467
  }
387
468
  //#endregion
469
+ //#region lib/client/WorktreeHeroContext.js
470
+ function labelFor(state) {
471
+ if (state.status !== "ready" || state.workspaceTitle === void 0 || state.value.kind === "none") return;
472
+ return `${state.workspaceTitle} (${state.value.label})`;
473
+ }
474
+ function elementWithClassSuffix(root, suffix) {
475
+ const candidates = root.querySelectorAll("[class]");
476
+ for (const candidate of candidates) if ([...candidate.classList].some((token) => token === suffix || token.endsWith(`_${suffix}`))) return candidate;
477
+ return null;
478
+ }
479
+ function headlineElement(root) {
480
+ return elementWithClassSuffix(root, "previewBadge") ?? elementWithClassSuffix(root, "headlineText") ?? elementWithClassSuffix(root, "headline");
481
+ }
482
+ function positionedAncestor(element) {
483
+ if (element.offsetParent instanceof HTMLElement) return element.offsetParent;
484
+ for (let ancestor = element.parentElement; ancestor !== null; ancestor = ancestor.parentElement) if (getComputedStyle(ancestor).position !== "static") return ancestor;
485
+ return null;
486
+ }
487
+ function measurePlacement(element) {
488
+ const hero = document.querySelector("[data-phase=\"hero\"]");
489
+ const overlay = positionedAncestor(element);
490
+ const headline = hero === null ? null : headlineElement(hero);
491
+ if (hero === null || headline === null || overlay === null) return null;
492
+ const anchor = headline.getBoundingClientRect();
493
+ const frame = overlay.getBoundingClientRect();
494
+ const width = element.getBoundingClientRect().width;
495
+ const afterHeadlineLeft = anchor.right - frame.left + 8;
496
+ const fitsAfterHeadline = afterHeadlineLeft + width <= frame.width - 8;
497
+ return {
498
+ left: fitsAfterHeadline ? afterHeadlineLeft : Math.max(8, frame.width - width - 8),
499
+ top: fitsAfterHeadline ? Math.max(8, anchor.top - frame.top + (anchor.height - 22) / 2) : Math.max(8, anchor.bottom - frame.top + 8)
500
+ };
501
+ }
502
+ function contextAriaLabel(state, t) {
503
+ if (state.value.kind === "main") return t("context.main", { name: state.value.label });
504
+ if (state.value.kind === "worktree") return t("context.worktree", { name: state.value.label });
505
+ }
506
+ /**
507
+ * Browser-local Hero suffix. It intentionally uses the frame overlay because
508
+ * rc.8 exposes no additive slot beside the native Hero headline.
509
+ */
510
+ function WorktreeHeroContext({ useWorktreeContext, t }) {
511
+ const state = useWorktreeContext((snapshot) => snapshot);
512
+ const label = labelFor(state);
513
+ const [placement, setPlacement] = (0, react.useState)(null);
514
+ const measure = (0, react.useCallback)((element) => {
515
+ if (element === null) {
516
+ setPlacement(null);
517
+ return;
518
+ }
519
+ setPlacement(measurePlacement(element));
520
+ }, []);
521
+ (0, react.useLayoutEffect)(() => {
522
+ if (typeof document === "undefined" || typeof window === "undefined") return void 0;
523
+ const element = document.querySelector("[data-worktree-hero-context]");
524
+ if (element === null) return void 0;
525
+ let frameRequest;
526
+ const schedule = () => {
527
+ if (frameRequest !== void 0) window.cancelAnimationFrame(frameRequest);
528
+ frameRequest = window.requestAnimationFrame(() => {
529
+ frameRequest = void 0;
530
+ measure(element);
531
+ });
532
+ };
533
+ const mutationObserver = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(schedule);
534
+ mutationObserver?.observe(document.body, {
535
+ subtree: true,
536
+ childList: true,
537
+ attributes: true,
538
+ attributeFilter: ["class", "data-phase"]
539
+ });
540
+ const resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(schedule);
541
+ resizeObserver?.observe(positionedAncestor(element) ?? element);
542
+ window.addEventListener("resize", schedule);
543
+ schedule();
544
+ return () => {
545
+ if (frameRequest !== void 0) window.cancelAnimationFrame(frameRequest);
546
+ mutationObserver?.disconnect();
547
+ resizeObserver?.disconnect();
548
+ window.removeEventListener("resize", schedule);
549
+ };
550
+ }, [label, measure]);
551
+ const ariaLabel = contextAriaLabel(state, t);
552
+ if (label === void 0) return null;
553
+ return (0, react_jsx_runtime.jsx)("span", {
554
+ ref: measure,
555
+ className: worktree_context_css_default.heroContext,
556
+ "data-worktree-hero-context": true,
557
+ "aria-label": ariaLabel,
558
+ title: label,
559
+ style: placement === null ? { visibility: "hidden" } : {
560
+ left: `${placement.left}px`,
561
+ top: `${placement.top}px`
562
+ },
563
+ children: label
564
+ });
565
+ }
566
+ //#endregion
388
567
  //#region lib/client/navigation.js
389
568
  /** Open an existing Session through DSH without touching the peer view mode. */
390
569
  function openWorktreeSession(opener, sessionId) {
@@ -419,6 +598,13 @@ window.__ModuleLoader__.load({
419
598
  bottom: rect.bottom
420
599
  };
421
600
  }
601
+ function syncObservedElement(observer, previous, next) {
602
+ const nextElement = next ?? void 0;
603
+ if (previous === nextElement) return previous;
604
+ if (previous !== void 0) observer?.unobserve(previous);
605
+ if (nextElement !== void 0) observer?.observe(nextElement);
606
+ return nextElement;
607
+ }
422
608
  function resolveNativeSidebarRoot(sidebar) {
423
609
  const directChild = sidebar.firstElementChild;
424
610
  if (directChild === null) return void 0;
@@ -460,34 +646,37 @@ window.__ModuleLoader__.load({
460
646
  setBounds(EMPTY_BOUNDS);
461
647
  return;
462
648
  }
649
+ const overlayElement = overlay;
650
+ const sidebarElement = sidebar;
651
+ const nativeRootElement = nativeRoot;
463
652
  let frameHandle;
464
- const update = () => {
465
- const newSession = findNewSessionAnchor(nativeRoot);
466
- const footer = nativeRoot.lastElementChild;
467
- 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;
468
661
  if (nextWidth > 0) setWidth(nextWidth);
469
- setBounds(computeOverlayBounds(asRect(overlay), newSession === void 0 ? void 0 : asRect(newSession), footer === null ? void 0 : asRect(footer)));
470
- };
471
- const scheduleUpdate = () => {
662
+ setBounds(computeOverlayBounds(asRect(overlayElement), newSession === void 0 ? void 0 : asRect(newSession), footer === null ? void 0 : asRect(footer)));
663
+ }
664
+ function scheduleUpdate() {
472
665
  if (frameHandle !== void 0) return;
473
666
  frameHandle = requestAnimationFrame(() => {
474
667
  frameHandle = void 0;
475
668
  update();
476
669
  });
477
- };
478
- update();
670
+ }
479
671
  const resizeObserver = typeof ResizeObserver === "function" ? new ResizeObserver(scheduleUpdate) : void 0;
480
672
  for (const element of [
481
- overlay,
482
- sidebar,
483
- nativeRoot
673
+ overlayElement,
674
+ sidebarElement,
675
+ nativeRootElement
484
676
  ]) resizeObserver?.observe(element);
485
- const newSession = findNewSessionAnchor(nativeRoot);
486
- const footer = nativeRoot.lastElementChild;
487
- if (newSession !== void 0) resizeObserver?.observe(newSession);
488
- if (footer !== null) resizeObserver?.observe(footer);
677
+ update();
489
678
  const mutationObserver = typeof MutationObserver === "function" ? new MutationObserver(scheduleUpdate) : void 0;
490
- mutationObserver?.observe(nativeRoot, {
679
+ mutationObserver?.observe(nativeRootElement, {
491
680
  childList: true,
492
681
  subtree: true
493
682
  });
@@ -576,6 +765,7 @@ window.__ModuleLoader__.load({
576
765
  case "WORKTREE_RPC_INVALID_RESULT": return t("error.invalidResult", { endpoint: detail(error, "endpoint") });
577
766
  case "WORKSPACE_ORDER_UNAVAILABLE": return t("error.workspaceOrderingUnavailable");
578
767
  case "SESSION_ORDER_UNAVAILABLE": return t("error.sessionOrderingUnavailable");
768
+ case "WORKTREE_ORDER_UNAVAILABLE": return t("error.worktreeOrderingUnavailable");
579
769
  case "SESSION_CREATE_UNAVAILABLE": return t("error.sessionCreationUnavailable");
580
770
  case "WORKTREE_CREATED_SESSION_UNAVAILABLE": return t("error.worktreeCreatedSessionUnavailable");
581
771
  case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
@@ -586,35 +776,98 @@ window.__ModuleLoader__.load({
586
776
  sessionId: detail(error, "sessionId"),
587
777
  reason: reason(error, t)
588
778
  });
779
+ case "SESSION_ALREADY_BOUND": return t("error.sessionAlreadyBound");
780
+ case "SESSION_LIST_NOT_READY": return t("error.sessionListNotReady");
781
+ case "SESSION_FACTS_INCOMPLETE": return t("error.sessionFactsIncomplete");
782
+ case "WORKTREE_SESSION_REPAIR_REQUIRED": return t("error.worktreeSessionRepairRequired");
783
+ case "WORKTREE_SESSION_UNAVAILABLE": return t("error.worktreeSessionUnavailable");
784
+ case "SESSION_ARCHIVED": return t("error.sessionArchived");
589
785
  default: return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
590
786
  }
591
787
  }
592
788
  //#endregion
593
- //#region lib/client/worktree-view.js
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
814
+ //#region lib/client/worktree-view-errors.js
594
815
  /** A DSH Session exists even when the external Worktree binding needs repair. */
595
816
  var WorktreeSessionBindingError = class extends Error {
596
- code = "SESSION_BINDING_FAILED";
597
- retryable = true;
817
+ code;
818
+ retryable;
819
+ details;
598
820
  sessionId;
599
821
  cause;
600
822
  constructor(sessionId, cause) {
601
- 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);
602
825
  super(reason);
603
826
  this.name = "WorktreeSessionBindingError";
827
+ const conflict = candidate?.code === "SESSION_ALREADY_BOUND";
828
+ this.code = conflict ? "SESSION_ALREADY_BOUND" : "SESSION_BINDING_FAILED";
829
+ this.retryable = conflict ? false : candidate?.retryable !== false;
830
+ this.details = typeof candidate?.details === "object" && candidate.details !== null && !Array.isArray(candidate.details) ? candidate.details : {};
604
831
  this.sessionId = sessionId;
605
832
  this.cause = cause;
606
833
  }
607
834
  };
608
- /** Reuse the previous ID snapshot when DSH republishes equivalent Workspace items. */
609
- function stableWorkspaceIds(previous, next) {
610
- if (previous.length !== next.length) return next;
611
- for (let index = 0; index < previous.length; index += 1) if (previous[index] !== next[index]) return next;
612
- return previous;
835
+ function recordDetails(value) {
836
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
837
+ const details = value.details;
838
+ if (typeof details !== "object" || details === null || Array.isArray(details)) return void 0;
839
+ return details;
613
840
  }
614
- /** Prefer the branch checked out by the DSH Workspace, then fall back to any local branch. */
615
- function selectDefaultBaseBranch(branches) {
616
- return branches.find((branch) => branch.isCurrent)?.name ?? branches[0]?.name ?? "";
841
+ /** Convert any adapter/Gateway failure into renderable, retry-aware UI data. */
842
+ function toWorktreeViewError(error) {
843
+ if (typeof error === "object" && error !== null) {
844
+ const candidate = error;
845
+ const details = error instanceof WorktreeSessionBindingError ? {
846
+ ...recordDetails(error) ?? {},
847
+ sessionId: error.sessionId
848
+ } : recordDetails(error);
849
+ return {
850
+ code: typeof candidate.code === "string" ? candidate.code : "WORKTREE_VIEW_FAILED",
851
+ message: typeof candidate.message === "string" ? candidate.message : "",
852
+ retryable: candidate.retryable !== false,
853
+ ...details === void 0 ? {} : { details }
854
+ };
855
+ }
856
+ return {
857
+ code: "WORKTREE_VIEW_FAILED",
858
+ message: "",
859
+ retryable: true
860
+ };
861
+ }
862
+ /** Keep ordering mutation/refresh failures reachable from the surface Retry control. */
863
+ function toRetryableWorktreeOrderError(error) {
864
+ return {
865
+ ...toWorktreeViewError(error),
866
+ retryable: true
867
+ };
617
868
  }
869
+ //#endregion
870
+ //#region lib/client/worktree-view-actions.js
618
871
  function browserRandomUuid() {
619
872
  const randomUUID = globalThis.crypto?.randomUUID;
620
873
  if (typeof randomUUID === "function") return randomUUID.call(globalThis.crypto);
@@ -631,29 +884,16 @@ window.__ModuleLoader__.load({
631
884
  }
632
885
  throw new Error("Unable to generate an available default Worktree name.");
633
886
  }
634
- /** Hide DSH-archived Sessions from the browser-local Worktree projection. */
635
- function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
636
- return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
637
- }
638
- /** Read all three Worktree projections needed by the surface in one refresh. */
639
- async function loadWorktreeView(manager, workspaceId) {
640
- const [worktrees, branches, bindings] = await Promise.all([
641
- manager.listWorktrees({ workspaceId }),
642
- manager.listBranches({ workspaceId }),
643
- manager.listBindings({ workspaceId })
644
- ]);
645
- return {
646
- worktrees,
647
- branches,
648
- bindings
649
- };
650
- }
651
- /** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
652
- async function loadWorktreeViews(manager, workspaceIds) {
653
- return Promise.all(workspaceIds.map(async (workspaceId) => ({
654
- workspaceId,
655
- ...await loadWorktreeView(manager, workspaceId)
656
- })));
887
+ /** Resolve a row-half drop target to native-style optional before-anchor semantics. */
888
+ function resolveWorktreeMove(worktreeIds, sourceWorktreeId, targetWorktreeId, half) {
889
+ const sourceIndex = worktreeIds.indexOf(sourceWorktreeId);
890
+ const targetIndex = worktreeIds.indexOf(targetWorktreeId);
891
+ if (sourceIndex === -1 || targetIndex === -1) return void 0;
892
+ const beforeWorktreeId = half === "before" ? targetWorktreeId : worktreeIds[targetIndex + 1];
893
+ if (beforeWorktreeId === sourceWorktreeId) return void 0;
894
+ const anchorIndex = beforeWorktreeId === void 0 ? worktreeIds.length : worktreeIds.indexOf(beforeWorktreeId);
895
+ if (anchorIndex === sourceIndex || anchorIndex === sourceIndex + 1) return void 0;
896
+ return beforeWorktreeId === void 0 ? {} : { beforeWorktreeId };
657
897
  }
658
898
  /** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
659
899
  async function executeWorktreeAction(manager, action) {
@@ -682,60 +922,507 @@ window.__ModuleLoader__.load({
682
922
  input.openSession(sessionId);
683
923
  return sessionId;
684
924
  }
685
- function recordDetails(value) {
686
- if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
687
- const details = value.details;
688
- if (typeof details !== "object" || details === null || Array.isArray(details)) return void 0;
689
- return details;
925
+ //#endregion
926
+ //#region lib/client/worktree-view-read.js
927
+ /** Reuse the previous ID snapshot when DSH republishes equivalent Workspace items. */
928
+ function stableWorkspaceIds(previous, next) {
929
+ if (previous.length !== next.length) return next;
930
+ for (let index = 0; index < previous.length; index += 1) if (previous[index] !== next[index]) return next;
931
+ return previous;
690
932
  }
691
- /** Convert any adapter/Gateway failure into renderable, retry-aware UI data. */
692
- function toWorktreeViewError(error) {
693
- if (typeof error === "object" && error !== null) {
694
- const candidate = error;
695
- const details = error instanceof WorktreeSessionBindingError ? {
696
- ...recordDetails(error) ?? {},
697
- sessionId: error.sessionId
698
- } : recordDetails(error);
699
- return {
700
- code: typeof candidate.code === "string" ? candidate.code : "WORKTREE_VIEW_FAILED",
701
- message: typeof candidate.message === "string" ? candidate.message : "",
702
- retryable: candidate.retryable !== false,
703
- ...details === void 0 ? {} : { details }
933
+ /** Keep only the most recently started Worktree surface refresh authoritative. */
934
+ function createWorktreeRefreshGuard() {
935
+ let latestGeneration = 0;
936
+ const begin = () => {
937
+ latestGeneration += 1;
938
+ return latestGeneration;
939
+ };
940
+ const isCurrent = (generation) => generation === latestGeneration;
941
+ const invalidate = () => {
942
+ latestGeneration += 1;
943
+ };
944
+ return {
945
+ begin,
946
+ isCurrent,
947
+ invalidate,
948
+ async run(load, onSuccess, onError) {
949
+ const generation = begin();
950
+ let value;
951
+ try {
952
+ value = await load();
953
+ } catch (error) {
954
+ if (!isCurrent(generation)) return;
955
+ onError(error);
956
+ return;
957
+ }
958
+ if (!isCurrent(generation)) return;
959
+ onSuccess(value);
960
+ }
961
+ };
962
+ }
963
+ /** Prefer the branch checked out by the DSH Workspace, then fall back to any local branch. */
964
+ function selectDefaultBaseBranch(branches) {
965
+ return branches.find((branch) => branch.isCurrent)?.name ?? branches[0]?.name ?? "";
966
+ }
967
+ /** Keep a valid user choice across branch-list refreshes, otherwise choose the current branch. */
968
+ function reconcileBaseBranchSelection(selectedBranch, branches) {
969
+ if (branches.some((branch) => branch.name === selectedBranch)) return selectedBranch;
970
+ return selectDefaultBaseBranch(branches);
971
+ }
972
+ /** Return copyable, read-only setup commands for a Git readiness state. */
973
+ function worktreeSetupCommands(status) {
974
+ switch (status) {
975
+ case "noRepository": return [
976
+ "git init",
977
+ "printf \"# README\\n\" > README.md",
978
+ "git add README.md",
979
+ "git commit -m \"Initial commit\""
980
+ ];
981
+ case "noInitialCommit": return [
982
+ "printf \"# README\\n\" > README.md",
983
+ "git add README.md",
984
+ "git commit -m \"Initial commit\""
985
+ ];
986
+ case "noLocalBranch": return ["git switch -c main"];
987
+ case "ready": return [];
988
+ }
989
+ }
990
+ function readinessFromBranchError(error) {
991
+ const viewError = toWorktreeViewError(error);
992
+ if (viewError.code === "WORKSPACE_NOT_GIT_REPOSITORY") return {
993
+ status: "noRepository",
994
+ error: viewError
995
+ };
996
+ if (viewError.code === "WORKTREE_REQUIRES_INITIAL_COMMIT") return {
997
+ status: "noInitialCommit",
998
+ error: viewError
999
+ };
1000
+ }
1001
+ /** Read all three Worktree projections needed by the surface in one refresh. */
1002
+ async function loadWorktreeView(manager, workspaceId) {
1003
+ const [worktreesResult, branchesResult, bindingsResult] = await Promise.allSettled([
1004
+ manager.listWorktrees({ workspaceId }),
1005
+ manager.listBranches({ workspaceId }),
1006
+ manager.listBindings({ workspaceId })
1007
+ ]);
1008
+ if (worktreesResult.status === "rejected") throw worktreesResult.reason;
1009
+ if (bindingsResult.status === "rejected") throw bindingsResult.reason;
1010
+ if (branchesResult.status === "rejected") {
1011
+ const readiness = readinessFromBranchError(branchesResult.reason);
1012
+ if (readiness !== void 0) return {
1013
+ worktrees: worktreesResult.value,
1014
+ branches: [],
1015
+ bindings: bindingsResult.value,
1016
+ readiness
704
1017
  };
1018
+ throw branchesResult.reason;
705
1019
  }
706
1020
  return {
707
- code: "WORKTREE_VIEW_FAILED",
708
- message: "",
709
- retryable: true
1021
+ worktrees: worktreesResult.value,
1022
+ branches: branchesResult.value,
1023
+ bindings: bindingsResult.value,
1024
+ readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
710
1025
  };
711
1026
  }
1027
+ /** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
1028
+ async function loadWorktreeViews(manager, workspaceIds, options = {}) {
1029
+ const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
1030
+ workspaceId,
1031
+ ...await loadWorktreeView(manager, workspaceId)
1032
+ })));
1033
+ if (options.invalidateContext !== false) await options.invalidateWorktreeContext?.();
1034
+ return views;
1035
+ }
1036
+ /** Hide DSH-archived Sessions from the browser-local Worktree projection. */
1037
+ function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
1038
+ return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
1039
+ }
712
1040
  //#endregion
713
- //#region lib/client/WorktreeSurface.js
714
- function toNativeWorktreeViewError(error) {
715
- const viewError = toWorktreeViewError(error);
716
- if (typeof error === "object" && error !== null) return viewError;
1041
+ //#region lib/client/worktree-session.js
1042
+ var WorktreeSessionActionError = class extends Error {
1043
+ code;
1044
+ retryable;
1045
+ details;
1046
+ constructor(code, message, retryable, details = {}) {
1047
+ super(message);
1048
+ this.code = code;
1049
+ this.retryable = retryable;
1050
+ this.name = "WorktreeSessionActionError";
1051
+ this.details = details;
1052
+ }
1053
+ };
1054
+ function resolveWorktreeSessionAction(input) {
1055
+ if (input.target.status !== "active" || input.target.health === "repair") return {
1056
+ kind: "reject",
1057
+ reason: "worktree-not-available"
1058
+ };
1059
+ if (input.sessions.phase !== "ready") return {
1060
+ kind: "wait",
1061
+ reason: "sessions-not-ready"
1062
+ };
1063
+ const targetBinding = input.bindings.find((binding) => binding.worktreeId === input.target.worktreeId && binding.status === "active");
1064
+ if (targetBinding !== void 0) {
1065
+ const summary = input.sessions.byId[targetBinding.sessionId];
1066
+ if (summary === void 0) return {
1067
+ kind: "repair",
1068
+ reason: "active-binding-session-missing",
1069
+ sessionId: targetBinding.sessionId
1070
+ };
1071
+ if (summary.cwd !== input.target.absolutePath) return {
1072
+ kind: "repair",
1073
+ reason: "active-binding-cwd-mismatch",
1074
+ sessionId: targetBinding.sessionId
1075
+ };
1076
+ if (summary.blank === true && !input.archivedSessionIds.includes(targetBinding.sessionId)) return {
1077
+ kind: "open-bound",
1078
+ sessionId: targetBinding.sessionId
1079
+ };
1080
+ }
1081
+ for (const sessionId of input.sessions.ids) {
1082
+ const summary = input.sessions.byId[sessionId];
1083
+ if (summary === void 0 || summary.blank === void 0 || summary.blank === true && summary.cwd === void 0) return {
1084
+ kind: "wait",
1085
+ reason: "session-facts-incomplete"
1086
+ };
1087
+ }
1088
+ for (const sessionId of input.sessions.ids) {
1089
+ const summary = input.sessions.byId[sessionId];
1090
+ if (summary?.blank !== true || summary.cwd !== input.target.absolutePath || input.archivedSessionIds.includes(sessionId)) continue;
1091
+ if (!input.bindings.some((binding) => binding.sessionId === sessionId)) return {
1092
+ kind: "bind-existing",
1093
+ sessionId
1094
+ };
1095
+ }
1096
+ return { kind: "create" };
1097
+ }
1098
+ function actionError(action) {
1099
+ switch (action.kind) {
1100
+ case "wait": return new WorktreeSessionActionError(action.reason === "sessions-not-ready" ? "SESSION_LIST_NOT_READY" : "SESSION_FACTS_INCOMPLETE", "", true);
1101
+ case "repair": return new WorktreeSessionActionError("WORKTREE_SESSION_REPAIR_REQUIRED", action.reason, true, { ...action.sessionId === void 0 ? {} : { sessionId: action.sessionId } });
1102
+ case "reject": return new WorktreeSessionActionError("WORKTREE_SESSION_UNAVAILABLE", action.reason, false);
1103
+ default: return new WorktreeSessionActionError("WORKTREE_SESSION_ACTION_FAILED", "", true);
1104
+ }
1105
+ }
1106
+ async function retryWorktreeSessionBinding(input) {
1107
+ if (input.archived) throw new WorktreeSessionActionError("SESSION_ARCHIVED", "", false, { sessionId: input.pending.sessionId });
1108
+ try {
1109
+ await input.manager.bindSession({
1110
+ workspaceId: input.pending.workspaceId,
1111
+ worktreeId: input.pending.worktreeId,
1112
+ sessionId: input.pending.sessionId
1113
+ });
1114
+ } catch (error) {
1115
+ throw new WorktreeSessionBindingError(input.pending.sessionId, error);
1116
+ }
1117
+ input.ensureSessionWorkspace(input.pending.workspaceId, input.pending.sessionId);
1118
+ input.openSession(input.pending.sessionId);
1119
+ return input.pending.sessionId;
1120
+ }
1121
+ /**
1122
+ * Browser-only Worktree `+` connector. It owns the read/resolve/bind/create/open
1123
+ * sequence and coalesces repeated calls for one Worktree within one Client fiber.
1124
+ */
1125
+ function createWorktreeSessionConnector(options) {
1126
+ const inFlight = /* @__PURE__ */ new Map();
1127
+ let disposed = false;
1128
+ const run = async (input) => {
1129
+ const [worktrees, bindings] = await Promise.all([options.manager.listWorktrees({ workspaceId: input.workspaceId }), options.manager.listBindings({ workspaceId: input.workspaceId })]);
1130
+ if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
1131
+ const target = worktrees.find((record) => record.worktreeId === input.worktreeId);
1132
+ if (target === void 0 || target.absolutePath !== input.cwd) throw new WorktreeSessionActionError("WORKTREE_SESSION_REPAIR_REQUIRED", "worktree target unavailable", true);
1133
+ const action = resolveWorktreeSessionAction({
1134
+ target,
1135
+ sessions: options.sessions.getSnapshot(),
1136
+ archivedSessionIds: options.archivedSessionIds(),
1137
+ bindings
1138
+ });
1139
+ if (action.kind === "open-bound") {
1140
+ options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
1141
+ if (!disposed) options.openSession(action.sessionId);
1142
+ return action.sessionId;
1143
+ }
1144
+ if (action.kind === "bind-existing") {
1145
+ try {
1146
+ await options.manager.bindSession({
1147
+ workspaceId: input.workspaceId,
1148
+ worktreeId: input.worktreeId,
1149
+ sessionId: action.sessionId
1150
+ });
1151
+ } catch (error) {
1152
+ throw new WorktreeSessionBindingError(action.sessionId, error);
1153
+ }
1154
+ if (!disposed) {
1155
+ options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
1156
+ if (!disposed) options.openSession(action.sessionId);
1157
+ }
1158
+ return action.sessionId;
1159
+ }
1160
+ if (action.kind !== "create") throw actionError(action);
1161
+ if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
1162
+ return createSessionForWorktree({
1163
+ ...input,
1164
+ createSession: options.createSession,
1165
+ manager: options.manager,
1166
+ beforeOpen: (sessionId) => {
1167
+ if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
1168
+ options.ensureSessionWorkspace(input.workspaceId, sessionId);
1169
+ },
1170
+ openSession: (sessionId) => {
1171
+ if (!disposed) options.openSession(sessionId);
1172
+ }
1173
+ });
1174
+ };
717
1175
  return {
718
- ...viewError,
719
- message: String(error)
1176
+ create(input) {
1177
+ const key = `${input.workspaceId}\u0000${input.worktreeId}`;
1178
+ const current = inFlight.get(key);
1179
+ if (current !== void 0) return current;
1180
+ const promise = run(input).finally(() => {
1181
+ if (inFlight.get(key) === promise) inFlight.delete(key);
1182
+ });
1183
+ inFlight.set(key, promise);
1184
+ return promise;
1185
+ },
1186
+ dispose() {
1187
+ disposed = true;
1188
+ inFlight.clear();
1189
+ }
720
1190
  };
721
1191
  }
722
- const EMPTY_READ_STATE = {
723
- status: "idle",
724
- views: []
725
- };
726
- function useStableWorkspaceIds(workspaces) {
727
- const next = workspaces.map((workspace) => workspace.workspaceId);
728
- const previousRef = (0, react.useRef)([]);
729
- const stable = stableWorkspaceIds(previousRef.current, next);
730
- if (stable !== previousRef.current) previousRef.current = stable;
731
- return previousRef.current;
1192
+ //#endregion
1193
+ //#region lib/client/worktree-surface-dialogs.js
1194
+ function worktreeSetupMessage(status, t) {
1195
+ switch (status) {
1196
+ case "noRepository": return t("worktree.setup.noRepository");
1197
+ case "noInitialCommit": return t("worktree.setup.noInitialCommit");
1198
+ case "noLocalBranch": return t("worktree.setup.noLocalBranch");
1199
+ }
732
1200
  }
733
- function sessionLabel(sessionId, sessions) {
734
- return sessions.byId[sessionId]?.displayTitle ?? sessionId;
1201
+ function WorktreeSessionRenameDialog({ t, target, draft, pending, error, onClose, onDraftChange, onSubmit }) {
1202
+ return (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1203
+ open: target !== void 0,
1204
+ onClose,
1205
+ closeLabel: t("dialog.close"),
1206
+ title: t("session.rename"),
1207
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1208
+ variant: "outline",
1209
+ disabled: pending,
1210
+ onClick: onClose,
1211
+ children: t("dialog.cancel")
1212
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1213
+ variant: "primary",
1214
+ disabled: pending || draft.trim().length === 0,
1215
+ onClick: () => {
1216
+ onSubmit();
1217
+ },
1218
+ children: t("dialog.rename")
1219
+ })] }),
1220
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1221
+ className: worktree_css_default.renameInput,
1222
+ value: draft,
1223
+ "aria-label": t("session.name"),
1224
+ autoFocus: true,
1225
+ disabled: pending,
1226
+ onFocus: (event) => {
1227
+ event.currentTarget.select();
1228
+ },
1229
+ onChange: (event) => {
1230
+ onDraftChange(event.currentTarget.value);
1231
+ },
1232
+ onKeyDown: (event) => {
1233
+ if (event.key === "Enter" && !event.nativeEvent.isComposing) {
1234
+ event.preventDefault();
1235
+ onSubmit();
1236
+ }
1237
+ }
1238
+ }), error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1239
+ className: worktree_css_default.renameError,
1240
+ role: "alert",
1241
+ children: formatWorktreeViewError(error, t)
1242
+ })]
1243
+ });
735
1244
  }
736
- function rowHalf(event) {
737
- const rect = event.currentTarget.getBoundingClientRect();
738
- return event.clientY < rect.top + rect.height / 2 ? "before" : "after";
1245
+ function WorktreeWorkspaceRenameDialog({ t, target, draft, pending, duplicate, error, onClose, onDraftChange, onSubmit }) {
1246
+ if (target === void 0) return null;
1247
+ return (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1248
+ open: true,
1249
+ onClose,
1250
+ closeLabel: t("dialog.closeWorkspaceRename"),
1251
+ title: t("workspace.renameTitle"),
1252
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1253
+ variant: "outline",
1254
+ disabled: pending,
1255
+ onClick: onClose,
1256
+ children: t("dialog.cancel")
1257
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1258
+ variant: "primary",
1259
+ disabled: pending || draft.trim().length === 0 || draft.trim() === target.currentTitle || duplicate,
1260
+ onClick: () => {
1261
+ onSubmit();
1262
+ },
1263
+ children: t("dialog.rename")
1264
+ })] }),
1265
+ children: [
1266
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1267
+ className: worktree_css_default.renameInput,
1268
+ value: draft,
1269
+ "aria-label": t("workspace.name"),
1270
+ autoFocus: true,
1271
+ disabled: pending,
1272
+ onFocus: (event) => {
1273
+ event.currentTarget.select();
1274
+ },
1275
+ onChange: (event) => {
1276
+ onDraftChange(event.currentTarget.value);
1277
+ },
1278
+ onKeyDown: (event) => {
1279
+ if (event.key === "Enter" && !event.nativeEvent.isComposing) {
1280
+ event.preventDefault();
1281
+ onSubmit();
1282
+ }
1283
+ }
1284
+ }),
1285
+ duplicate && (0, react_jsx_runtime.jsx)("p", {
1286
+ className: worktree_css_default.renameError,
1287
+ role: "alert",
1288
+ children: t("workspace.duplicate")
1289
+ }),
1290
+ error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1291
+ className: worktree_css_default.renameError,
1292
+ role: "alert",
1293
+ children: formatWorktreeViewError(error, t)
1294
+ })
1295
+ ]
1296
+ });
1297
+ }
1298
+ function WorktreeWorkspaceDeleteDialog({ t, target, pending, error, onClose, onSubmit }) {
1299
+ if (target === void 0) return null;
1300
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1301
+ open: true,
1302
+ onClose,
1303
+ closeLabel: t("dialog.closeWorkspaceDelete"),
1304
+ title: t("workspace.deleteTitle"),
1305
+ description: t("workspace.deleteDescription", { name: target.title }),
1306
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1307
+ variant: "outline",
1308
+ disabled: pending,
1309
+ onClick: onClose,
1310
+ children: t("dialog.cancel")
1311
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1312
+ variant: "outline",
1313
+ disabled: pending,
1314
+ onClick: () => {
1315
+ onSubmit();
1316
+ },
1317
+ children: t("dialog.delete")
1318
+ })] }),
1319
+ children: error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1320
+ className: worktree_css_default.renameError,
1321
+ role: "alert",
1322
+ children: formatWorktreeViewError(error, t)
1323
+ })
1324
+ });
1325
+ }
1326
+ function WorktreeCreateDialog({ t, workspace, view, setupStatus, canCreate, selectedBranch, newBranch, actionPending, onClose, onSelectedBranchChange, onNewBranchChange, onSubmit }) {
1327
+ if (workspace === void 0) return null;
1328
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1329
+ open: true,
1330
+ onClose: () => {
1331
+ if (actionPending) return;
1332
+ onClose();
1333
+ },
1334
+ closeLabel: t("dialog.closeWorktreeCreate"),
1335
+ title: t("worktree.createTitle"),
1336
+ description: t("worktree.createDescription", { name: workspace.title }),
1337
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1338
+ variant: "outline",
1339
+ disabled: actionPending,
1340
+ onClick: onClose,
1341
+ children: t("dialog.cancel")
1342
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1343
+ variant: "primary",
1344
+ disabled: actionPending || selectedBranch.length === 0 || newBranch.trim().length === 0,
1345
+ onClick: () => {
1346
+ onSubmit();
1347
+ },
1348
+ children: t("worktree.create")
1349
+ })] }),
1350
+ children: canCreate ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("label", {
1351
+ className: worktree_css_default.modalField,
1352
+ children: [t("worktree.baseBranch"), (0, react_jsx_runtime.jsx)("select", {
1353
+ className: worktree_css_default.actionSelect,
1354
+ "aria-label": t("worktree.baseBranch"),
1355
+ value: selectedBranch,
1356
+ disabled: actionPending,
1357
+ onChange: (event) => {
1358
+ onSelectedBranchChange(event.currentTarget.value);
1359
+ },
1360
+ children: view?.branches.map((branch) => (0, react_jsx_runtime.jsxs)("option", {
1361
+ value: branch.name,
1362
+ children: [
1363
+ branch.name,
1364
+ branch.isCurrent ? t("branch.current") : "",
1365
+ branch.checkedOut ? t("branch.checkedOut") : ""
1366
+ ]
1367
+ }, branch.name))
1368
+ })]
1369
+ }), (0, react_jsx_runtime.jsxs)("label", {
1370
+ className: worktree_css_default.modalField,
1371
+ children: [t("worktree.name"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1372
+ className: worktree_css_default.renameInput,
1373
+ "aria-label": t("worktree.name"),
1374
+ value: newBranch,
1375
+ placeholder: "dsh/12345678",
1376
+ disabled: actionPending,
1377
+ onChange: (event) => {
1378
+ onNewBranchChange(event.currentTarget.value);
1379
+ }
1380
+ })]
1381
+ })] }) : (0, react_jsx_runtime.jsxs)("div", {
1382
+ className: worktree_css_default.gitReadiness,
1383
+ "data-worktree-readiness": setupStatus ?? "loading",
1384
+ role: "alert",
1385
+ children: [(0, react_jsx_runtime.jsx)("p", {
1386
+ className: worktree_css_default.message,
1387
+ children: setupStatus === void 0 ? t("status.loading") : worktreeSetupMessage(setupStatus, t)
1388
+ }), setupStatus !== void 0 && (0, react_jsx_runtime.jsx)("pre", {
1389
+ className: worktree_css_default.commandBlock,
1390
+ "aria-label": t("worktree.setup.commands"),
1391
+ children: worktreeSetupCommands(setupStatus).join("\n")
1392
+ })]
1393
+ })
1394
+ });
1395
+ }
1396
+ function WorktreeRemovalDialog({ t, worktree, actionPending, onClose, onSubmit }) {
1397
+ if (worktree === void 0) return null;
1398
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1399
+ open: true,
1400
+ onClose: () => {
1401
+ if (actionPending) return;
1402
+ onClose();
1403
+ },
1404
+ closeLabel: t("dialog.closeWorktreeRemove"),
1405
+ title: t("worktree.remove"),
1406
+ description: t("worktree.removeDescription", { name: worktree.branch }),
1407
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1408
+ variant: "outline",
1409
+ disabled: actionPending,
1410
+ onClick: onClose,
1411
+ children: t("dialog.cancel")
1412
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1413
+ variant: "primary",
1414
+ disabled: actionPending,
1415
+ onClick: () => {
1416
+ onSubmit();
1417
+ },
1418
+ children: t("worktree.remove")
1419
+ })] })
1420
+ });
1421
+ }
1422
+ //#endregion
1423
+ //#region lib/client/worktree-surface-selectors.js
1424
+ function sessionLabel(sessionId, sessions, t) {
1425
+ return sessionDisplayLabel(sessionId, sessions, t("session.new"));
739
1426
  }
740
1427
  function bindingIdsFor(bindings, worktreeId) {
741
1428
  return bindings.filter((binding) => binding.worktreeId === worktreeId).map((binding) => binding.sessionId);
@@ -746,10 +1433,16 @@ window.__ModuleLoader__.load({
746
1433
  function workspaceMatches(workspace, view, sessions, query) {
747
1434
  if (query.length === 0) return true;
748
1435
  if (includesText(workspace.title, query)) return true;
749
- if (workspace.sessionIds.some((sessionId) => includesText(sessionLabel(sessionId, sessions), query))) return true;
1436
+ if (workspace.sessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return true;
750
1437
  if (view === void 0) return false;
751
1438
  if (view.worktrees.some((record) => includesText(record.branch, query) || includesText(record.absolutePath, query))) return true;
752
- return view.bindings.some((binding) => includesText(sessionLabel(binding.sessionId, sessions), query));
1439
+ return view.bindings.some((binding) => sessionMatchesQuery(binding.sessionId, sessions, query));
1440
+ }
1441
+ //#endregion
1442
+ //#region lib/client/worktree-surface-rows.js
1443
+ function rowHalf(event) {
1444
+ const rect = event.currentTarget.getBoundingClientRect();
1445
+ return event.clientY < rect.top + rect.height / 2 ? "before" : "after";
753
1446
  }
754
1447
  /** Workspace row using the native DSH menu, fixed action column, and drag contract. */
755
1448
  function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
@@ -857,13 +1550,36 @@ window.__ModuleLoader__.load({
857
1550
  });
858
1551
  }
859
1552
  /** Shared Main/Worktree group row with parameterized icon, state, and actions. */
860
- function WorktreeGroupRow({ t, kind, label, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu }) {
1553
+ function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
861
1554
  const main = kind === "main";
1555
+ const markerClass = drag?.marker === "before" ? worktree_css_default.dropBefore : drag?.marker === "after" ? worktree_css_default.dropAfter : "";
1556
+ const dragProps = drag === void 0 ? {} : {
1557
+ draggable: true,
1558
+ onDragStart: (event) => {
1559
+ event.dataTransfer.effectAllowed = "move";
1560
+ event.dataTransfer.setData("text/plain", worktreeId ?? label);
1561
+ drag.start();
1562
+ },
1563
+ onDragEnd: drag.end,
1564
+ onDragOver: (event) => {
1565
+ if (!drag.active) return;
1566
+ event.preventDefault();
1567
+ event.dataTransfer.dropEffect = "move";
1568
+ drag.hover(rowHalf(event));
1569
+ },
1570
+ onDrop: (event) => {
1571
+ if (!drag.active) return;
1572
+ event.preventDefault();
1573
+ drag.drop(rowHalf(event));
1574
+ }
1575
+ };
862
1576
  const row = (0, react_jsx_runtime.jsxs)("div", {
863
- className: worktree_css_default.worktreeRow,
1577
+ className: `${worktree_css_default.worktreeRow} ${markerClass}`,
864
1578
  "data-main-group": main ? "true" : void 0,
865
1579
  "data-main-expanded": main ? String(expanded) : void 0,
866
1580
  "data-menu-open": menu?.open ? "true" : void 0,
1581
+ "data-worktree-drag": drag?.active ? "active" : void 0,
1582
+ ...dragProps,
867
1583
  onClick: onToggle,
868
1584
  children: [
869
1585
  (0, react_jsx_runtime.jsx)("button", {
@@ -954,7 +1670,7 @@ window.__ModuleLoader__.load({
954
1670
  });
955
1671
  }
956
1672
  /** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
957
- function WorktreeSessionRow({ t, sessionId, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
1673
+ function WorktreeSessionRow({ t, sessionId, blank, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
958
1674
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
959
1675
  const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
960
1676
  const sessionMenuItems = [
@@ -980,6 +1696,7 @@ window.__ModuleLoader__.load({
980
1696
  return (0, react_jsx_runtime.jsxs)("div", {
981
1697
  className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
982
1698
  "data-session-id": sessionId,
1699
+ "data-session-blank": blank ? "true" : void 0,
983
1700
  "data-session-drag": drag.active ? "active" : void 0,
984
1701
  "data-menu-open": menuOpen || void 0,
985
1702
  role: "treeitem",
@@ -1013,7 +1730,7 @@ window.__ModuleLoader__.load({
1013
1730
  className: worktree_css_default.sessionLabel,
1014
1731
  children: label
1015
1732
  })]
1016
- }), (0, react_jsx_runtime.jsx)("span", {
1733
+ }), !blank && (0, react_jsx_runtime.jsx)("span", {
1017
1734
  className: worktree_css_default.rowActions,
1018
1735
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
1019
1736
  open: menuOpen,
@@ -1050,7 +1767,8 @@ window.__ModuleLoader__.load({
1050
1767
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
1051
1768
  t,
1052
1769
  sessionId,
1053
- label: sessionLabel(sessionId, sessions),
1770
+ blank: isBlankSession(sessionId, sessions),
1771
+ label: sessionLabel(sessionId, sessions, t),
1054
1772
  drag: {
1055
1773
  active: sameGroupDrag,
1056
1774
  marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
@@ -1088,16 +1806,39 @@ window.__ModuleLoader__.load({
1088
1806
  children: expanded ? t("session.collapse") : t("session.expandMore", { count: sessionIds.length - 5 })
1089
1807
  })] });
1090
1808
  }
1809
+ //#endregion
1810
+ //#region lib/client/WorktreeSurface.js
1811
+ function toNativeWorktreeViewError(error) {
1812
+ const viewError = toWorktreeViewError(error);
1813
+ if (typeof error === "object" && error !== null) return viewError;
1814
+ return {
1815
+ ...viewError,
1816
+ message: String(error)
1817
+ };
1818
+ }
1819
+ const EMPTY_READ_STATE = {
1820
+ status: "idle",
1821
+ views: []
1822
+ };
1823
+ function useStableWorkspaceIds(workspaces) {
1824
+ const next = workspaces.map((workspace) => workspace.workspaceId);
1825
+ const previousRef = (0, react.useRef)([]);
1826
+ const stable = stableWorkspaceIds(previousRef.current, next);
1827
+ if (stable !== previousRef.current) previousRef.current = stable;
1828
+ return previousRef.current;
1829
+ }
1091
1830
  /**
1092
1831
  * Peer Worktree navigation surface. It keeps the original DSH Workspace mode
1093
1832
  * intact and renders a browser-local Workspace → Worktree → Session projection.
1094
1833
  */
1095
- function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
1834
+ function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
1096
1835
  const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
1097
1836
  const sessions = useSessions((state) => state);
1098
1837
  const workspaces = useWorkspaces((state) => state);
1099
1838
  const workspaceIds = useStableWorkspaceIds(workspaces.items);
1100
1839
  const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
1840
+ const readStateRef = (0, react.useRef)(readState);
1841
+ readStateRef.current = readState;
1101
1842
  const [searchQuery, setSearchQuery] = (0, react.useState)("");
1102
1843
  const [expandedWorkspaces, setExpandedWorkspaces] = (0, react.useState)({});
1103
1844
  const [expandedMains, setExpandedMains] = (0, react.useState)({});
@@ -1127,36 +1868,52 @@ window.__ModuleLoader__.load({
1127
1868
  const [sessionDrag, setSessionDrag] = (0, react.useState)();
1128
1869
  const [expandedSessionGroups, setExpandedSessionGroups] = (0, react.useState)({});
1129
1870
  const sessionDropCommitted = (0, react.useRef)(false);
1871
+ const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
1872
+ const worktreeDropCommitted = (0, react.useRef)(false);
1873
+ const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
1130
1874
  const { ref, width, bounds } = useSidebarOverlayGeometry(mode === "worktree");
1131
1875
  const collapsed = width <= 64;
1132
1876
  const query = searchQuery.trim().toLocaleLowerCase();
1133
1877
  const archivedSessionIds = workspaces.archivedSessionIds ?? [];
1134
- const refresh = (0, react.useCallback)(async () => {
1878
+ const pendingSessionArchived = pendingSessionBinding !== void 0 && archivedSessionIds.includes(pendingSessionBinding.sessionId);
1879
+ const refresh = (0, react.useCallback)(async (options = {}) => {
1135
1880
  if (manager === void 0) {
1881
+ refreshGuard.current.invalidate();
1136
1882
  setReadState(EMPTY_READ_STATE);
1137
1883
  return;
1138
1884
  }
1139
- setReadState({
1885
+ const preserveCurrent = options.preserveCurrent === true;
1886
+ if (!preserveCurrent) setReadState({
1140
1887
  status: "loading",
1141
1888
  views: []
1142
1889
  });
1143
- try {
1144
- const views = await loadWorktreeViews(manager, workspaceIds);
1890
+ await refreshGuard.current.run(() => loadWorktreeViews(manager, workspaceIds, {
1891
+ invalidateContext: options.invalidateContext !== false,
1892
+ invalidateWorktreeContext
1893
+ }), (views) => {
1145
1894
  setReadState({
1146
1895
  status: "ready",
1147
1896
  views
1148
1897
  });
1149
- } catch (error) {
1898
+ }, (error) => {
1899
+ if (preserveCurrent) throw error;
1150
1900
  setReadState({
1151
1901
  status: "error",
1152
1902
  views: [],
1153
1903
  error: toWorktreeViewError(error)
1154
1904
  });
1155
- }
1156
- }, [manager, workspaceIds]);
1905
+ });
1906
+ }, [
1907
+ invalidateWorktreeContext,
1908
+ manager,
1909
+ workspaceIds
1910
+ ]);
1157
1911
  (0, react.useEffect)(() => {
1158
- if (mode === "worktree") refresh();
1159
- else setReadState(EMPTY_READ_STATE);
1912
+ if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
1913
+ else {
1914
+ refreshGuard.current.invalidate();
1915
+ setReadState(EMPTY_READ_STATE);
1916
+ }
1160
1917
  }, [mode, refresh]);
1161
1918
  (0, react.useEffect)(() => {
1162
1919
  if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
@@ -1172,12 +1929,23 @@ window.__ModuleLoader__.load({
1172
1929
  const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
1173
1930
  const modalWorkspace = workspaces.items.find((workspace) => workspace.workspaceId === worktreeModalWorkspaceId);
1174
1931
  const modalView = worktreeModalWorkspaceId === void 0 ? void 0 : viewByWorkspace.get(worktreeModalWorkspaceId);
1932
+ const modalReadiness = modalView?.readiness;
1933
+ const modalSetupStatus = modalView === void 0 ? void 0 : modalReadiness?.status === "ready" ? modalView.branches.length === 0 ? "noLocalBranch" : void 0 : modalReadiness?.status;
1934
+ const modalCanCreate = modalSetupStatus === void 0 && modalReadiness?.status === "ready";
1935
+ (0, react.useEffect)(() => {
1936
+ if (worktreeModalWorkspaceId === void 0 || modalView === void 0) return;
1937
+ if (modalView.readiness.status !== "ready") {
1938
+ setSelectedBranch("");
1939
+ return;
1940
+ }
1941
+ setSelectedBranch((current) => reconcileBaseBranchSelection(current, modalView.branches));
1942
+ }, [modalView, worktreeModalWorkspaceId]);
1175
1943
  const runMutation = async (operation) => {
1176
1944
  setActionPending(true);
1177
1945
  setActionError(void 0);
1178
1946
  try {
1179
1947
  await operation();
1180
- await refresh();
1948
+ await refresh({ preserveCurrent: true });
1181
1949
  } catch (error) {
1182
1950
  setActionError(toWorktreeViewError(error));
1183
1951
  } finally {
@@ -1303,6 +2071,29 @@ window.__ModuleLoader__.load({
1303
2071
  setActionError(toWorktreeViewError(error));
1304
2072
  });
1305
2073
  };
2074
+ const commitWorktreeDrag = (activeDrag, over, worktreeIds, workspaceId) => {
2075
+ if (worktreeDropCommitted.current) return;
2076
+ worktreeDropCommitted.current = true;
2077
+ setWorktreeDrag(void 0);
2078
+ if (activeDrag.workspaceId !== workspaceId) return;
2079
+ const move = resolveWorktreeMove(worktreeIds, activeDrag.worktreeId, over.worktreeId, over.half);
2080
+ if (move === void 0) return;
2081
+ if (insertWorktreeBefore === void 0) {
2082
+ setActionError({
2083
+ code: "WORKTREE_ORDER_UNAVAILABLE",
2084
+ message: "",
2085
+ retryable: true
2086
+ });
2087
+ return;
2088
+ }
2089
+ setActionError(void 0);
2090
+ insertWorktreeBefore(workspaceId, activeDrag.worktreeId, move.beforeWorktreeId).then(() => refresh({
2091
+ preserveCurrent: true,
2092
+ invalidateContext: false
2093
+ })).catch((error) => {
2094
+ setActionError(toRetryableWorktreeOrderError(error));
2095
+ });
2096
+ };
1306
2097
  const openSessionRename = (sessionId, currentTitle) => {
1307
2098
  setSessionRenameTarget({
1308
2099
  sessionId,
@@ -1372,7 +2163,7 @@ window.__ModuleLoader__.load({
1372
2163
  };
1373
2164
  const submitWorktree = async () => {
1374
2165
  const worktreeName = newBranch.trim();
1375
- if (manager === void 0 || modalWorkspace === void 0 || selectedBranch.length === 0 || worktreeName.length === 0) return;
2166
+ if (manager === void 0 || modalWorkspace === void 0 || !modalCanCreate || selectedBranch.length === 0 || worktreeName.length === 0) return;
1376
2167
  const input = {
1377
2168
  workspaceId: modalWorkspace.workspaceId,
1378
2169
  branch: selectedBranch,
@@ -1393,7 +2184,7 @@ window.__ModuleLoader__.load({
1393
2184
  };
1394
2185
  setWorktreeModalWorkspaceId(void 0);
1395
2186
  if (createSessionCallback === void 0) {
1396
- await refresh();
2187
+ await refresh({ preserveCurrent: true });
1397
2188
  setActionError({
1398
2189
  code: "WORKTREE_CREATED_SESSION_UNAVAILABLE",
1399
2190
  message: "",
@@ -1408,14 +2199,15 @@ window.__ModuleLoader__.load({
1408
2199
  };
1409
2200
  try {
1410
2201
  await createSessionCallback(sessionInput);
2202
+ await invalidateWorktreeContext?.(createdWorktree.workspaceId);
1411
2203
  } catch (error) {
1412
- if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
2204
+ if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
1413
2205
  ...sessionInput,
1414
2206
  sessionId: error.sessionId
1415
2207
  });
1416
2208
  throw error;
1417
2209
  }
1418
- await refresh();
2210
+ await refresh({ preserveCurrent: true });
1419
2211
  } catch (error) {
1420
2212
  setActionError(toWorktreeViewError(error));
1421
2213
  } finally {
@@ -1436,9 +2228,10 @@ window.__ModuleLoader__.load({
1436
2228
  setPendingSessionBinding(void 0);
1437
2229
  try {
1438
2230
  await createSessionCallback(input);
1439
- await refresh();
2231
+ await invalidateWorktreeContext?.(input.workspaceId);
2232
+ await refresh({ preserveCurrent: true });
1440
2233
  } catch (error) {
1441
- if (error instanceof WorktreeSessionBindingError) setPendingSessionBinding({
2234
+ if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
1442
2235
  ...input,
1443
2236
  sessionId: error.sessionId
1444
2237
  });
@@ -1448,21 +2241,25 @@ window.__ModuleLoader__.load({
1448
2241
  }
1449
2242
  };
1450
2243
  const retrySessionBinding = async () => {
1451
- if (manager === void 0 || pendingSessionBinding === void 0) return;
2244
+ if (manager === void 0 || pendingSessionBinding === void 0 || pendingSessionArchived) return;
2245
+ const pending = pendingSessionBinding;
1452
2246
  setActionPending(true);
1453
2247
  setActionError(void 0);
1454
2248
  try {
1455
- await manager.bindSession({
1456
- workspaceId: pendingSessionBinding.workspaceId,
1457
- worktreeId: pendingSessionBinding.worktreeId,
1458
- sessionId: pendingSessionBinding.sessionId
2249
+ await retryWorktreeSessionBinding({
2250
+ manager,
2251
+ pending,
2252
+ archived: false,
2253
+ ensureSessionWorkspace: (workspaceId, sessionId) => {
2254
+ ensureSessionWorkspace?.(workspaceId, sessionId);
2255
+ },
2256
+ openSession
1459
2257
  });
1460
- const sessionId = pendingSessionBinding.sessionId;
1461
2258
  setPendingSessionBinding(void 0);
1462
- ensureSessionWorkspace?.(pendingSessionBinding.workspaceId, sessionId);
1463
- await refresh();
1464
- openSession(sessionId);
2259
+ await refresh({ preserveCurrent: true });
2260
+ await invalidateWorktreeContext?.(pending.workspaceId);
1465
2261
  } catch (error) {
2262
+ if (error instanceof WorktreeSessionBindingError && !error.retryable) setPendingSessionBinding(void 0);
1466
2263
  setActionError(toWorktreeViewError(error));
1467
2264
  } finally {
1468
2265
  setActionPending(false);
@@ -1556,7 +2353,7 @@ window.__ModuleLoader__.load({
1556
2353
  children: [(0, react_jsx_runtime.jsx)("button", {
1557
2354
  type: "button",
1558
2355
  className: worktree_css_default.actionButton,
1559
- disabled: actionPending,
2356
+ disabled: actionPending || pendingSessionArchived,
1560
2357
  onClick: () => {
1561
2358
  retrySessionBinding();
1562
2359
  },
@@ -1612,14 +2409,17 @@ window.__ModuleLoader__.load({
1612
2409
  children: t("workspace.noMatches")
1613
2410
  }) : visibleWorkspaces.map((workspace) => {
1614
2411
  const view = viewByWorkspace.get(workspace.workspaceId);
2412
+ const currentBranch = view?.branches.find((branch) => branch.isCurrent)?.name;
2413
+ const mainLabel = currentBranch === void 0 ? t("worktree.main") : t("worktree.mainWithBranch", { branch: currentBranch });
1615
2414
  const expanded = expandedWorkspaces[workspace.workspaceId] !== false;
1616
2415
  const workspaceMatchesQuery = includesText(workspace.title, query);
1617
2416
  const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
1618
2417
  const bindings = view?.bindings ?? [];
1619
- const visibleMainSessionIds = unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]).filter((sessionId) => workspaceMatchesQuery || includesText(sessionLabel(sessionId, sessions), query));
2418
+ const visibleMainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions).filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
1620
2419
  const mainExpanded = expandedMains[workspace.workspaceId] !== false;
1621
2420
  const mainGroupKey = `main:${workspace.workspaceId}`;
1622
2421
  const worktrees = view?.worktrees ?? [];
2422
+ const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
1623
2423
  return (0, react_jsx_runtime.jsxs)("section", {
1624
2424
  className: worktree_css_default.workspaceGroup,
1625
2425
  "data-workspace-id": workspace.workspaceId,
@@ -1682,7 +2482,7 @@ window.__ModuleLoader__.load({
1682
2482
  (0, react_jsx_runtime.jsx)(WorktreeGroupRow, {
1683
2483
  t,
1684
2484
  kind: "main",
1685
- label: t("worktree.main"),
2485
+ label: mainLabel,
1686
2486
  expanded: mainExpanded,
1687
2487
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
1688
2488
  workspaceTitle: workspace.title,
@@ -1744,10 +2544,10 @@ window.__ModuleLoader__.load({
1744
2544
  children: t("worktree.noWorktrees")
1745
2545
  }),
1746
2546
  worktrees.map((record) => {
1747
- const worktreeSessionIds = filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds);
2547
+ const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
1748
2548
  const worktreeMatchesQuery = workspaceMatchesQuery || includesText(record.branch, query) || includesText(record.absolutePath, query);
1749
- if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => includesText(sessionLabel(sessionId, sessions), query))) return null;
1750
- const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || includesText(sessionLabel(sessionId, sessions), query));
2549
+ if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return null;
2550
+ const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
1751
2551
  const worktreeGroupKey = `worktree:${record.worktreeId}`;
1752
2552
  const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
1753
2553
  const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
@@ -1759,6 +2559,7 @@ window.__ModuleLoader__.load({
1759
2559
  t,
1760
2560
  kind: "worktree",
1761
2561
  label: record.branch,
2562
+ worktreeId: record.worktreeId,
1762
2563
  expanded: worktreeExpanded,
1763
2564
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
1764
2565
  workspaceTitle: workspace.title,
@@ -1767,7 +2568,7 @@ window.__ModuleLoader__.load({
1767
2568
  onToggle: () => {
1768
2569
  toggleWorktree(record.worktreeId);
1769
2570
  },
1770
- onCreateSession: record.status === "active" ? () => {
2571
+ onCreateSession: record.status === "active" && record.health !== "repair" ? () => {
1771
2572
  createSession({
1772
2573
  workspaceId: record.workspaceId,
1773
2574
  worktreeId: record.worktreeId,
@@ -1785,7 +2586,39 @@ window.__ModuleLoader__.load({
1785
2586
  setWorktreeRemoval(record);
1786
2587
  setActionError(void 0);
1787
2588
  }
1788
- } : void 0
2589
+ } : void 0,
2590
+ drag: {
2591
+ active: sameWorkspaceWorktreeDrag,
2592
+ marker: worktreeDrag?.over?.worktreeId === record.worktreeId ? worktreeDrag.over.half : null,
2593
+ start: () => {
2594
+ worktreeDropCommitted.current = false;
2595
+ setWorktreeDrag({
2596
+ workspaceId: workspace.workspaceId,
2597
+ worktreeId: record.worktreeId,
2598
+ over: null
2599
+ });
2600
+ },
2601
+ hover: (half) => {
2602
+ setWorktreeDrag((current) => current === void 0 || current.workspaceId !== workspace.workspaceId ? current : {
2603
+ ...current,
2604
+ over: {
2605
+ worktreeId: record.worktreeId,
2606
+ half
2607
+ }
2608
+ });
2609
+ },
2610
+ drop: (half) => {
2611
+ if (worktreeDrag === void 0) return;
2612
+ commitWorktreeDrag(worktreeDrag, {
2613
+ worktreeId: record.worktreeId,
2614
+ half
2615
+ }, worktrees.map((candidate) => candidate.worktreeId), workspace.workspaceId);
2616
+ },
2617
+ end: () => {
2618
+ setWorktreeDrag(void 0);
2619
+ worktreeDropCommitted.current = false;
2620
+ }
2621
+ }
1789
2622
  }), worktreeExpanded && (0, react_jsx_runtime.jsx)(WorktreeSessionGroup, {
1790
2623
  t,
1791
2624
  groupKey: worktreeGroupKey,
@@ -1855,232 +2688,318 @@ window.__ModuleLoader__.load({
1855
2688
  children: "WT"
1856
2689
  })
1857
2690
  }),
1858
- (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1859
- open: sessionRenameTarget !== void 0,
2691
+ (0, react_jsx_runtime.jsx)(WorktreeSessionRenameDialog, {
2692
+ t,
2693
+ target: sessionRenameTarget,
2694
+ draft: sessionRenameDraft,
2695
+ pending: sessionRenamePending,
2696
+ error: sessionRenameError,
1860
2697
  onClose: closeSessionRename,
1861
- closeLabel: t("dialog.close"),
1862
- title: t("session.rename"),
1863
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1864
- variant: "outline",
1865
- disabled: sessionRenamePending,
1866
- onClick: closeSessionRename,
1867
- children: t("dialog.cancel")
1868
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1869
- variant: "primary",
1870
- disabled: sessionRenamePending || sessionRenameDraft.trim().length === 0,
1871
- onClick: () => {
1872
- confirmSessionRename();
1873
- },
1874
- children: t("dialog.rename")
1875
- })] }),
1876
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1877
- className: worktree_css_default.renameInput,
1878
- value: sessionRenameDraft,
1879
- "aria-label": t("session.name"),
1880
- autoFocus: true,
1881
- disabled: sessionRenamePending,
1882
- onFocus: (event) => {
1883
- event.currentTarget.select();
1884
- },
1885
- onChange: (event) => {
1886
- setSessionRenameDraft(event.currentTarget.value);
1887
- setSessionRenameError(void 0);
1888
- },
1889
- onKeyDown: (event) => {
1890
- if (event.key === "Enter" && !event.nativeEvent.isComposing) {
1891
- event.preventDefault();
1892
- confirmSessionRename();
1893
- }
1894
- }
1895
- }), sessionRenameError !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1896
- className: worktree_css_default.renameError,
1897
- role: "alert",
1898
- children: formatWorktreeViewError(sessionRenameError, t)
1899
- })]
2698
+ onDraftChange: (draft) => {
2699
+ setSessionRenameDraft(draft);
2700
+ setSessionRenameError(void 0);
2701
+ },
2702
+ onSubmit: confirmSessionRename
1900
2703
  }),
1901
- workspaceRenameTarget !== void 0 && (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1902
- open: workspaceRenameTarget !== void 0,
2704
+ (0, react_jsx_runtime.jsx)(WorktreeWorkspaceRenameDialog, {
2705
+ t,
2706
+ target: workspaceRenameTarget,
2707
+ draft: workspaceRenameDraft,
2708
+ pending: workspaceRenamePending,
2709
+ duplicate: workspaceRenameDuplicate,
2710
+ error: workspaceRenameError,
1903
2711
  onClose: closeWorkspaceRename,
1904
- closeLabel: t("dialog.closeWorkspaceRename"),
1905
- title: t("workspace.renameTitle"),
1906
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1907
- variant: "outline",
1908
- disabled: workspaceRenamePending,
1909
- onClick: closeWorkspaceRename,
1910
- children: t("dialog.cancel")
1911
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1912
- variant: "primary",
1913
- disabled: workspaceRenameBlocked,
1914
- onClick: () => {
1915
- confirmWorkspaceRename();
1916
- },
1917
- children: t("dialog.rename")
1918
- })] }),
1919
- children: [
1920
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
1921
- className: worktree_css_default.renameInput,
1922
- value: workspaceRenameDraft,
1923
- "aria-label": t("workspace.name"),
1924
- autoFocus: true,
1925
- disabled: workspaceRenamePending,
1926
- onFocus: (event) => {
1927
- event.currentTarget.select();
1928
- },
1929
- onChange: (event) => {
1930
- setWorkspaceRenameDraft(event.currentTarget.value);
1931
- setWorkspaceRenameError(void 0);
1932
- },
1933
- onKeyDown: (event) => {
1934
- if (event.key === "Enter" && !event.nativeEvent.isComposing) {
1935
- event.preventDefault();
1936
- confirmWorkspaceRename();
1937
- }
1938
- }
1939
- }),
1940
- workspaceRenameDuplicate && (0, react_jsx_runtime.jsx)("p", {
1941
- className: worktree_css_default.renameError,
1942
- role: "alert",
1943
- children: t("workspace.duplicate")
1944
- }),
1945
- workspaceRenameError !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1946
- className: worktree_css_default.renameError,
1947
- role: "alert",
1948
- children: formatWorktreeViewError(workspaceRenameError, t)
1949
- })
1950
- ]
2712
+ onDraftChange: (draft) => {
2713
+ setWorkspaceRenameDraft(draft);
2714
+ setWorkspaceRenameError(void 0);
2715
+ },
2716
+ onSubmit: confirmWorkspaceRename
1951
2717
  }),
1952
- workspaceDeleteTarget !== void 0 && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1953
- open: workspaceDeleteTarget !== void 0,
2718
+ (0, react_jsx_runtime.jsx)(WorktreeWorkspaceDeleteDialog, {
2719
+ t,
2720
+ target: workspaceDeleteTarget,
2721
+ pending: workspaceDeletePending,
2722
+ error: workspaceDeleteError,
1954
2723
  onClose: closeWorkspaceDelete,
1955
- closeLabel: t("dialog.closeWorkspaceDelete"),
1956
- title: t("workspace.deleteTitle"),
1957
- description: t("workspace.deleteDescription", { name: workspaceDeleteTarget.title }),
1958
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1959
- variant: "outline",
1960
- disabled: workspaceDeletePending,
1961
- onClick: closeWorkspaceDelete,
1962
- children: t("dialog.cancel")
1963
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1964
- variant: "outline",
1965
- disabled: workspaceDeletePending,
1966
- onClick: () => {
1967
- confirmWorkspaceDelete();
1968
- },
1969
- children: t("dialog.delete")
1970
- })] }),
1971
- children: workspaceDeleteError !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1972
- className: worktree_css_default.renameError,
1973
- role: "alert",
1974
- children: formatWorktreeViewError(workspaceDeleteError, t)
1975
- })
2724
+ onSubmit: confirmWorkspaceDelete
1976
2725
  }),
1977
- worktreeModalWorkspaceId !== void 0 && modalWorkspace !== void 0 && (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1978
- open: worktreeModalWorkspaceId !== void 0,
2726
+ (0, react_jsx_runtime.jsx)(WorktreeCreateDialog, {
2727
+ t,
2728
+ workspace: modalWorkspace,
2729
+ view: modalView,
2730
+ setupStatus: modalSetupStatus,
2731
+ canCreate: modalCanCreate,
2732
+ selectedBranch,
2733
+ newBranch,
2734
+ actionPending,
1979
2735
  onClose: () => {
1980
- if (actionPending) return;
1981
2736
  setWorktreeModalWorkspaceId(void 0);
1982
2737
  },
1983
- closeLabel: t("dialog.closeWorktreeCreate"),
1984
- title: t("worktree.createTitle"),
1985
- description: t("worktree.createDescription", { name: modalWorkspace.title }),
1986
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1987
- variant: "outline",
1988
- disabled: actionPending,
1989
- onClick: () => {
1990
- setWorktreeModalWorkspaceId(void 0);
1991
- },
1992
- children: t("dialog.cancel")
1993
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1994
- variant: "primary",
1995
- disabled: actionPending || selectedBranch.length === 0 || newBranch.trim().length === 0,
1996
- onClick: () => {
1997
- submitWorktree();
1998
- },
1999
- children: t("worktree.create")
2000
- })] }),
2001
- children: [
2002
- (0, react_jsx_runtime.jsxs)("label", {
2003
- className: worktree_css_default.modalField,
2004
- children: [t("worktree.baseBranch"), (0, react_jsx_runtime.jsxs)("select", {
2005
- className: worktree_css_default.actionSelect,
2006
- "aria-label": t("worktree.baseBranch"),
2007
- value: selectedBranch,
2008
- disabled: actionPending,
2009
- onChange: (event) => {
2010
- setSelectedBranch(event.currentTarget.value);
2011
- },
2012
- children: [(0, react_jsx_runtime.jsx)("option", {
2013
- value: "",
2014
- children: t("worktree.noLocalBranch")
2015
- }), (modalView?.branches ?? []).map((branch) => (0, react_jsx_runtime.jsxs)("option", {
2016
- value: branch.name,
2017
- children: [
2018
- branch.name,
2019
- branch.isCurrent ? t("branch.current") : "",
2020
- branch.checkedOut ? t("branch.checkedOut") : ""
2021
- ]
2022
- }, branch.name))]
2023
- })]
2024
- }),
2025
- (0, react_jsx_runtime.jsxs)("label", {
2026
- className: worktree_css_default.modalField,
2027
- children: [t("worktree.name"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
2028
- className: worktree_css_default.renameInput,
2029
- "aria-label": t("worktree.name"),
2030
- value: newBranch,
2031
- placeholder: "dsh/12345678",
2032
- disabled: actionPending,
2033
- onChange: (event) => {
2034
- setNewBranch(event.currentTarget.value);
2035
- }
2036
- })]
2037
- }),
2038
- modalView?.branches.length === 0 && (0, react_jsx_runtime.jsx)("p", {
2039
- className: worktree_css_default.empty,
2040
- children: t("worktree.noBranches")
2041
- })
2042
- ]
2738
+ onSelectedBranchChange: setSelectedBranch,
2739
+ onNewBranchChange: setNewBranch,
2740
+ onSubmit: submitWorktree
2043
2741
  }),
2044
- worktreeRemoval !== void 0 && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
2045
- open: worktreeRemoval !== void 0,
2742
+ (0, react_jsx_runtime.jsx)(WorktreeRemovalDialog, {
2743
+ t,
2744
+ worktree: worktreeRemoval,
2745
+ actionPending,
2046
2746
  onClose: () => {
2047
- if (actionPending) return;
2048
2747
  setWorktreeRemoval(void 0);
2049
2748
  },
2050
- closeLabel: t("dialog.closeWorktreeRemove"),
2051
- title: t("worktree.remove"),
2052
- description: t("worktree.removeDescription", { name: worktreeRemoval.branch }),
2053
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2054
- variant: "outline",
2055
- disabled: actionPending,
2056
- onClick: () => {
2057
- setWorktreeRemoval(void 0);
2058
- },
2059
- children: t("dialog.cancel")
2060
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2061
- variant: "primary",
2062
- disabled: actionPending,
2063
- onClick: () => {
2064
- if (manager === void 0) return;
2065
- const target = worktreeRemoval;
2066
- runMutation(async () => {
2067
- await executeWorktreeAction(manager, {
2068
- type: "removeWorktree",
2069
- input: {
2070
- workspaceId: target.workspaceId,
2071
- worktreeId: target.worktreeId
2072
- }
2073
- });
2074
- setWorktreeRemoval(void 0);
2749
+ onSubmit: () => {
2750
+ if (manager === void 0 || worktreeRemoval === void 0) return;
2751
+ const target = worktreeRemoval;
2752
+ runMutation(async () => {
2753
+ await executeWorktreeAction(manager, {
2754
+ type: "removeWorktree",
2755
+ input: {
2756
+ workspaceId: target.workspaceId,
2757
+ worktreeId: target.worktreeId
2758
+ }
2075
2759
  });
2076
- },
2077
- children: t("worktree.remove")
2078
- })] })
2760
+ await invalidateWorktreeContext?.(target.workspaceId);
2761
+ setWorktreeRemoval(void 0);
2762
+ });
2763
+ }
2079
2764
  })
2080
2765
  ]
2081
2766
  });
2082
2767
  }
2083
2768
  //#endregion
2769
+ //#region lib/client/WorktreeOverlay.js
2770
+ /** Compose the independent Hero context and Worktree navigation overlays. */
2771
+ function WorktreeOverlay(props) {
2772
+ 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 })] });
2773
+ }
2774
+ //#endregion
2775
+ //#region lib/client/worktree-context.js
2776
+ const none = (reason) => ({
2777
+ kind: "none",
2778
+ reason
2779
+ });
2780
+ /** Resolve the branch or active Worktree label for one current DSH Session. */
2781
+ function resolveWorktreeSessionContext(input) {
2782
+ const sessionId = input.currentSessionId;
2783
+ if (sessionId === void 0 && input.currentWorkspaceId === void 0) return none("no-session");
2784
+ const workspace = sessionId === void 0 ? input.workspaces.find(({ workspaceId }) => workspaceId === input.currentWorkspaceId) : input.workspaces.find(({ sessionIds }) => sessionIds.includes(sessionId));
2785
+ if (workspace === void 0) return none("unbound");
2786
+ const binding = sessionId === void 0 ? void 0 : input.bindings.find((candidate) => candidate.sessionId === sessionId);
2787
+ if (binding !== void 0) {
2788
+ if (binding.workspaceId !== workspace.workspaceId) return none("workspace-mismatch");
2789
+ if (binding.status === "detached") return none("detached");
2790
+ const record = input.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId);
2791
+ if (record === void 0 || record.workspaceId !== workspace.workspaceId) return none(record === void 0 ? "stale" : "workspace-mismatch");
2792
+ if (record.status !== "active") return none("stale");
2793
+ if (record.health === "repair") return none("repair");
2794
+ if (record.branch.length === 0) return none("not-ready");
2795
+ return {
2796
+ kind: "worktree",
2797
+ workspaceId: workspace.workspaceId,
2798
+ worktreeId: record.worktreeId,
2799
+ label: record.branch,
2800
+ source: "active-binding"
2801
+ };
2802
+ }
2803
+ const currentBranch = input.branches.find(({ isCurrent }) => isCurrent);
2804
+ if (currentBranch === void 0 || currentBranch.name.length === 0) return none("not-ready");
2805
+ return {
2806
+ kind: "main",
2807
+ workspaceId: workspace.workspaceId,
2808
+ label: currentBranch.name,
2809
+ source: "current-branch"
2810
+ };
2811
+ }
2812
+ //#endregion
2813
+ //#region lib/client/worktree-context-store.js
2814
+ const notReady = () => ({
2815
+ kind: "none",
2816
+ reason: "not-ready"
2817
+ });
2818
+ function scheduledRefresh() {
2819
+ let resolve;
2820
+ return {
2821
+ promise: new Promise((resolvePromise) => {
2822
+ resolve = resolvePromise;
2823
+ }),
2824
+ resolve
2825
+ };
2826
+ }
2827
+ function identityFrom(sessions, workspaces) {
2828
+ const sessionId = sessions.getSnapshot().current;
2829
+ if (sessionId === void 0) return { workspaceId: workspaces.getSnapshot().recentWorkspaceId };
2830
+ return {
2831
+ sessionId,
2832
+ workspaceId: workspaces.getSnapshot().items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
2833
+ };
2834
+ }
2835
+ /**
2836
+ * Build one browser-local current-Session projection shared by the header
2837
+ * consumer. Superseded requests may still finish on the transport, but their
2838
+ * results never become visible in the current snapshot.
2839
+ */
2840
+ function createWorktreeContextProjection(input) {
2841
+ const store = input.storeFactory({
2842
+ status: "idle",
2843
+ value: notReady()
2844
+ });
2845
+ let disposed = false;
2846
+ let generation = 0;
2847
+ let scheduled = false;
2848
+ let scheduleTicket = 0;
2849
+ let scheduledCompletion;
2850
+ let latestRefresh = Promise.resolve();
2851
+ const setPending = (identity) => {
2852
+ if (identity.workspaceId === void 0) {
2853
+ store.set({
2854
+ status: "ready",
2855
+ value: resolveWorktreeSessionContext({
2856
+ currentSessionId: identity.sessionId,
2857
+ currentWorkspaceId: identity.workspaceId,
2858
+ workspaces: input.workspaces.getSnapshot().items,
2859
+ branches: [],
2860
+ worktrees: [],
2861
+ bindings: []
2862
+ })
2863
+ });
2864
+ return;
2865
+ }
2866
+ const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === identity.workspaceId);
2867
+ store.set({
2868
+ status: "loading",
2869
+ ...identity.sessionId === void 0 ? {} : { sessionId: identity.sessionId },
2870
+ workspaceId: identity.workspaceId,
2871
+ workspaceTitle: workspace?.title,
2872
+ value: notReady()
2873
+ });
2874
+ };
2875
+ const matchesCurrent = (request, requestGeneration) => {
2876
+ if (disposed || generation !== requestGeneration) return false;
2877
+ const current = identityFrom(input.sessions, input.workspaces);
2878
+ return current.sessionId === request.sessionId && current.workspaceId === request.workspaceId;
2879
+ };
2880
+ const runRefresh = async () => {
2881
+ if (disposed) return;
2882
+ const requestGeneration = ++generation;
2883
+ const identity = identityFrom(input.sessions, input.workspaces);
2884
+ setPending(identity);
2885
+ if (identity.workspaceId === void 0) return;
2886
+ const request = {
2887
+ sessionId: identity.sessionId,
2888
+ workspaceId: identity.workspaceId
2889
+ };
2890
+ try {
2891
+ const data = await loadWorktreeView(input.manager, request.workspaceId);
2892
+ if (!matchesCurrent(request, requestGeneration)) return;
2893
+ const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId);
2894
+ if ("error" in data.readiness) {
2895
+ store.set({
2896
+ status: "error",
2897
+ ...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
2898
+ workspaceId: request.workspaceId,
2899
+ workspaceTitle: workspace?.title,
2900
+ value: notReady(),
2901
+ error: data.readiness.error
2902
+ });
2903
+ return;
2904
+ }
2905
+ store.set({
2906
+ status: "ready",
2907
+ ...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
2908
+ workspaceId: request.workspaceId,
2909
+ workspaceTitle: workspace?.title,
2910
+ value: resolveWorktreeSessionContext({
2911
+ currentSessionId: request.sessionId,
2912
+ currentWorkspaceId: request.workspaceId,
2913
+ workspaces: input.workspaces.getSnapshot().items,
2914
+ branches: data.branches,
2915
+ worktrees: data.worktrees,
2916
+ bindings: data.bindings
2917
+ })
2918
+ });
2919
+ } catch (error) {
2920
+ if (!matchesCurrent(request, requestGeneration)) return;
2921
+ store.set({
2922
+ status: "error",
2923
+ ...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
2924
+ workspaceId: request.workspaceId,
2925
+ workspaceTitle: input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId)?.title,
2926
+ value: notReady(),
2927
+ error: toWorktreeViewError(error)
2928
+ });
2929
+ }
2930
+ };
2931
+ const cancelScheduledRefresh = () => {
2932
+ scheduleTicket += 1;
2933
+ scheduled = false;
2934
+ const completion = scheduledCompletion;
2935
+ scheduledCompletion = void 0;
2936
+ completion?.resolve();
2937
+ };
2938
+ const refresh = () => {
2939
+ cancelScheduledRefresh();
2940
+ const completion = runRefresh();
2941
+ latestRefresh = completion;
2942
+ return completion;
2943
+ };
2944
+ const scheduleRefresh = () => {
2945
+ if (disposed) return;
2946
+ generation += 1;
2947
+ if (scheduled) return;
2948
+ setPending(identityFrom(input.sessions, input.workspaces));
2949
+ scheduled = true;
2950
+ const ticket = ++scheduleTicket;
2951
+ const completion = scheduledRefresh();
2952
+ scheduledCompletion = completion;
2953
+ latestRefresh = completion.promise;
2954
+ queueMicrotask(() => {
2955
+ if (disposed || ticket !== scheduleTicket) {
2956
+ completion.resolve();
2957
+ return;
2958
+ }
2959
+ scheduled = false;
2960
+ runRefresh().finally(() => {
2961
+ if (scheduledCompletion === completion) scheduledCompletion = void 0;
2962
+ completion.resolve();
2963
+ });
2964
+ });
2965
+ };
2966
+ const waitForLatestRefresh = async (workspaceId) => {
2967
+ let observed;
2968
+ while (!disposed) {
2969
+ if (workspaceId !== void 0 && identityFrom(input.sessions, input.workspaces).workspaceId !== workspaceId) return;
2970
+ const completion = latestRefresh;
2971
+ if (completion === observed) return;
2972
+ observed = completion;
2973
+ await completion;
2974
+ }
2975
+ };
2976
+ const unsubscribeSessions = input.sessions.subscribe(scheduleRefresh);
2977
+ const unsubscribeWorkspaces = input.workspaces.subscribe(scheduleRefresh);
2978
+ return {
2979
+ store,
2980
+ refresh,
2981
+ async invalidate(workspaceId) {
2982
+ if (disposed) return;
2983
+ const identity = identityFrom(input.sessions, input.workspaces);
2984
+ if (workspaceId !== void 0 && workspaceId !== identity.workspaceId) return;
2985
+ await refresh();
2986
+ await waitForLatestRefresh(workspaceId ?? identity.workspaceId);
2987
+ },
2988
+ dispose() {
2989
+ if (disposed) return;
2990
+ disposed = true;
2991
+ generation += 1;
2992
+ cancelScheduledRefresh();
2993
+ unsubscribeSessions();
2994
+ unsubscribeWorkspaces();
2995
+ store.set({
2996
+ status: "idle",
2997
+ value: notReady()
2998
+ });
2999
+ }
3000
+ };
3001
+ }
3002
+ //#endregion
2084
3003
  //#region lib/client/view-mode-store.js
2085
3004
  /** Create one root-scoped, browser-local view-mode store for the two slot entries. */
2086
3005
  function createWorktreeViewStore() {
@@ -2122,17 +3041,24 @@ window.__ModuleLoader__.load({
2122
3041
  let bindings = [];
2123
3042
  let disposed = false;
2124
3043
  let applying = false;
2125
- const apply = (nextBindings) => {
2126
- const current = list.getSnapshot();
2127
- const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
2128
- if (sameWorkspaceItems(current, next)) return;
3044
+ const nativeSet = list.set;
3045
+ const write = (next) => {
2129
3046
  applying = true;
2130
3047
  try {
2131
- list.set(next);
3048
+ nativeSet(next);
2132
3049
  } finally {
2133
3050
  applying = false;
2134
3051
  }
2135
3052
  };
3053
+ list.set = (next) => {
3054
+ write(projectVirtualWorkspaceMembership(next, bindings, bindings));
3055
+ };
3056
+ const apply = (nextBindings) => {
3057
+ const current = list.getSnapshot();
3058
+ const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
3059
+ if (sameWorkspaceItems(current, next)) return;
3060
+ write(next);
3061
+ };
2136
3062
  const replay = () => {
2137
3063
  if (disposed || applying) return;
2138
3064
  apply(bindings);
@@ -2160,6 +3086,7 @@ window.__ModuleLoader__.load({
2160
3086
  bindings = [];
2161
3087
  disposed = true;
2162
3088
  unsubscribe();
3089
+ list.set = nativeSet;
2163
3090
  }
2164
3091
  };
2165
3092
  }
@@ -2185,8 +3112,16 @@ window.__ModuleLoader__.load({
2185
3112
  const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
2186
3113
  const sessions = ctx.sessions;
2187
3114
  const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
3115
+ const contextProjection = createWorktreeContextProjection({
3116
+ sessions: ctx.sessions.list,
3117
+ workspaces: ctx.workspaces.list,
3118
+ manager,
3119
+ storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
3120
+ });
2188
3121
  ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
2189
3122
  ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
3123
+ ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
3124
+ contextProjection.refresh();
2190
3125
  const viewStore = createWorktreeViewStore();
2191
3126
  const ensureSessionWorkspace = (workspaceId, sessionId) => {
2192
3127
  virtualWorkspaceMembership.ensure({
@@ -2197,6 +3132,24 @@ window.__ModuleLoader__.load({
2197
3132
  const syncSessionWorkspaces = (bindings) => {
2198
3133
  virtualWorkspaceMembership.sync(bindings);
2199
3134
  };
3135
+ const worktreeSessionConnector = createWorktreeSessionConnector({
3136
+ manager,
3137
+ sessions: ctx.sessions.list,
3138
+ archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
3139
+ createSession: async (input) => String(await sessions.create(input)),
3140
+ ensureSessionWorkspace,
3141
+ openSession: (sessionId) => {
3142
+ ctx.sessions.open(sessionId);
3143
+ }
3144
+ });
3145
+ ctx.effect(() => () => worktreeSessionConnector.dispose(), "clutch-dsh-worktree: Worktree Session connector cleanup");
3146
+ ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
3147
+ name: "conversation.session.header.actions",
3148
+ id: "clutch-dsh-worktree-context-header",
3149
+ order: -5,
3150
+ locale: WORKTREE_NS,
3151
+ inject: () => ({ hooks: { worktreeContext: contextProjection.store } })
3152
+ }, WorktreeHeaderContext));
2200
3153
  ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
2201
3154
  name: "sidebar.footer.action",
2202
3155
  id: "clutch-dsh-worktree-mode-action",
@@ -2211,22 +3164,14 @@ window.__ModuleLoader__.load({
2211
3164
  locale: WORKTREE_NS,
2212
3165
  inject: () => ({
2213
3166
  available: true,
3167
+ hooks: { worktreeContext: contextProjection.store },
2214
3168
  manager,
2215
3169
  createWorkspace: async () => {
2216
3170
  const workspacePath = await ctx.workspaces.pickDirectory();
2217
3171
  if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
2218
3172
  },
2219
- createSessionForWorktree: (input) => createSessionForWorktree({
2220
- ...input,
2221
- createSession: (sessionInput) => sessions.create(sessionInput),
2222
- manager,
2223
- beforeOpen: (sessionId) => {
2224
- ensureSessionWorkspace(input.workspaceId, sessionId);
2225
- },
2226
- openSession: (sessionId) => {
2227
- ctx.sessions.open(sessionId);
2228
- }
2229
- }),
3173
+ createSessionForWorktree: (input) => worktreeSessionConnector.create(input),
3174
+ invalidateWorktreeContext: (workspaceId) => contextProjection.invalidate(workspaceId),
2230
3175
  createMainSession: (workspaceId) => {
2231
3176
  ctx.workspaces.startSession(workspaceId);
2232
3177
  },
@@ -2242,6 +3187,11 @@ window.__ModuleLoader__.load({
2242
3187
  insertSessionBefore: async (workspaceId, sessionId, beforeSessionId) => {
2243
3188
  await ctx.workspaces.insertSessionBefore(workspaceId, sessionId, beforeSessionId);
2244
3189
  },
3190
+ insertWorktreeBefore: (workspaceId, worktreeId, beforeWorktreeId) => manager.insertWorktreeBefore({
3191
+ workspaceId,
3192
+ worktreeId,
3193
+ beforeWorktreeId
3194
+ }),
2245
3195
  renameSession: async (sessionId, title) => {
2246
3196
  const session = ctx.sessions.binding(sessionId)?.session;
2247
3197
  if (session === void 0) throw new Error(`unknown session "${sessionId}"`);
@@ -2263,7 +3213,7 @@ window.__ModuleLoader__.load({
2263
3213
  ctx.sessions.open(sessionId);
2264
3214
  }
2265
3215
  })
2266
- }, WorktreeSurface));
3216
+ }, WorktreeOverlay));
2267
3217
  }
2268
3218
  //#endregion
2269
3219
  exports.WORKTREE_CONNECTION_CHANNEL = WORKTREE_CONNECTION_CHANNEL;