@cerbur/clutch-dsh-worktree 0.1.6 → 0.1.7

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 (116) hide show
  1. package/README.md +107 -15
  2. package/README.zh.md +86 -10
  3. package/cordis.patch.yml +21 -0
  4. package/lib/client/WorktreeContext.d.ts.map +1 -1
  5. package/lib/client/WorktreeContext.js +2 -2
  6. package/lib/client/WorktreeContext.js.map +1 -1
  7. package/lib/client/WorktreeSurface.d.ts +2 -2
  8. package/lib/client/WorktreeSurface.d.ts.map +1 -1
  9. package/lib/client/WorktreeSurface.js +270 -65
  10. package/lib/client/WorktreeSurface.js.map +1 -1
  11. package/lib/client/entry.d.ts.map +1 -1
  12. package/lib/client/entry.js +84 -2
  13. package/lib/client/entry.js.map +1 -1
  14. package/lib/client/index.d.ts +3 -0
  15. package/lib/client/index.d.ts.map +1 -1
  16. package/lib/client/index.js +2 -0
  17. package/lib/client/index.js.map +1 -1
  18. package/lib/client/locales.d.ts +58 -0
  19. package/lib/client/locales.d.ts.map +1 -1
  20. package/lib/client/locales.js +58 -0
  21. package/lib/client/locales.js.map +1 -1
  22. package/lib/client/session-view.d.ts +34 -0
  23. package/lib/client/session-view.d.ts.map +1 -1
  24. package/lib/client/session-view.js +119 -1
  25. package/lib/client/session-view.js.map +1 -1
  26. package/lib/client/worktree-connection.d.ts +4 -2
  27. package/lib/client/worktree-connection.d.ts.map +1 -1
  28. package/lib/client/worktree-connection.js +4 -0
  29. package/lib/client/worktree-connection.js.map +1 -1
  30. package/lib/client/worktree-error-copy.d.ts +2 -0
  31. package/lib/client/worktree-error-copy.d.ts.map +1 -1
  32. package/lib/client/worktree-error-copy.js +16 -0
  33. package/lib/client/worktree-error-copy.js.map +1 -1
  34. package/lib/client/worktree-permission-icon.d.ts +7 -0
  35. package/lib/client/worktree-permission-icon.d.ts.map +1 -0
  36. package/lib/client/worktree-permission-icon.js +119 -0
  37. package/lib/client/worktree-permission-icon.js.map +1 -0
  38. package/lib/client/worktree-permission.d.ts +21 -0
  39. package/lib/client/worktree-permission.d.ts.map +1 -0
  40. package/lib/client/worktree-permission.js +70 -0
  41. package/lib/client/worktree-permission.js.map +1 -0
  42. package/lib/client/worktree-session-fork.d.ts +65 -0
  43. package/lib/client/worktree-session-fork.d.ts.map +1 -0
  44. package/lib/client/worktree-session-fork.js +174 -0
  45. package/lib/client/worktree-session-fork.js.map +1 -0
  46. package/lib/client/worktree-session-order.d.ts +36 -0
  47. package/lib/client/worktree-session-order.d.ts.map +1 -0
  48. package/lib/client/worktree-session-order.js +215 -0
  49. package/lib/client/worktree-session-order.js.map +1 -0
  50. package/lib/client/worktree-session.d.ts +34 -1
  51. package/lib/client/worktree-session.d.ts.map +1 -1
  52. package/lib/client/worktree-session.js +98 -2
  53. package/lib/client/worktree-session.js.map +1 -1
  54. package/lib/client/worktree-surface-rows.d.ts +4 -4
  55. package/lib/client/worktree-surface-rows.d.ts.map +1 -1
  56. package/lib/client/worktree-surface-rows.js +132 -47
  57. package/lib/client/worktree-surface-rows.js.map +1 -1
  58. package/lib/client/worktree-surface-selectors.d.ts +2 -0
  59. package/lib/client/worktree-surface-selectors.d.ts.map +1 -1
  60. package/lib/client/worktree-surface-selectors.js +8 -0
  61. package/lib/client/worktree-surface-selectors.js.map +1 -1
  62. package/lib/client/worktree-surface-types.d.ts +46 -3
  63. package/lib/client/worktree-surface-types.d.ts.map +1 -1
  64. package/lib/client/worktree-view-actions.d.ts +8 -3
  65. package/lib/client/worktree-view-actions.d.ts.map +1 -1
  66. package/lib/client/worktree-view-actions.js +28 -2
  67. package/lib/client/worktree-view-actions.js.map +1 -1
  68. package/lib/client/worktree-view-errors.d.ts +10 -0
  69. package/lib/client/worktree-view-errors.d.ts.map +1 -1
  70. package/lib/client/worktree-view-errors.js +22 -1
  71. package/lib/client/worktree-view-errors.js.map +1 -1
  72. package/lib/client.js +1473 -201
  73. package/lib/client.js.map +1 -1
  74. package/lib/contract/index.contract.js +2 -0
  75. package/lib/contract/index.contract.js.map +1 -1
  76. package/lib/contract/index.d.ts +6 -2
  77. package/lib/contract/index.d.ts.map +1 -1
  78. package/lib/contract/index.js +4 -0
  79. package/lib/contract/index.js.map +1 -1
  80. package/lib/contract/worktree-permission.d.ts +73 -0
  81. package/lib/contract/worktree-permission.d.ts.map +1 -0
  82. package/lib/contract/worktree-permission.js +32 -0
  83. package/lib/contract/worktree-permission.js.map +1 -0
  84. package/lib/host/index.d.ts +4 -0
  85. package/lib/host/index.d.ts.map +1 -1
  86. package/lib/host/index.js +2 -0
  87. package/lib/host/index.js.map +1 -1
  88. package/lib/host/remote.d.ts +2 -2
  89. package/lib/host/remote.d.ts.map +1 -1
  90. package/lib/host/remote.js +7 -1
  91. package/lib/host/remote.js.map +1 -1
  92. package/lib/host/service.d.ts +3 -1
  93. package/lib/host/service.d.ts.map +1 -1
  94. package/lib/host/service.js +36 -2
  95. package/lib/host/service.js.map +1 -1
  96. package/lib/host/worktree-permission-manager.d.ts +14 -0
  97. package/lib/host/worktree-permission-manager.d.ts.map +1 -0
  98. package/lib/host/worktree-permission-manager.js +111 -0
  99. package/lib/host/worktree-permission-manager.js.map +1 -0
  100. package/lib/host/worktree-permission.d.ts +38 -0
  101. package/lib/host/worktree-permission.d.ts.map +1 -0
  102. package/lib/host/worktree-permission.js +156 -0
  103. package/lib/host/worktree-permission.js.map +1 -0
  104. package/lib/index.d.ts +4 -3
  105. package/lib/index.d.ts.map +1 -1
  106. package/lib/index.js +2 -1
  107. package/lib/index.js.map +1 -1
  108. package/lib/manage/worktree-permission.d.ts +3 -0
  109. package/lib/manage/worktree-permission.d.ts.map +1 -0
  110. package/lib/manage/worktree-permission.js +3 -0
  111. package/lib/manage/worktree-permission.js.map +1 -0
  112. package/lib/typert.host.js +126 -27
  113. package/lib/typert.remote-client.d.ts +5 -1
  114. package/lib/typert.remote-client.d.ts.map +1 -1
  115. package/lib/typert.remote-client.js +126 -27
  116. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -40,6 +40,8 @@ window.__ModuleLoader__.load({
40
40
  "worktree.expand": "展开 {name}",
41
41
  "worktree.collapse": "收起 {name}",
42
42
  "worktree.options": "Worktree 选项:{name}",
43
+ "worktree.copyPath": "复制路径",
44
+ "worktree.createNew": "创建新的 Worktree",
43
45
  "worktree.remove": "移除 Worktree",
44
46
  "worktree.removeDescription": "移除“{name}”?Session 会保留在 DSH 中,并作为已分离关系继续可用。",
45
47
  "worktree.removeExternalDescription": "移除“{name}”?这会删除关联的外部 Worktree 目录。Session 会保留在 DSH 中,并作为已分离关系继续可用。",
@@ -73,6 +75,23 @@ window.__ModuleLoader__.load({
73
75
  "session.expandMore": "展开其余 {count} 个会话",
74
76
  "session.collapse": "收起",
75
77
  "session.name": "会话名称",
78
+ "session.status.running": "进行中",
79
+ "session.status.subagentsRunning.one": "{n} 个子代理运行中",
80
+ "session.status.subagentsRunning.other": "{n} 个子代理运行中",
81
+ "session.status.idle": "空闲",
82
+ "session.status.waitingApproval": "等待审批",
83
+ "session.status.planReview": "计划待审",
84
+ "session.status.waitingAnswer": "等待回答",
85
+ "session.status.completed": "已完成",
86
+ copy: "复制",
87
+ "hover.copied": "已复制",
88
+ "session.time.now": "刚刚",
89
+ "session.time.minutes": "{n}分钟",
90
+ "session.time.hours": "{n}小时",
91
+ "session.time.days": "{n}天",
92
+ "session.time.months": "{n}个月",
93
+ "session.time.years": "{n}年",
94
+ "session.time.ago": "{t}前",
76
95
  "dialog.close": "关闭",
77
96
  "dialog.closeWorkspaceRename": "关闭重命名工作区对话框",
78
97
  "dialog.closeWorkspaceDelete": "关闭删除工作区对话框",
@@ -84,6 +103,14 @@ window.__ModuleLoader__.load({
84
103
  "action.retry": "重试",
85
104
  "action.retryBinding": "重试绑定",
86
105
  "action.openCreatedSession": "打开已创建的 Session",
106
+ "permission.fallbackWorkspaceWrite": "无法使用 Worktree 完全访问预设,已降级为 workspace-write;保留审批提示。",
107
+ "permission.userRestricted": "已保留你在 DSH 原生权限界面选择的限制,未自动提升此 Worktree Session。",
108
+ "permission.unverified": "无法验证 Worktree Session 的权限服务;Session 已保留,但完全访问未得到确认。",
109
+ "permission.unavailable": "Worktree Session 权限状态暂时不可用,请重试。",
110
+ "permission.fullAccessTitle": "确认启用 Worktree Full access?",
111
+ "permission.fullAccessDescription": "启用 Worktree Full access 后,此 Session 可能访问 Session 目录之外的关联 Git 元数据和 Worktree 文件。完全访问会关闭此 Session 的文件系统沙箱,但会保留审批提示;网络和进程策略不变。目标 Worktree:{cwd}",
112
+ "permission.fullAccessAcknowledge": "我已了解风险,并愿意继续",
113
+ "permission.fullAccessEnable": "启用 Worktree Full access",
87
114
  "status.loading": "正在加载工作区…",
88
115
  "error.worktreeDataUnavailable": "Worktree 数据不可用,请重试。",
89
116
  "error.gitNotInstalled": "Git 未安装或不可用,请安装 Git 后重试。",
@@ -104,6 +131,8 @@ window.__ModuleLoader__.load({
104
131
  "error.sessionRenameUnavailable": "会话重命名不可用,请重新连接后重试。",
105
132
  "error.sessionBindingFailed": "Session {sessionId} 已创建,但 Worktree 绑定失败:{reason}",
106
133
  "error.sessionAlreadyBound": "Session 已绑定到其他 Worktree,未创建新的 Session。",
134
+ "error.worktreePermissionConfirmationRequired": "Session 和绑定已保留;确认完全访问后重试,未打开 Session。",
135
+ "error.worktreePermissionFailed": "Worktree Session 权限设置失败,可重试:{reason}",
107
136
  "error.sessionListNotReady": "Session 列表尚未就绪,请重试。",
108
137
  "error.sessionFactsIncomplete": "Session 信息尚未完整,请重试。",
109
138
  "error.worktreeSessionRepairRequired": "当前 Worktree 的 Session 绑定需要修复,请重试。",
@@ -142,6 +171,8 @@ window.__ModuleLoader__.load({
142
171
  "worktree.expand": "Expand {name}",
143
172
  "worktree.collapse": "Collapse {name}",
144
173
  "worktree.options": "Worktree options for {name}",
174
+ "worktree.copyPath": "Copy path",
175
+ "worktree.createNew": "Create new Worktree",
145
176
  "worktree.remove": "Remove Worktree",
146
177
  "worktree.removeDescription": "Remove {name}? Sessions stay in DSH and remain available as detached bindings.",
147
178
  "worktree.removeExternalDescription": "Remove {name}? This deletes the linked external Worktree directory. Sessions stay in DSH and remain available as detached bindings.",
@@ -175,6 +206,23 @@ window.__ModuleLoader__.load({
175
206
  "session.expandMore": "Expand {count} more",
176
207
  "session.collapse": "Collapse",
177
208
  "session.name": "Session name",
209
+ "session.status.running": "Running",
210
+ "session.status.subagentsRunning.one": "{n} subagent running",
211
+ "session.status.subagentsRunning.other": "{n} subagents running",
212
+ "session.status.idle": "Idle",
213
+ "session.status.waitingApproval": "Waiting for approval",
214
+ "session.status.planReview": "Plan awaiting review",
215
+ "session.status.waitingAnswer": "Waiting for answer",
216
+ "session.status.completed": "Completed",
217
+ copy: "Copy",
218
+ "hover.copied": "Copied",
219
+ "session.time.now": "now",
220
+ "session.time.minutes": "{n}min",
221
+ "session.time.hours": "{n}h",
222
+ "session.time.days": "{n}d",
223
+ "session.time.months": "{n}mo",
224
+ "session.time.years": "{n}y",
225
+ "session.time.ago": "{t} ago",
178
226
  "dialog.close": "Close",
179
227
  "dialog.closeWorkspaceRename": "Close Rename Workspace dialog",
180
228
  "dialog.closeWorkspaceDelete": "Close Delete Workspace dialog",
@@ -186,6 +234,14 @@ window.__ModuleLoader__.load({
186
234
  "action.retry": "Retry",
187
235
  "action.retryBinding": "Retry Binding",
188
236
  "action.openCreatedSession": "Open Created Session",
237
+ "permission.fallbackWorkspaceWrite": "The Worktree Full Access preset is unavailable; fell back to workspace-write with approval prompts enabled.",
238
+ "permission.userRestricted": "The restriction selected in DSH’s native permission UI was preserved; this Worktree Session was not elevated.",
239
+ "permission.unverified": "The Worktree Session permission service could not be verified; the Session was retained, but Full Access is not confirmed.",
240
+ "permission.unavailable": "The Worktree Session permission state is temporarily unavailable; retry the request.",
241
+ "permission.fullAccessTitle": "Enable Worktree Full access?",
242
+ "permission.fullAccessDescription": "Worktree Full access lets this Session access linked Git metadata and Worktree files outside the Session directory. It disables filesystem confinement for this Session while keeping approval prompts enabled; network and process policy are unchanged. Target Worktree: {cwd}",
243
+ "permission.fullAccessAcknowledge": "I understand the risks and want to continue",
244
+ "permission.fullAccessEnable": "Enable Worktree Full access",
189
245
  "status.loading": "Loading Workspaces…",
190
246
  "error.worktreeDataUnavailable": "Worktree data is unavailable. Retry the request.",
191
247
  "error.gitNotInstalled": "Git is not installed or unavailable. Install Git and retry.",
@@ -206,6 +262,8 @@ window.__ModuleLoader__.load({
206
262
  "error.sessionRenameUnavailable": "Session rename is unavailable; retry after reconnecting.",
207
263
  "error.sessionBindingFailed": "Session {sessionId} was created, but Worktree binding failed: {reason}",
208
264
  "error.sessionAlreadyBound": "The Session is already bound to another Worktree; no new Session was created.",
265
+ "error.worktreePermissionConfirmationRequired": "The Session and binding were retained; confirm Full Access and retry. The Session was not opened.",
266
+ "error.worktreePermissionFailed": "Worktree Session permission setup failed; retryable error: {reason}",
209
267
  "error.sessionListNotReady": "The Session list is not ready yet; retry the request.",
210
268
  "error.sessionFactsIncomplete": "Session facts are incomplete; retry the request.",
211
269
  "error.worktreeSessionRepairRequired": "The current Worktree Session binding needs repair; retry the request.",
@@ -231,7 +289,9 @@ window.__ModuleLoader__.load({
231
289
  removeWorktree: "worktreeManager/removeWorktree",
232
290
  insertWorktreeBefore: "worktreeManager/insertWorktreeBefore",
233
291
  listBindings: "worktreeManager/listBindings",
234
- bindSession: "worktreeManager/bindSession"
292
+ bindSession: "worktreeManager/bindSession",
293
+ ensureWorktreePermission: "worktreeManager/ensureWorktreePermission",
294
+ normalizeDetachedWorktreePermissions: "worktreeManager/normalizeDetachedWorktreePermissions"
235
295
  });
236
296
  /** Browser-safe error shared by transport, Gateway, endpoint and domain failures. */
237
297
  var WorktreeConnectionError = class extends Error {
@@ -246,14 +306,14 @@ window.__ModuleLoader__.load({
246
306
  this.retryable = options.retryable;
247
307
  }
248
308
  };
249
- function isRecord$1(value) {
309
+ function isRecord$2(value) {
250
310
  return typeof value === "object" && value !== null && !Array.isArray(value);
251
311
  }
252
312
  function isWorktreeError(value) {
253
- return isRecord$1(value) && typeof value.code === "string" && typeof value.message === "string" && isRecord$1(value.details);
313
+ return isRecord$2(value) && typeof value.code === "string" && typeof value.message === "string" && isRecord$2(value.details);
254
314
  }
255
315
  function isWorktreeRemoteResult(value) {
256
- if (!isRecord$1(value) || typeof value.ok !== "boolean") return false;
316
+ if (!isRecord$2(value) || typeof value.ok !== "boolean") return false;
257
317
  return value.ok || isWorktreeError(value.error) && value.error.details !== void 0;
258
318
  }
259
319
  function disposedError() {
@@ -274,7 +334,7 @@ window.__ModuleLoader__.load({
274
334
  });
275
335
  }
276
336
  function gatewayFailure(endpoint, result) {
277
- const rawDetails = isRecord$1(result.error.details) ? result.error.details : {};
337
+ const rawDetails = isRecord$2(result.error.details) ? result.error.details : {};
278
338
  throw new WorktreeConnectionError({
279
339
  code: result.error.code,
280
340
  message: result.error.message,
@@ -343,6 +403,8 @@ window.__ModuleLoader__.load({
343
403
  },
344
404
  listBindings: (input) => invoke("listBindings", input),
345
405
  bindSession: (input) => invoke("bindSession", input),
406
+ ensureWorktreePermission: (input) => invoke("ensureWorktreePermission", input),
407
+ normalizeDetachedWorktreePermissions: (input) => invoke("normalizeDetachedWorktreePermissions", input),
346
408
  dispose() {
347
409
  if (disposed) return;
348
410
  disposed = true;
@@ -352,7 +414,7 @@ window.__ModuleLoader__.load({
352
414
  };
353
415
  }
354
416
  //#endregion
355
- //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_0c53e50f-f169-4c5e-9664-1c2d58ae1212/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
417
+ //#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
356
418
  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-contextHoverTitle {\n max-width: 360px;\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContextHost {\n position: absolute;\n z-index: 1;\n display: block;\n width: max-content;\n max-width: 260px;\n min-height: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContext {\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: auto;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n";
357
419
  const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
358
420
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
@@ -375,18 +437,25 @@ window.__ModuleLoader__.load({
375
437
  function WorktreeContextLabel({ value, t }) {
376
438
  if (value.kind === "none") return null;
377
439
  const ariaLabel = value.kind === "main" ? t("context.main", { name: value.label }) : t("context.worktree", { name: value.label });
378
- return (0, react_jsx_runtime.jsxs)("span", {
379
- className: worktree_context_css_default.headerContext,
380
- title: value.label,
381
- "aria-label": ariaLabel,
382
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {
383
- size: 14,
384
- className: worktree_context_css_default.contextIcon,
385
- "aria-hidden": "true"
386
- }), (0, react_jsx_runtime.jsx)("span", {
387
- className: worktree_context_css_default.contextLabel,
440
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
441
+ anchor: (0, react_jsx_runtime.jsxs)("span", {
442
+ className: worktree_context_css_default.headerContext,
443
+ title: value.label,
444
+ "aria-label": ariaLabel,
445
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {
446
+ size: 14,
447
+ className: worktree_context_css_default.contextIcon,
448
+ "aria-hidden": "true"
449
+ }), (0, react_jsx_runtime.jsx)("span", {
450
+ className: worktree_context_css_default.contextLabel,
451
+ children: value.label
452
+ })]
453
+ }),
454
+ content: (0, react_jsx_runtime.jsx)("div", {
455
+ className: worktree_context_css_default.contextHoverTitle,
388
456
  children: value.label
389
- })]
457
+ }),
458
+ openDelayMs: 500
390
459
  });
391
460
  }
392
461
  /** Render the current branch or active Worktree branch beside the Session title. */
@@ -399,8 +468,8 @@ window.__ModuleLoader__.load({
399
468
  });
400
469
  }
401
470
  //#endregion
402
- //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_0c53e50f-f169-4c5e-9664-1c2d58ae1212/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
403
- 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 display: inline-flex;\n min-width: 0;\n align-items: center;\n height: 22px;\n overflow: hidden;\n font-weight: 400;\n line-height: 22px;\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-worktreeModalTabs {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab {\n border: 0;\n border-bottom: 2px solid transparent;\n padding: 4px 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab[aria-selected='true'] {\n border-bottom-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportCandidates {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect {\n width: 100%;\n min-width: 0;\n padding: 7px 8px;\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: 13px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportError {\n display: grid;\n gap: 8px;\n}\n\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-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-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.-cerbur-clutch-dsh-worktree-worktreeImportSelect: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: 16px;\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: calc(100% - 22px);\n margin-left: 22px;\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[data-session-current='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] .-cerbur-clutch-dsh-worktree-treeSessionContent {\n font-weight: 600;\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-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";
471
+ //#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
472
+ 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 display: inline-flex;\n min-width: 0;\n align-items: center;\n height: 22px;\n overflow: hidden;\n font-weight: 400;\n line-height: 22px;\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-worktreeModalTabs {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab {\n border: 0;\n border-bottom: 2px solid transparent;\n padding: 4px 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab[aria-selected='true'] {\n border-bottom-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportCandidates {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect {\n width: 100%;\n min-width: 0;\n padding: 7px 8px;\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: 13px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportError {\n display: grid;\n gap: 8px;\n}\n\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-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-notice {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\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-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:\n 11px/16px ui-monospace,\n SFMono-Regular,\n Menlo,\n 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.-cerbur-clutch-dsh-worktree-worktreeImportSelect: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/* Native Session hover card: full title, relative time, and current status. */\n.-cerbur-clutch-dsh-worktree-sessionHoverContent {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTitle {\n color: #FFFFFF;\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: break-word;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTime {\n color: #CFD3D6;\n font-size: 12px;\n line-height: 16px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverStatus {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #ADB2B8;\n font-size: 12px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-groupActivity {\n position: absolute;\n top: 0;\n right: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n visibility: hidden;\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: visible;\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: 16px;\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: calc(100% - 22px);\n margin-left: 22px;\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[data-session-current='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] .-cerbur-clutch-dsh-worktree-treeSessionContent {\n font-weight: 600;\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-sessionTrailing {\n position: relative;\n display: inline-flex;\n flex: 0 0 52px;\n align-items: center;\n justify-content: flex-end;\n width: 52px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-rowActions {\n position: absolute;\n inset: 0;\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta {\n color: var(--dsw-alias-label-tertiary);\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionStatus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionTime {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 4px;\n font-size: 12px;\n line-height: 20px;\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-rowActions {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-cerbur-clutch-dsh-worktree-sessionMeta {\n visibility: hidden;\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.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-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-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";
404
473
  const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
405
474
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
406
475
  const tag = document.createElement("style");
@@ -427,6 +496,7 @@ window.__ModuleLoader__.load({
427
496
  "workspaceLabel": "-cerbur-clutch-dsh-worktree-workspaceLabel",
428
497
  "content": "-cerbur-clutch-dsh-worktree-content",
429
498
  "error": "-cerbur-clutch-dsh-worktree-error",
499
+ "notice": "-cerbur-clutch-dsh-worktree-notice",
430
500
  "retryButton": "-cerbur-clutch-dsh-worktree-retryButton",
431
501
  "actionButton": "-cerbur-clutch-dsh-worktree-actionButton",
432
502
  "recoveryActions": "-cerbur-clutch-dsh-worktree-recoveryActions",
@@ -459,9 +529,14 @@ window.__ModuleLoader__.load({
459
529
  "worktreeState": "-cerbur-clutch-dsh-worktree-worktreeState",
460
530
  "workspaceTitle": "-cerbur-clutch-dsh-worktree-workspaceTitle",
461
531
  "worktreeHoverTitle": "-cerbur-clutch-dsh-worktree-worktreeHoverTitle",
532
+ "sessionHoverContent": "-cerbur-clutch-dsh-worktree-sessionHoverContent",
533
+ "sessionHoverTitle": "-cerbur-clutch-dsh-worktree-sessionHoverTitle",
534
+ "sessionHoverTime": "-cerbur-clutch-dsh-worktree-sessionHoverTime",
535
+ "sessionHoverStatus": "-cerbur-clutch-dsh-worktree-sessionHoverStatus",
462
536
  "treeActionSlot": "-cerbur-clutch-dsh-worktree-treeActionSlot",
463
537
  "workspaceActions": "-cerbur-clutch-dsh-worktree-workspaceActions",
464
538
  "menuAction": "-cerbur-clutch-dsh-worktree-menuAction",
539
+ "groupActivity": "-cerbur-clutch-dsh-worktree-groupActivity",
465
540
  "dropBefore": "-cerbur-clutch-dsh-worktree-dropBefore",
466
541
  "dropAfter": "-cerbur-clutch-dsh-worktree-dropAfter",
467
542
  "treeChildren": "-cerbur-clutch-dsh-worktree-treeChildren",
@@ -470,7 +545,11 @@ window.__ModuleLoader__.load({
470
545
  "worktreeGroup": "-cerbur-clutch-dsh-worktree-worktreeGroup",
471
546
  "treeSessionRow": "-cerbur-clutch-dsh-worktree-treeSessionRow",
472
547
  "treeSessionContent": "-cerbur-clutch-dsh-worktree-treeSessionContent",
548
+ "sessionTrailing": "-cerbur-clutch-dsh-worktree-sessionTrailing",
549
+ "sessionMeta": "-cerbur-clutch-dsh-worktree-sessionMeta",
473
550
  "rowActions": "-cerbur-clutch-dsh-worktree-rowActions",
551
+ "sessionStatus": "-cerbur-clutch-dsh-worktree-sessionStatus",
552
+ "sessionTime": "-cerbur-clutch-dsh-worktree-sessionTime",
474
553
  "sessionOverflowButton": "-cerbur-clutch-dsh-worktree-sessionOverflowButton",
475
554
  "renameInput": "-cerbur-clutch-dsh-worktree-renameInput",
476
555
  "renameError": "-cerbur-clutch-dsh-worktree-renameError",
@@ -746,27 +825,27 @@ window.__ModuleLoader__.load({
746
825
  //#region lib/client/worktree-expand-state.js
747
826
  /** Browser-local storage identity; never sent to DSH or the plugin sidecar. */
748
827
  const WORKTREE_EXPAND_STATE_STORAGE_KEY = "clutch-dsh-worktree.expand-state";
749
- function emptyState() {
828
+ function emptyState$1() {
750
829
  return {
751
830
  collapsedWorkspaceIds: {},
752
831
  collapsedMainWorkspaceIds: {},
753
832
  collapsedWorktreeIds: {}
754
833
  };
755
834
  }
756
- function isRecord(value) {
835
+ function isRecord$1(value) {
757
836
  return typeof value === "object" && value !== null && !Array.isArray(value);
758
837
  }
759
- function normalizeIds(value) {
760
- if (!isRecord(value)) return {};
838
+ function normalizeIds$1(value) {
839
+ if (!isRecord$1(value)) return {};
761
840
  return Object.fromEntries(Object.entries(value).filter(([id, collapsed]) => id.length > 0 && collapsed === true));
762
841
  }
763
842
  /** Turn any persisted JSON value into the current state shape. */
764
843
  function normalizeWorktreeExpandState(value) {
765
- const source = isRecord(value) ? value : {};
844
+ const source = isRecord$1(value) ? value : {};
766
845
  return {
767
- collapsedWorkspaceIds: normalizeIds(source.collapsedWorkspaceIds),
768
- collapsedMainWorkspaceIds: normalizeIds(source.collapsedMainWorkspaceIds),
769
- collapsedWorktreeIds: normalizeIds(source.collapsedWorktreeIds)
846
+ collapsedWorkspaceIds: normalizeIds$1(source.collapsedWorkspaceIds),
847
+ collapsedMainWorkspaceIds: normalizeIds$1(source.collapsedMainWorkspaceIds),
848
+ collapsedWorktreeIds: normalizeIds$1(source.collapsedWorktreeIds)
770
849
  };
771
850
  }
772
851
  function isWorkspaceExpanded(state, workspaceId) {
@@ -790,9 +869,9 @@ window.__ModuleLoader__.load({
790
869
  function createWorktreeExpandStateStore(snapshotStoreFactory) {
791
870
  let store;
792
871
  try {
793
- store = snapshotStoreFactory(emptyState(), { persist: { name: WORKTREE_EXPAND_STATE_STORAGE_KEY } });
872
+ store = snapshotStoreFactory(emptyState$1(), { persist: { name: WORKTREE_EXPAND_STATE_STORAGE_KEY } });
794
873
  } catch {
795
- store = snapshotStoreFactory(emptyState());
874
+ store = snapshotStoreFactory(emptyState$1());
796
875
  }
797
876
  store.set(normalizeWorktreeExpandState(store.getSnapshot()));
798
877
  return Object.assign(store, { actions: {
@@ -883,6 +962,14 @@ window.__ModuleLoader__.load({
883
962
  function reason(error, t) {
884
963
  return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
885
964
  }
965
+ function formatWorktreePermissionNotice(result, t) {
966
+ switch (result.status) {
967
+ case "fallback-workspace-write": return t("permission.fallbackWorkspaceWrite");
968
+ case "user-restricted": return t("permission.userRestricted");
969
+ case "unverified": return t("permission.unverified");
970
+ default: return t("permission.unavailable");
971
+ }
972
+ }
886
973
  function formatWorktreeViewError(error, t) {
887
974
  switch (error.code) {
888
975
  case "CLIENT_DISPOSED": return t("error.connectionDisposed");
@@ -908,6 +995,8 @@ window.__ModuleLoader__.load({
908
995
  reason: reason(error, t)
909
996
  });
910
997
  case "SESSION_ALREADY_BOUND": return t("error.sessionAlreadyBound");
998
+ case "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED": return t("error.worktreePermissionConfirmationRequired");
999
+ case "WORKTREE_PERMISSION_FAILED": return t("error.worktreePermissionFailed", { reason: reason(error, t) });
911
1000
  case "SESSION_LIST_NOT_READY": return t("error.sessionListNotReady");
912
1001
  case "SESSION_FACTS_INCOMPLETE": return t("error.sessionFactsIncomplete");
913
1002
  case "WORKTREE_SESSION_REPAIR_REQUIRED": return t("error.worktreeSessionRepairRequired");
@@ -919,6 +1008,127 @@ window.__ModuleLoader__.load({
919
1008
  }
920
1009
  //#endregion
921
1010
  //#region lib/client/session-view.js
1011
+ function isPendingInteractionStatus(value) {
1012
+ return value === "approval" || value === "plan-review" || value === "question";
1013
+ }
1014
+ function validUpdatedAt(value) {
1015
+ return value !== void 0 && Number.isFinite(value);
1016
+ }
1017
+ /**
1018
+ * Native-compatible subagent lineage index. The upstream runtime's public client
1019
+ * entry is a browser module-loader bundle, so keeping this pure mirror local lets
1020
+ * the browser Consumer and its Node tests share the same status semantics.
1021
+ */
1022
+ function indexSubagentDescendants(summaries) {
1023
+ const indexed = /* @__PURE__ */ new Map();
1024
+ for (const descendant of Object.values(summaries)) {
1025
+ if (descendant.origin !== "subagent") continue;
1026
+ const seen = /* @__PURE__ */ new Set();
1027
+ let current = descendant;
1028
+ while (current?.origin === "subagent" && current.parentId !== void 0 && !seen.has(current.id)) {
1029
+ seen.add(current.id);
1030
+ const aggregate = indexed.get(current.parentId);
1031
+ if (aggregate === void 0) indexed.set(current.parentId, {
1032
+ count: 1,
1033
+ runningCount: descendant.running ? 1 : 0
1034
+ });
1035
+ else {
1036
+ aggregate.count += 1;
1037
+ if (descendant.running) aggregate.runningCount += 1;
1038
+ }
1039
+ current = summaries[current.parentId];
1040
+ }
1041
+ }
1042
+ return indexed;
1043
+ }
1044
+ /** Native Workspace relative-time buckets, kept pure for deterministic rendering/tests. */
1045
+ function relativeTime(updatedAt, now) {
1046
+ if (!validUpdatedAt(updatedAt) || !Number.isFinite(now)) return void 0;
1047
+ const MIN = 6e4;
1048
+ const HOUR = 36e5;
1049
+ const DAY = 864e5;
1050
+ const diff = Math.max(0, now - updatedAt);
1051
+ if (diff < MIN) return {
1052
+ unit: "now",
1053
+ n: 0
1054
+ };
1055
+ if (diff < HOUR) return {
1056
+ unit: "minutes",
1057
+ n: Math.floor(diff / MIN)
1058
+ };
1059
+ if (diff < DAY) return {
1060
+ unit: "hours",
1061
+ n: Math.floor(diff / HOUR)
1062
+ };
1063
+ if (diff < 30 * DAY) return {
1064
+ unit: "days",
1065
+ n: Math.floor(diff / DAY)
1066
+ };
1067
+ if (diff < 365 * DAY) return {
1068
+ unit: "months",
1069
+ n: Math.floor(diff / (30 * DAY))
1070
+ };
1071
+ return {
1072
+ unit: "years",
1073
+ n: Math.floor(diff / (365 * DAY))
1074
+ };
1075
+ }
1076
+ /** Match native Workspace status priority while retaining the aggregate subagent count. */
1077
+ function sessionStatus(session, runningSubagentCount) {
1078
+ const count = Number.isFinite(runningSubagentCount) && runningSubagentCount > 0 ? Math.floor(runningSubagentCount) : 0;
1079
+ if (isPendingInteractionStatus(session.pendingInteraction)) return {
1080
+ state: "warning",
1081
+ labelKey: session.pendingInteraction === "approval" ? "waitingApproval" : session.pendingInteraction === "plan-review" ? "planReview" : "waitingAnswer",
1082
+ runningSubagentCount: count
1083
+ };
1084
+ if (session.running === true) return {
1085
+ state: "ongoing",
1086
+ labelKey: "running",
1087
+ runningSubagentCount: count
1088
+ };
1089
+ if (count > 0) return {
1090
+ state: "ongoing",
1091
+ labelKey: "subagentsRunning",
1092
+ runningSubagentCount: count
1093
+ };
1094
+ if (session.completed === true) return {
1095
+ state: "done",
1096
+ labelKey: "completed",
1097
+ runningSubagentCount: 0
1098
+ };
1099
+ return {
1100
+ state: "done",
1101
+ labelKey: "idle",
1102
+ runningSubagentCount: 0
1103
+ };
1104
+ }
1105
+ function toLineageSummary(sessionId, summary) {
1106
+ return {
1107
+ id: sessionId,
1108
+ running: summary.running === true,
1109
+ ...summary.parentId === void 0 ? {} : { parentId: summary.parentId },
1110
+ ...summary.origin === "subagent" ? { origin: "subagent" } : {}
1111
+ };
1112
+ }
1113
+ /** Derive row and group activity facts from one retained DSH Session snapshot. */
1114
+ function deriveSessionPresentationIndex(sessions) {
1115
+ const descendants = indexSubagentDescendants(Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => [sessionId, toLineageSummary(sessionId, summary)])));
1116
+ return Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => {
1117
+ const runningSubagentCount = descendants.get(sessionId)?.runningCount ?? 0;
1118
+ return [sessionId, {
1119
+ status: sessionStatus(summary, runningSubagentCount),
1120
+ running: summary.running === true,
1121
+ ongoing: summary.running === true || runningSubagentCount > 0,
1122
+ runningSubagentCount,
1123
+ completed: summary.completed === true,
1124
+ ...validUpdatedAt(summary.updatedAt) ? { updatedAt: summary.updatedAt } : {}
1125
+ }];
1126
+ }));
1127
+ }
1128
+ /** Aggregate only live ongoing activity; callers decide which IDs are in the group. */
1129
+ function hasOngoingSession(sessionIds, presentations) {
1130
+ return sessionIds.some((sessionId) => presentations[sessionId]?.ongoing === true);
1131
+ }
922
1132
  /** Read the native blank flag without inferring blankness from title or id. */
923
1133
  function isBlankSession(sessionId, sessions) {
924
1134
  return sessions.byId[sessionId]?.blank === true;
@@ -943,6 +1153,193 @@ window.__ModuleLoader__.load({
943
1153
  return (summary?.displayTitle ?? sessionId).toLocaleLowerCase().includes(normalizedQuery);
944
1154
  }
945
1155
  //#endregion
1156
+ //#region lib/client/worktree-session-order.js
1157
+ /** Browser-only persistence key; this state never crosses the DSH or sidecar boundary. */
1158
+ const WORKTREE_SESSION_ORDER_STORAGE_KEY = "clutch-dsh-worktree.session-order";
1159
+ function emptyState() {
1160
+ return { accounts: {} };
1161
+ }
1162
+ function isRecord(value) {
1163
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1164
+ }
1165
+ function isValidTimestamp(value) {
1166
+ return typeof value === "number" && Number.isFinite(value);
1167
+ }
1168
+ function normalizeIds(value) {
1169
+ if (!Array.isArray(value)) return [];
1170
+ const seen = /* @__PURE__ */ new Set();
1171
+ const ids = [];
1172
+ for (const id of value) {
1173
+ if (typeof id !== "string" || id.length === 0 || seen.has(id)) continue;
1174
+ seen.add(id);
1175
+ ids.push(id);
1176
+ }
1177
+ return ids;
1178
+ }
1179
+ function normalizeAccount(value) {
1180
+ if (!isRecord(value)) return void 0;
1181
+ const order = normalizeIds(value.order);
1182
+ const allowed = new Set(order);
1183
+ const observedUpdatedAt = {};
1184
+ if (isRecord(value.observedUpdatedAt)) {
1185
+ for (const [id, timestamp] of Object.entries(value.observedUpdatedAt)) if (allowed.has(id) && isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
1186
+ }
1187
+ return {
1188
+ order,
1189
+ observedUpdatedAt
1190
+ };
1191
+ }
1192
+ /** Normalize persisted state without trusting any browser-local JSON shape. */
1193
+ function normalizeWorktreeSessionOrderState(value) {
1194
+ if (!isRecord(value) || !isRecord(value.accounts)) return emptyState();
1195
+ const accounts = {};
1196
+ for (const [accountKey, account] of Object.entries(value.accounts)) {
1197
+ if (accountKey.length === 0) continue;
1198
+ const normalized = normalizeAccount(account);
1199
+ if (normalized !== void 0) accounts[accountKey] = normalized;
1200
+ }
1201
+ return { accounts };
1202
+ }
1203
+ function validIds(ids) {
1204
+ return normalizeIds([...ids]);
1205
+ }
1206
+ function sameRecord(left, right) {
1207
+ if (left === void 0) return false;
1208
+ const leftKeys = Object.keys(left);
1209
+ const rightKeys = Object.keys(right);
1210
+ if (leftKeys.length !== rightKeys.length) return false;
1211
+ return rightKeys.every((key) => left[key] === right[key]);
1212
+ }
1213
+ function sameAccount(left, right) {
1214
+ return left !== void 0 && left.order.length === right.order.length && left.order.every((id, index) => id === right.order[index]) && sameRecord(left.observedUpdatedAt, right.observedUpdatedAt);
1215
+ }
1216
+ /**
1217
+ * Native-style activity order transition. The first observation records timestamps
1218
+ * without turning an existing list into a recency sort.
1219
+ */
1220
+ function nextSessionOrderAccount(input) {
1221
+ const baseIds = validIds(input.baseIds);
1222
+ const previous = input.previous;
1223
+ if (previous === void 0) {
1224
+ const observedUpdatedAt = {};
1225
+ for (const id of baseIds) {
1226
+ const timestamp = input.updatedAtById[id];
1227
+ if (isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
1228
+ }
1229
+ return {
1230
+ order: baseIds,
1231
+ observedUpdatedAt
1232
+ };
1233
+ }
1234
+ const available = new Set(baseIds);
1235
+ const order = [];
1236
+ const seen = /* @__PURE__ */ new Set();
1237
+ for (const id of previous.order) if (available.has(id) && !seen.has(id)) {
1238
+ seen.add(id);
1239
+ order.push(id);
1240
+ }
1241
+ for (const id of baseIds) if (!seen.has(id)) {
1242
+ seen.add(id);
1243
+ order.push(id);
1244
+ }
1245
+ const observedUpdatedAt = {};
1246
+ const previousIds = new Set(previous.order);
1247
+ const newlyObserved = [];
1248
+ const promoted = [];
1249
+ for (const [index, id] of order.entries()) {
1250
+ if (!previousIds.has(id)) newlyObserved.push(id);
1251
+ const previousTimestamp = previous.observedUpdatedAt[id];
1252
+ const timestamp = input.updatedAtById[id];
1253
+ if (isValidTimestamp(previousTimestamp)) observedUpdatedAt[id] = previousTimestamp;
1254
+ if (isValidTimestamp(timestamp)) {
1255
+ if (!isValidTimestamp(previousTimestamp) || timestamp > previousTimestamp) {
1256
+ if (isValidTimestamp(previousTimestamp)) promoted.push({
1257
+ id,
1258
+ timestamp,
1259
+ index
1260
+ });
1261
+ observedUpdatedAt[id] = Math.max(observedUpdatedAt[id] ?? timestamp, timestamp);
1262
+ }
1263
+ }
1264
+ }
1265
+ promoted.sort((left, right) => right.timestamp - left.timestamp || left.index - right.index);
1266
+ const promotedIds = /* @__PURE__ */ new Set([...newlyObserved, ...promoted.map(({ id }) => id)]);
1267
+ return {
1268
+ order: [
1269
+ ...newlyObserved,
1270
+ ...promoted.map(({ id }) => id),
1271
+ ...order.filter((id) => !promotedIds.has(id))
1272
+ ],
1273
+ observedUpdatedAt
1274
+ };
1275
+ }
1276
+ /** Apply a successful manual drag without dropping IDs hidden by search. */
1277
+ function reorderSessionIds(order, sessionId, overSessionId, half) {
1278
+ const next = order.filter((id) => id !== sessionId);
1279
+ const targetIndex = next.indexOf(overSessionId);
1280
+ if (targetIndex === -1) return [...order];
1281
+ next.splice(half === "before" ? targetIndex : targetIndex + 1, 0, sessionId);
1282
+ return next;
1283
+ }
1284
+ function cloneAccount(account) {
1285
+ return {
1286
+ order: [...account.order],
1287
+ observedUpdatedAt: { ...account.observedUpdatedAt }
1288
+ };
1289
+ }
1290
+ /** Create one apply-scoped, browser-local Session ordering store. */
1291
+ function createWorktreeSessionOrderStore(snapshotStoreFactory) {
1292
+ let store;
1293
+ try {
1294
+ store = snapshotStoreFactory(emptyState(), { persist: { name: WORKTREE_SESSION_ORDER_STORAGE_KEY } });
1295
+ } catch {
1296
+ store = snapshotStoreFactory(emptyState());
1297
+ }
1298
+ store.set(normalizeWorktreeSessionOrderState(store.getSnapshot()));
1299
+ let disposed = false;
1300
+ return Object.assign(store, {
1301
+ actions: {
1302
+ reconcile: (accountKey, baseIds, updatedAtById) => {
1303
+ if (disposed || accountKey.length === 0) return;
1304
+ store.update((draft) => {
1305
+ const next = nextSessionOrderAccount({
1306
+ baseIds,
1307
+ updatedAtById,
1308
+ previous: draft.accounts[accountKey]
1309
+ });
1310
+ if (sameAccount(draft.accounts[accountKey], next)) return;
1311
+ draft.accounts[accountKey] = cloneAccount(next);
1312
+ });
1313
+ },
1314
+ setOrder: (accountKey, order) => {
1315
+ if (disposed || accountKey.length === 0) return;
1316
+ store.update((draft) => {
1317
+ const current = draft.accounts[accountKey] ?? {
1318
+ order: [],
1319
+ observedUpdatedAt: {}
1320
+ };
1321
+ const next = {
1322
+ order: validIds(order),
1323
+ observedUpdatedAt: { ...current.observedUpdatedAt }
1324
+ };
1325
+ if (sameAccount(current, next)) return;
1326
+ draft.accounts[accountKey] = next;
1327
+ });
1328
+ },
1329
+ retain: (accountKeys) => {
1330
+ if (disposed) return;
1331
+ store.update((draft) => {
1332
+ const allowed = new Set(accountKeys);
1333
+ for (const accountKey of Object.keys(draft.accounts)) if (!allowed.has(accountKey)) delete draft.accounts[accountKey];
1334
+ });
1335
+ }
1336
+ },
1337
+ dispose: () => {
1338
+ disposed = true;
1339
+ }
1340
+ });
1341
+ }
1342
+ //#endregion
946
1343
  //#region lib/client/worktree-view-errors.js
947
1344
  /** A DSH Session exists even when the external Worktree binding needs repair. */
948
1345
  var WorktreeSessionBindingError = class extends Error {
@@ -964,6 +1361,25 @@ window.__ModuleLoader__.load({
964
1361
  this.cause = cause;
965
1362
  }
966
1363
  };
1364
+ /** A Session is retained after permission confirmation or permission setup needs retry. */
1365
+ var WorktreeSessionPermissionError = class extends Error {
1366
+ code;
1367
+ retryable = true;
1368
+ details;
1369
+ sessionId;
1370
+ createdSession;
1371
+ cause;
1372
+ constructor(sessionId, createdSession, cause) {
1373
+ const reason = cause instanceof Error ? cause.message : cause === void 0 ? "" : String(cause);
1374
+ super(reason);
1375
+ this.name = "WorktreeSessionPermissionError";
1376
+ this.code = cause === void 0 ? "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED" : "WORKTREE_PERMISSION_FAILED";
1377
+ this.details = { sessionId };
1378
+ this.sessionId = sessionId;
1379
+ this.createdSession = createdSession;
1380
+ this.cause = cause;
1381
+ }
1382
+ };
967
1383
  function recordDetails(value) {
968
1384
  if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
969
1385
  const details = value.details;
@@ -974,7 +1390,7 @@ window.__ModuleLoader__.load({
974
1390
  function toWorktreeViewError(error) {
975
1391
  if (typeof error === "object" && error !== null) {
976
1392
  const candidate = error;
977
- const details = error instanceof WorktreeSessionBindingError ? {
1393
+ const details = error instanceof WorktreeSessionBindingError || error instanceof WorktreeSessionPermissionError ? {
978
1394
  ...recordDetails(error) ?? {},
979
1395
  sessionId: error.sessionId
980
1396
  } : recordDetails(error);
@@ -1016,6 +1432,21 @@ window.__ModuleLoader__.load({
1016
1432
  }
1017
1433
  throw new Error("Unable to generate an available default Worktree name.");
1018
1434
  }
1435
+ /** Generate the next available numeric sibling name for a selected Worktree. */
1436
+ function createNumberedWorktreeName(baseName, existingNames) {
1437
+ const normalizedBaseName = baseName.trim();
1438
+ const usedNames = new Set([...existingNames].map((name) => name.trim()));
1439
+ const numberedBase = normalizedBaseName.match(/^(.*)-(\d+)$/);
1440
+ const prefix = numberedBase?.[1] || normalizedBaseName || "worktree";
1441
+ const parsedNumber = numberedBase === null ? 1 : Number(numberedBase[2]);
1442
+ let number = Number.isSafeInteger(parsedNumber) ? parsedNumber + 1 : 2;
1443
+ for (let attempt = 0; attempt < 1e4; attempt += 1) {
1444
+ const candidate = `${prefix}-${number}`;
1445
+ if (!usedNames.has(candidate)) return candidate;
1446
+ number += 1;
1447
+ }
1448
+ throw new Error("Unable to generate an available numbered Worktree name.");
1449
+ }
1019
1450
  /** Resolve a row-half drop target to native-style optional before-anchor semantics. */
1020
1451
  function resolveWorktreeMove(worktreeIds, sourceWorktreeId, targetWorktreeId, half) {
1021
1452
  const sourceIndex = worktreeIds.indexOf(sourceWorktreeId);
@@ -1028,11 +1459,19 @@ window.__ModuleLoader__.load({
1028
1459
  return beforeWorktreeId === void 0 ? {} : { beforeWorktreeId };
1029
1460
  }
1030
1461
  /** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
1031
- async function executeWorktreeAction(manager, action) {
1462
+ async function executeWorktreeAction(manager, action, permission, onPermissionResult) {
1032
1463
  if (action.type === "createWorktree") return manager.createWorktree(action.input);
1033
1464
  if (action.type === "importWorktree") return manager.importWorktree(action.input);
1034
1465
  if (action.type === "removeWorktree") {
1035
1466
  await manager.removeWorktree(action.input);
1467
+ const result = await permission?.normalizeDetachedWorktreePermissions({
1468
+ workspaceId: action.input.workspaceId,
1469
+ worktreeId: action.input.worktreeId
1470
+ });
1471
+ if (result !== void 0) onPermissionResult?.({
1472
+ workspaceId: action.input.workspaceId,
1473
+ worktreeId: action.input.worktreeId
1474
+ }, result);
1036
1475
  return;
1037
1476
  }
1038
1477
  }
@@ -1051,7 +1490,7 @@ window.__ModuleLoader__.load({
1051
1490
  } catch (error) {
1052
1491
  throw new WorktreeSessionBindingError(sessionId, error);
1053
1492
  }
1054
- input.beforeOpen?.(sessionId);
1493
+ await input.beforeOpen?.(sessionId);
1055
1494
  input.openSession(sessionId);
1056
1495
  return sessionId;
1057
1496
  }
@@ -1210,6 +1649,54 @@ window.__ModuleLoader__.load({
1210
1649
  this.details = details;
1211
1650
  }
1212
1651
  };
1652
+ /**
1653
+ * Keep the confirmation and second permission call in one place for new,
1654
+ * reused, and retried Sessions. The Host still validates the relation.
1655
+ */
1656
+ async function ensureWorktreeSessionPermission(input) {
1657
+ if (input.permission === void 0) return;
1658
+ const request = {
1659
+ workspaceId: input.workspaceId,
1660
+ worktreeId: input.worktreeId,
1661
+ sessionId: input.sessionId,
1662
+ binding: "active"
1663
+ };
1664
+ let result;
1665
+ try {
1666
+ result = await input.permission.ensureWorktreePermission(request);
1667
+ } catch (error) {
1668
+ throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
1669
+ }
1670
+ if (result.status === "confirmation-required") {
1671
+ let confirmed;
1672
+ try {
1673
+ confirmed = input.confirmFullAccess === void 0 ? false : await input.confirmFullAccess({
1674
+ workspaceId: input.workspaceId,
1675
+ worktreeId: input.worktreeId,
1676
+ sessionId: input.sessionId,
1677
+ cwd: input.cwd
1678
+ });
1679
+ } catch (error) {
1680
+ throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
1681
+ }
1682
+ if (!confirmed) throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
1683
+ try {
1684
+ result = await input.permission.ensureWorktreePermission({
1685
+ ...request,
1686
+ confirmed: true
1687
+ });
1688
+ } catch (error) {
1689
+ throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
1690
+ }
1691
+ }
1692
+ if (result.status === "confirmation-required") throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
1693
+ input.onPermissionResult?.({
1694
+ workspaceId: input.workspaceId,
1695
+ worktreeId: input.worktreeId,
1696
+ sessionId: input.sessionId,
1697
+ cwd: input.cwd
1698
+ }, result);
1699
+ }
1213
1700
  function resolveWorktreeSessionAction(input) {
1214
1701
  if (input.target.status !== "active" || input.target.health === "repair") return {
1215
1702
  kind: "reject",
@@ -1273,6 +1760,16 @@ window.__ModuleLoader__.load({
1273
1760
  } catch (error) {
1274
1761
  throw new WorktreeSessionBindingError(input.pending.sessionId, error);
1275
1762
  }
1763
+ await ensureWorktreeSessionPermission({
1764
+ permission: input.permission,
1765
+ confirmFullAccess: input.confirmFullAccess,
1766
+ onPermissionResult: input.onPermissionResult,
1767
+ sessionId: input.pending.sessionId,
1768
+ workspaceId: input.pending.workspaceId,
1769
+ worktreeId: input.pending.worktreeId,
1770
+ cwd: input.pending.cwd,
1771
+ createdSession: true
1772
+ });
1276
1773
  input.ensureSessionWorkspace(input.pending.workspaceId, input.pending.sessionId);
1277
1774
  input.openSession(input.pending.sessionId);
1278
1775
  return input.pending.sessionId;
@@ -1296,6 +1793,16 @@ window.__ModuleLoader__.load({
1296
1793
  bindings
1297
1794
  });
1298
1795
  if (action.kind === "open-bound") {
1796
+ await ensureWorktreeSessionPermission({
1797
+ permission: options.permission,
1798
+ confirmFullAccess: options.confirmFullAccess,
1799
+ onPermissionResult: options.onPermissionResult,
1800
+ sessionId: action.sessionId,
1801
+ workspaceId: input.workspaceId,
1802
+ worktreeId: input.worktreeId,
1803
+ cwd: input.cwd,
1804
+ createdSession: false
1805
+ });
1299
1806
  options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
1300
1807
  if (!disposed) options.openSession(action.sessionId);
1301
1808
  return action.sessionId;
@@ -1310,6 +1817,16 @@ window.__ModuleLoader__.load({
1310
1817
  } catch (error) {
1311
1818
  throw new WorktreeSessionBindingError(action.sessionId, error);
1312
1819
  }
1820
+ await ensureWorktreeSessionPermission({
1821
+ permission: options.permission,
1822
+ confirmFullAccess: options.confirmFullAccess,
1823
+ onPermissionResult: options.onPermissionResult,
1824
+ sessionId: action.sessionId,
1825
+ workspaceId: input.workspaceId,
1826
+ worktreeId: input.worktreeId,
1827
+ cwd: input.cwd,
1828
+ createdSession: false
1829
+ });
1313
1830
  if (!disposed) {
1314
1831
  options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
1315
1832
  if (!disposed) options.openSession(action.sessionId);
@@ -1322,9 +1839,18 @@ window.__ModuleLoader__.load({
1322
1839
  ...input,
1323
1840
  createSession: options.createSession,
1324
1841
  manager: options.manager,
1325
- beforeOpen: (sessionId) => {
1842
+ beforeOpen: async (sessionId) => {
1326
1843
  if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
1327
- options.ensureSessionWorkspace(input.workspaceId, sessionId);
1844
+ await ensureWorktreeSessionPermission({
1845
+ permission: options.permission,
1846
+ confirmFullAccess: options.confirmFullAccess,
1847
+ onPermissionResult: options.onPermissionResult,
1848
+ sessionId,
1849
+ workspaceId: input.workspaceId,
1850
+ worktreeId: input.worktreeId,
1851
+ cwd: input.cwd,
1852
+ createdSession: true
1853
+ });
1328
1854
  },
1329
1855
  openSession: (sessionId) => {
1330
1856
  if (!disposed) options.openSession(sessionId);
@@ -1734,6 +2260,13 @@ window.__ModuleLoader__.load({
1734
2260
  "session-group:" + location.groupKey
1735
2261
  ];
1736
2262
  }
2263
+ function shouldRevealCurrentSessionGroup(sessionIds, currentSessionId) {
2264
+ if (currentSessionId === void 0 || sessionIds.length <= 5) return false;
2265
+ return sessionIds.indexOf(currentSessionId) >= 5;
2266
+ }
2267
+ function isSessionGroupAutoExpanded(sessionIds, currentSessionId, currentSessionRevealActive) {
2268
+ return currentSessionRevealActive && shouldRevealCurrentSessionGroup(sessionIds, currentSessionId);
2269
+ }
1737
2270
  //#endregion
1738
2271
  //#region lib/client/worktree-session-position.js
1739
2272
  function scrollCurrentSessionIntoView(root, sessionId) {
@@ -1749,8 +2282,65 @@ window.__ModuleLoader__.load({
1749
2282
  const rect = event.currentTarget.getBoundingClientRect();
1750
2283
  return event.clientY < rect.top + rect.height / 2 ? "before" : "after";
1751
2284
  }
2285
+ function sessionStatusLabel(t, status) {
2286
+ switch (status.labelKey) {
2287
+ case "running": return t("session.status.running");
2288
+ case "subagentsRunning": return t(status.runningSubagentCount === 1 ? "session.status.subagentsRunning.one" : "session.status.subagentsRunning.other", { n: status.runningSubagentCount });
2289
+ case "idle": return t("session.status.idle");
2290
+ case "waitingApproval": return t("session.status.waitingApproval");
2291
+ case "planReview": return t("session.status.planReview");
2292
+ case "waitingAnswer": return t("session.status.waitingAnswer");
2293
+ case "completed": return t("session.status.completed");
2294
+ }
2295
+ }
2296
+ function sessionTimeLabel(t, value) {
2297
+ switch (value.unit) {
2298
+ case "now": return t("session.time.now");
2299
+ case "minutes": return t("session.time.minutes", { n: value.n });
2300
+ case "hours": return t("session.time.hours", { n: value.n });
2301
+ case "days": return t("session.time.days", { n: value.n });
2302
+ case "months": return t("session.time.months", { n: value.n });
2303
+ case "years": return t("session.time.years", { n: value.n });
2304
+ }
2305
+ }
2306
+ /** Native Workspace hover-card time copy, including the trailing "ago" marker. */
2307
+ function sessionHoverTimeLabel(t, value) {
2308
+ const label = sessionTimeLabel(t, value);
2309
+ return value.unit === "now" ? label : t("session.time.ago", { t: label });
2310
+ }
2311
+ /** Native Workspace hover-card status list, including a secondary subagent status when relevant. */
2312
+ function sessionHoverStatuses(presentation) {
2313
+ if (presentation.runningSubagentCount === 0 || presentation.status.labelKey === "subagentsRunning") return [presentation.status];
2314
+ return [presentation.status, {
2315
+ state: "ongoing",
2316
+ labelKey: "subagentsRunning",
2317
+ runningSubagentCount: presentation.runningSubagentCount
2318
+ }];
2319
+ }
2320
+ /** Native Workspace Session hover-card details, adapted to the Worktree row projection. */
2321
+ function WorktreeSessionHoverContent({ label, blank, presentation, t }) {
2322
+ const statuses = presentation === void 0 ? [] : sessionHoverStatuses(presentation);
2323
+ const timeValue = !blank && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
2324
+ return (0, react_jsx_runtime.jsxs)("div", {
2325
+ className: worktree_css_default.sessionHoverContent,
2326
+ children: [
2327
+ (0, react_jsx_runtime.jsx)("div", {
2328
+ className: worktree_css_default.sessionHoverTitle,
2329
+ children: label
2330
+ }),
2331
+ !blank && timeValue !== void 0 && (0, react_jsx_runtime.jsx)("div", {
2332
+ className: worktree_css_default.sessionHoverTime,
2333
+ children: sessionHoverTimeLabel(t, timeValue)
2334
+ }),
2335
+ statuses.map((status) => (0, react_jsx_runtime.jsxs)("div", {
2336
+ className: worktree_css_default.sessionHoverStatus,
2337
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: status.state }), (0, react_jsx_runtime.jsx)("span", { children: sessionStatusLabel(t, status) })]
2338
+ }, `${status.labelKey}-${status.runningSubagentCount}`))
2339
+ ]
2340
+ });
2341
+ }
1752
2342
  /** Workspace row using the native DSH menu, fixed action column, and drag contract. */
1753
- function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
2343
+ function WorktreeWorkspaceRow({ t, workspace, expanded, hasOngoingSession, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
1754
2344
  const workspaceMenuItems = [{
1755
2345
  id: "rename",
1756
2346
  label: t("workspace.rename"),
@@ -1767,6 +2357,7 @@ window.__ModuleLoader__.load({
1767
2357
  return (0, react_jsx_runtime.jsxs)("div", {
1768
2358
  className: `${worktree_css_default.workspaceRow} ${markerClass}`,
1769
2359
  "data-workspace-drag": drag.active ? "active" : void 0,
2360
+ "data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
1770
2361
  "data-menu-open": menuOpen || void 0,
1771
2362
  draggable: true,
1772
2363
  onClick: () => {
@@ -1812,50 +2403,61 @@ window.__ModuleLoader__.load({
1812
2403
  }),
1813
2404
  (0, react_jsx_runtime.jsxs)("span", {
1814
2405
  className: `${worktree_css_default.treeActionSlot} ${worktree_css_default.workspaceActions}`,
1815
- children: [(0, react_jsx_runtime.jsx)("span", {
1816
- className: worktree_css_default.menuAction,
1817
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
1818
- open: menuOpen,
1819
- onClose: () => {
1820
- onMenuOpenChange(false);
1821
- },
1822
- items: workspaceMenuItems,
1823
- onSelect: (id) => {
1824
- onMenuOpenChange(false);
1825
- if (id === "rename") onRename();
1826
- if (id === "delete") onDelete();
1827
- },
1828
- portal: true,
1829
- closeOnPointerLeave: true,
1830
- anchor: (0, react_jsx_runtime.jsx)("button", {
1831
- type: "button",
1832
- className: worktree_css_default.iconButton,
1833
- "data-workspace-menu": true,
1834
- "aria-label": t("workspace.options", { name: workspace.title }),
1835
- onClick: (event) => {
1836
- event.stopPropagation();
1837
- onMenuOpenChange(!menuOpen);
2406
+ children: [
2407
+ (0, react_jsx_runtime.jsx)("span", {
2408
+ className: worktree_css_default.groupActivity,
2409
+ "data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
2410
+ role: hasOngoingSession && !expanded ? "img" : void 0,
2411
+ "aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
2412
+ title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
2413
+ children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
2414
+ }),
2415
+ (0, react_jsx_runtime.jsx)("span", {
2416
+ className: worktree_css_default.menuAction,
2417
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
2418
+ open: menuOpen,
2419
+ onClose: () => {
2420
+ onMenuOpenChange(false);
1838
2421
  },
1839
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2422
+ items: workspaceMenuItems,
2423
+ onSelect: (id) => {
2424
+ onMenuOpenChange(false);
2425
+ if (id === "rename") onRename();
2426
+ if (id === "delete") onDelete();
2427
+ },
2428
+ portal: true,
2429
+ closeOnPointerLeave: true,
2430
+ anchor: (0, react_jsx_runtime.jsx)("button", {
2431
+ type: "button",
2432
+ className: worktree_css_default.iconButton,
2433
+ "data-workspace-menu": true,
2434
+ "aria-label": t("workspace.options", { name: workspace.title }),
2435
+ onClick: (event) => {
2436
+ event.stopPropagation();
2437
+ onMenuOpenChange(!menuOpen);
2438
+ },
2439
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2440
+ })
1840
2441
  })
2442
+ }),
2443
+ (0, react_jsx_runtime.jsx)("button", {
2444
+ type: "button",
2445
+ className: worktree_css_default.iconButton,
2446
+ "data-add-worktree": true,
2447
+ "aria-label": t("workspace.addWorktree", { name: workspace.title }),
2448
+ onClick: (event) => {
2449
+ event.stopPropagation();
2450
+ onCreateWorktree();
2451
+ },
2452
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
1841
2453
  })
1842
- }), (0, react_jsx_runtime.jsx)("button", {
1843
- type: "button",
1844
- className: worktree_css_default.iconButton,
1845
- "data-add-worktree": true,
1846
- "aria-label": t("workspace.addWorktree", { name: workspace.title }),
1847
- onClick: (event) => {
1848
- event.stopPropagation();
1849
- onCreateWorktree();
1850
- },
1851
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
1852
- })]
2454
+ ]
1853
2455
  })
1854
2456
  ]
1855
2457
  });
1856
2458
  }
1857
2459
  /** Shared Main/Worktree group row with parameterized icon, state, and actions. */
1858
- function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
2460
+ function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, hasOngoingSession, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
1859
2461
  const main = kind === "main";
1860
2462
  const markerClass = drag?.marker === "before" ? worktree_css_default.dropBefore : drag?.marker === "after" ? worktree_css_default.dropAfter : "";
1861
2463
  const dragProps = drag === void 0 ? {} : {
@@ -1882,6 +2484,7 @@ window.__ModuleLoader__.load({
1882
2484
  className: `${worktree_css_default.worktreeRow} ${markerClass}`,
1883
2485
  "data-main-group": main ? "true" : void 0,
1884
2486
  "data-main-expanded": main ? String(expanded) : void 0,
2487
+ "data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
1885
2488
  "data-menu-open": menu?.open ? "true" : void 0,
1886
2489
  "data-worktree-drag": drag?.active ? "active" : void 0,
1887
2490
  ...dragProps,
@@ -1916,50 +2519,77 @@ window.__ModuleLoader__.load({
1916
2519
  }),
1917
2520
  (0, react_jsx_runtime.jsxs)("span", {
1918
2521
  className: worktree_css_default.treeActionSlot,
1919
- children: [menu !== void 0 && (0, react_jsx_runtime.jsx)("span", {
1920
- className: worktree_css_default.menuAction,
1921
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
1922
- open: menu.open,
1923
- onClose: () => {
1924
- menu.onOpenChange(false);
1925
- },
1926
- items: [{
1927
- id: "remove",
1928
- label: t("worktree.remove"),
1929
- icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}),
1930
- danger: true,
1931
- disabled: menu.disabled
1932
- }],
1933
- onSelect: (id) => {
1934
- menu.onOpenChange(false);
1935
- if (id === "remove") menu.onRemove();
1936
- },
1937
- portal: true,
1938
- closeOnPointerLeave: true,
1939
- anchor: (0, react_jsx_runtime.jsx)("button", {
1940
- type: "button",
1941
- className: worktree_css_default.iconButton,
1942
- "data-worktree-menu": true,
1943
- "aria-label": t("worktree.options", { name: menu.label }),
1944
- onClick: (event) => {
1945
- event.stopPropagation();
1946
- menu.onOpenChange(!menu.open);
2522
+ children: [
2523
+ (0, react_jsx_runtime.jsx)("span", {
2524
+ className: worktree_css_default.groupActivity,
2525
+ "data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
2526
+ role: hasOngoingSession && !expanded ? "img" : void 0,
2527
+ "aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
2528
+ title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
2529
+ children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
2530
+ }),
2531
+ menu !== void 0 && (0, react_jsx_runtime.jsx)("span", {
2532
+ className: worktree_css_default.menuAction,
2533
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
2534
+ open: menu.open,
2535
+ onClose: () => {
2536
+ menu.onOpenChange(false);
1947
2537
  },
1948
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2538
+ items: [
2539
+ ...menu.showCreate ? [{
2540
+ id: "create",
2541
+ label: t("worktree.createNew"),
2542
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {}),
2543
+ disabled: menu.disabled || menu.onCreateWorktree === void 0
2544
+ }] : [],
2545
+ {
2546
+ id: "copy-path",
2547
+ label: t("worktree.copyPath"),
2548
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}),
2549
+ disabled: menu.disabled
2550
+ },
2551
+ ...menu.showRemove ? [{
2552
+ id: "remove",
2553
+ label: t("worktree.remove"),
2554
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}),
2555
+ danger: true,
2556
+ disabled: menu.disabled || menu.onRemove === void 0
2557
+ }] : []
2558
+ ],
2559
+ onSelect: (id) => {
2560
+ menu.onOpenChange(false);
2561
+ if (id === "create" && menu.showCreate) menu.onCreateWorktree?.();
2562
+ if (id === "copy-path") (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(menu.copyPath);
2563
+ if (id === "remove" && menu.showRemove) menu.onRemove?.();
2564
+ },
2565
+ portal: true,
2566
+ closeOnPointerLeave: true,
2567
+ anchor: (0, react_jsx_runtime.jsx)("button", {
2568
+ type: "button",
2569
+ className: worktree_css_default.iconButton,
2570
+ "data-worktree-menu": true,
2571
+ "aria-label": t("worktree.options", { name: menu.label }),
2572
+ onClick: (event) => {
2573
+ event.stopPropagation();
2574
+ menu.onOpenChange(!menu.open);
2575
+ },
2576
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2577
+ })
1949
2578
  })
2579
+ }),
2580
+ onCreateSession !== void 0 && (0, react_jsx_runtime.jsx)("button", {
2581
+ type: "button",
2582
+ className: worktree_css_default.iconButton,
2583
+ "data-add-main-session": main ? "true" : void 0,
2584
+ "data-add-session": main ? void 0 : "true",
2585
+ "aria-label": t("worktree.addSession", { name: workspaceTitle }),
2586
+ onClick: (event) => {
2587
+ event.stopPropagation();
2588
+ onCreateSession();
2589
+ },
2590
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
1950
2591
  })
1951
- }), onCreateSession !== void 0 && (0, react_jsx_runtime.jsx)("button", {
1952
- type: "button",
1953
- className: worktree_css_default.iconButton,
1954
- "data-add-main-session": main ? "true" : void 0,
1955
- "data-add-session": main ? void 0 : "true",
1956
- "aria-label": t("worktree.addSession", { name: workspaceTitle }),
1957
- onClick: (event) => {
1958
- event.stopPropagation();
1959
- onCreateSession();
1960
- },
1961
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
1962
- })]
2592
+ ]
1963
2593
  })
1964
2594
  ]
1965
2595
  });
@@ -1975,7 +2605,7 @@ window.__ModuleLoader__.load({
1975
2605
  });
1976
2606
  }
1977
2607
  /** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
1978
- function WorktreeSessionRow({ t, sessionId, blank, current, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
2608
+ function WorktreeSessionRow({ t, sessionId, blank, current, label, drag, actionPending, onOpen, onRename, onFork, onArchive, presentation }) {
1979
2609
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
1980
2610
  const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
1981
2611
  const sessionMenuItems = [
@@ -1998,73 +2628,107 @@ window.__ModuleLoader__.load({
1998
2628
  disabled: onArchive === void 0 || actionPending
1999
2629
  }
2000
2630
  ];
2001
- return (0, react_jsx_runtime.jsxs)("div", {
2002
- className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
2003
- "data-session-id": sessionId,
2004
- "data-session-blank": blank ? "true" : void 0,
2005
- "data-session-current": current ? "true" : void 0,
2006
- "data-session-drag": drag.active ? "active" : void 0,
2007
- "data-menu-open": menuOpen || void 0,
2008
- role: "treeitem",
2009
- "aria-current": current ? "true" : void 0,
2010
- draggable: true,
2011
- onDragStart: (event) => {
2012
- event.dataTransfer.effectAllowed = "move";
2013
- event.dataTransfer.setData("text/plain", sessionId);
2014
- drag.start();
2015
- },
2016
- onDragEnd: drag.end,
2017
- onDragOver: (event) => {
2018
- if (!drag.active) return;
2019
- event.preventDefault();
2020
- event.dataTransfer.dropEffect = "move";
2021
- drag.hover(rowHalf(event));
2022
- },
2023
- onDrop: (event) => {
2024
- if (!drag.active) return;
2025
- event.preventDefault();
2026
- drag.drop(rowHalf(event));
2027
- },
2028
- children: [(0, react_jsx_runtime.jsx)("button", {
2029
- type: "button",
2030
- className: worktree_css_default.treeSessionContent,
2031
- onClick: onOpen,
2032
- children: (0, react_jsx_runtime.jsx)("span", {
2033
- className: worktree_css_default.sessionLabel,
2034
- children: label
2035
- })
2036
- }), !blank && (0, react_jsx_runtime.jsx)("span", {
2037
- className: worktree_css_default.rowActions,
2038
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
2039
- open: menuOpen,
2040
- onClose: () => {
2041
- setMenuOpen(false);
2042
- },
2043
- items: sessionMenuItems,
2044
- onSelect: (id) => {
2045
- setMenuOpen(false);
2046
- if (id === "rename") onRename?.(sessionId, label);
2047
- if (id === "fork") onFork?.(sessionId);
2048
- if (id === "archive") onArchive?.(sessionId);
2049
- },
2050
- portal: true,
2051
- closeOnPointerLeave: true,
2052
- anchor: (0, react_jsx_runtime.jsx)("button", {
2053
- type: "button",
2054
- className: worktree_css_default.iconButton,
2055
- "data-session-menu": true,
2056
- "aria-label": t("session.options", { name: label }),
2057
- onClick: (event) => {
2058
- event.stopPropagation();
2059
- setMenuOpen((current) => !current);
2060
- },
2061
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2631
+ const statusLabel = presentation === void 0 ? void 0 : sessionStatusLabel(t, presentation.status);
2632
+ const showTrailingStatus = !blank && presentation !== void 0 && (presentation.status.state !== "done" || presentation.completed);
2633
+ const timeValue = !blank && !showTrailingStatus && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
2634
+ const timeLabel = timeValue === void 0 ? void 0 : sessionTimeLabel(t, timeValue);
2635
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
2636
+ anchor: (0, react_jsx_runtime.jsxs)("div", {
2637
+ className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
2638
+ "data-session-id": sessionId,
2639
+ "data-session-blank": blank ? "true" : void 0,
2640
+ "data-session-current": current ? "true" : void 0,
2641
+ "data-session-drag": drag.active ? "active" : void 0,
2642
+ "data-menu-open": menuOpen || void 0,
2643
+ role: "treeitem",
2644
+ "aria-current": current ? "true" : void 0,
2645
+ draggable: true,
2646
+ onDragStart: (event) => {
2647
+ event.dataTransfer.effectAllowed = "move";
2648
+ event.dataTransfer.setData("text/plain", sessionId);
2649
+ drag.start();
2650
+ },
2651
+ onDragEnd: drag.end,
2652
+ onDragOver: (event) => {
2653
+ if (!drag.active) return;
2654
+ event.preventDefault();
2655
+ event.dataTransfer.dropEffect = "move";
2656
+ drag.hover(rowHalf(event));
2657
+ },
2658
+ onDrop: (event) => {
2659
+ if (!drag.active) return;
2660
+ event.preventDefault();
2661
+ drag.drop(rowHalf(event));
2662
+ },
2663
+ children: [(0, react_jsx_runtime.jsx)("button", {
2664
+ type: "button",
2665
+ className: worktree_css_default.treeSessionContent,
2666
+ onClick: onOpen,
2667
+ children: (0, react_jsx_runtime.jsx)("span", {
2668
+ className: worktree_css_default.sessionLabel,
2669
+ children: label
2062
2670
  })
2063
- })
2064
- })]
2671
+ }), !blank && (0, react_jsx_runtime.jsxs)("span", {
2672
+ className: worktree_css_default.sessionTrailing,
2673
+ children: [(0, react_jsx_runtime.jsx)("span", {
2674
+ className: worktree_css_default.sessionMeta,
2675
+ children: showTrailingStatus && presentation !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
2676
+ className: worktree_css_default.sessionStatus,
2677
+ "data-session-status": statusLabel,
2678
+ role: "img",
2679
+ "aria-label": statusLabel,
2680
+ title: statusLabel,
2681
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: presentation.status.state })
2682
+ }) : timeLabel !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
2683
+ className: worktree_css_default.sessionTime,
2684
+ "data-session-time": true,
2685
+ children: timeLabel
2686
+ }) : null
2687
+ }), (0, react_jsx_runtime.jsx)("span", {
2688
+ className: worktree_css_default.rowActions,
2689
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
2690
+ open: menuOpen,
2691
+ onClose: () => {
2692
+ setMenuOpen(false);
2693
+ },
2694
+ items: sessionMenuItems,
2695
+ onSelect: (id) => {
2696
+ setMenuOpen(false);
2697
+ if (id === "rename") onRename?.(sessionId, label);
2698
+ if (id === "fork") onFork?.(sessionId);
2699
+ if (id === "archive") onArchive?.(sessionId);
2700
+ },
2701
+ portal: true,
2702
+ closeOnPointerLeave: true,
2703
+ anchor: (0, react_jsx_runtime.jsx)("button", {
2704
+ type: "button",
2705
+ className: worktree_css_default.iconButton,
2706
+ "data-session-menu": true,
2707
+ "aria-label": t("session.options", { name: label }),
2708
+ onClick: (event) => {
2709
+ event.stopPropagation();
2710
+ setMenuOpen((current) => !current);
2711
+ },
2712
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
2713
+ })
2714
+ })
2715
+ })]
2716
+ })]
2717
+ }),
2718
+ content: (0, react_jsx_runtime.jsx)(WorktreeSessionHoverContent, {
2719
+ label,
2720
+ blank,
2721
+ presentation,
2722
+ t
2723
+ }),
2724
+ openDelayMs: 500,
2725
+ disabled: menuOpen || drag.active,
2726
+ copyText: blank ? void 0 : label,
2727
+ copyLabel: t("copy"),
2728
+ copiedLabel: t("hover.copied")
2065
2729
  });
2066
2730
  }
2067
- function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, currentSessionId, expanded, actionPending, sessions, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
2731
+ function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, currentSessionId, expanded, actionPending, sessions, sessionPresentations, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
2068
2732
  const visibleSessionIds = expanded ? sessionIds : sessionIds.slice(0, 5);
2069
2733
  const sameGroupDrag = dragState?.groupKey === groupKey;
2070
2734
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
@@ -2073,6 +2737,7 @@ window.__ModuleLoader__.load({
2073
2737
  blank: isBlankSession(sessionId, sessions),
2074
2738
  current: sessionId === currentSessionId,
2075
2739
  label: sessionLabel(sessionId, sessions, t),
2740
+ presentation: sessionPresentations[sessionId],
2076
2741
  drag: {
2077
2742
  active: sameGroupDrag,
2078
2743
  marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
@@ -2124,6 +2789,33 @@ window.__ModuleLoader__.load({
2124
2789
  status: "idle",
2125
2790
  views: []
2126
2791
  };
2792
+ const EMPTY_PERMISSION_NOTICE = void 0;
2793
+ const EMPTY_PERMISSION_NOTICE_SUBSCRIBE = () => () => {};
2794
+ const EMPTY_PERMISSION_NOTICE_SNAPSHOT = () => EMPTY_PERMISSION_NOTICE;
2795
+ const EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE = () => () => {};
2796
+ const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => void 0;
2797
+ const EMPTY_FORK_RECOVERY_SNAPSHOT = {
2798
+ revision: 0,
2799
+ pending: []
2800
+ };
2801
+ const EMPTY_FORK_RECOVERY_STORE = {
2802
+ getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
2803
+ subscribe: () => () => {}
2804
+ };
2805
+ function updatedAtById(sessionIds, sessions) {
2806
+ return Object.fromEntries(sessionIds.map((sessionId) => [sessionId, sessions.byId[sessionId]?.updatedAt]));
2807
+ }
2808
+ function forkRecoveryError(recovery) {
2809
+ const error = toNativeWorktreeViewError(recovery.error);
2810
+ return {
2811
+ ...error,
2812
+ code: error.code === "WORKTREE_VIEW_FAILED" ? "SESSION_BINDING_FAILED" : error.code,
2813
+ details: {
2814
+ ...error.details ?? {},
2815
+ sessionId: recovery.childSessionId
2816
+ }
2817
+ };
2818
+ }
2127
2819
  function useStableWorkspaceIds(workspaces) {
2128
2820
  const next = workspaces.map((workspace) => workspace.workspaceId);
2129
2821
  const previousRef = (0, react.useRef)([]);
@@ -2135,14 +2827,30 @@ window.__ModuleLoader__.load({
2135
2827
  * Peer Worktree navigation surface. It keeps the original DSH Workspace mode
2136
2828
  * intact and renders a browser-local Workspace → Worktree → Session projection.
2137
2829
  */
2138
- function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, manager, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
2830
+ function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, sessionOrder, manager, permission, confirmFullAccess, fullAccessConfirmation, onPermissionResult, onPermissionNotice, permissionNotice, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, forkRecovery, retryForkSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
2139
2831
  const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
2140
2832
  const sessions = useSessions((state) => state);
2141
2833
  const workspaces = useWorkspaces((state) => state);
2834
+ const forkRecoveryStore = forkRecovery ?? EMPTY_FORK_RECOVERY_STORE;
2835
+ const forkRecoverySnapshot = (0, react.useSyncExternalStore)(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
2142
2836
  const currentSessionId = sessions.current;
2143
2837
  const workspaceIds = useStableWorkspaceIds(workspaces.items);
2144
2838
  const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
2145
2839
  const expandSnapshot = (0, react.useSyncExternalStore)(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
2840
+ const permissionNoticeSnapshot = (0, react.useSyncExternalStore)(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
2841
+ const fullAccessConfirmationSnapshot = (0, react.useSyncExternalStore)(fullAccessConfirmation?.subscribe ?? EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT);
2842
+ const fullAccessConfirmationKey = fullAccessConfirmationSnapshot === void 0 ? "" : [
2843
+ fullAccessConfirmationSnapshot.workspaceId,
2844
+ fullAccessConfirmationSnapshot.worktreeId,
2845
+ fullAccessConfirmationSnapshot.sessionId,
2846
+ fullAccessConfirmationSnapshot.cwd
2847
+ ].join("\0");
2848
+ const [fullAccessAcknowledged, setFullAccessAcknowledged] = (0, react.useState)(false);
2849
+ (0, react.useEffect)(() => {
2850
+ setFullAccessAcknowledged(false);
2851
+ }, [fullAccessConfirmationKey]);
2852
+ const sessionOrderSnapshot = (0, react.useSyncExternalStore)(sessionOrder.subscribe, sessionOrder.getSnapshot, sessionOrder.getSnapshot);
2853
+ const sessionPresentations = (0, react.useMemo)(() => deriveSessionPresentationIndex(sessions), [sessions.byId]);
2146
2854
  const readStateRef = (0, react.useRef)(readState);
2147
2855
  readStateRef.current = readState;
2148
2856
  const [searchQuery, setSearchQuery] = (0, react.useState)("");
@@ -2161,6 +2869,7 @@ window.__ModuleLoader__.load({
2161
2869
  });
2162
2870
  const [selectedImportPath, setSelectedImportPath] = (0, react.useState)();
2163
2871
  const [openWorkspaceMenuId, setOpenWorkspaceMenuId] = (0, react.useState)();
2872
+ const [openMainMenuId, setOpenMainMenuId] = (0, react.useState)();
2164
2873
  const [openWorktreeMenuId, setOpenWorktreeMenuId] = (0, react.useState)();
2165
2874
  const [worktreeRemoval, setWorktreeRemoval] = (0, react.useState)();
2166
2875
  const [selectedBranch, setSelectedBranch] = (0, react.useState)("");
@@ -2168,6 +2877,7 @@ window.__ModuleLoader__.load({
2168
2877
  const [pendingSessionBinding, setPendingSessionBinding] = (0, react.useState)();
2169
2878
  const [actionError, setActionError] = (0, react.useState)();
2170
2879
  const [actionPending, setActionPending] = (0, react.useState)(false);
2880
+ const [forkRetryKey, setForkRetryKey] = (0, react.useState)();
2171
2881
  const [sessionRenameTarget, setSessionRenameTarget] = (0, react.useState)();
2172
2882
  const [sessionRenameDraft, setSessionRenameDraft] = (0, react.useState)("");
2173
2883
  const [sessionRenamePending, setSessionRenamePending] = (0, react.useState)(false);
@@ -2187,6 +2897,7 @@ window.__ModuleLoader__.load({
2187
2897
  const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
2188
2898
  const worktreeDropCommitted = (0, react.useRef)(false);
2189
2899
  const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
2900
+ const forkRecoveryRevisionRef = (0, react.useRef)(forkRecoverySnapshot.revision);
2190
2901
  const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader());
2191
2902
  const modalReadViewRef = (0, react.useRef)();
2192
2903
  const importCandidatesGuard = (0, react.useRef)(createWorktreeRefreshGuard());
@@ -2265,6 +2976,20 @@ window.__ModuleLoader__.load({
2265
2976
  setReadState(EMPTY_READ_STATE);
2266
2977
  }
2267
2978
  }, [mode, refresh]);
2979
+ (0, react.useEffect)(() => {
2980
+ if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision) return;
2981
+ forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
2982
+ if (mode !== "worktree" || manager === void 0) return;
2983
+ refresh({
2984
+ preserveCurrent: readStateRef.current.status === "ready",
2985
+ invalidateContext: false
2986
+ }).catch(() => {});
2987
+ }, [
2988
+ forkRecoverySnapshot.revision,
2989
+ manager,
2990
+ mode,
2991
+ refresh
2992
+ ]);
2268
2993
  (0, react.useEffect)(() => {
2269
2994
  if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
2270
2995
  syncSessionWorkspaces(readState.views.flatMap((view) => view.bindings.map((binding) => ({
@@ -2277,6 +3002,60 @@ window.__ModuleLoader__.load({
2277
3002
  syncSessionWorkspaces
2278
3003
  ]);
2279
3004
  const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
3005
+ const sessionOrderInputs = (0, react.useMemo)(() => {
3006
+ if (readState.status !== "ready") return [];
3007
+ const inputs = [];
3008
+ for (const workspace of workspaces.items) {
3009
+ const view = viewByWorkspace.get(workspace.workspaceId);
3010
+ const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
3011
+ const bindings = view?.bindings ?? [];
3012
+ const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
3013
+ inputs.push({
3014
+ accountKey: `main:${workspace.workspaceId}`,
3015
+ sessionIds: mainSessionIds,
3016
+ updatedAtById: updatedAtById(mainSessionIds, sessions)
3017
+ });
3018
+ for (const record of view?.worktrees ?? []) {
3019
+ const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
3020
+ inputs.push({
3021
+ accountKey: `worktree:${record.worktreeId}`,
3022
+ sessionIds: worktreeSessionIds,
3023
+ updatedAtById: updatedAtById(worktreeSessionIds, sessions)
3024
+ });
3025
+ }
3026
+ }
3027
+ return inputs;
3028
+ }, [
3029
+ archivedSessionIds,
3030
+ readState.status,
3031
+ sessions.byId,
3032
+ sessions.ids,
3033
+ viewByWorkspace,
3034
+ workspaces,
3035
+ workspaces.items
3036
+ ]);
3037
+ const orderedSessionIdsByAccount = (0, react.useMemo)(() => {
3038
+ const ordered = /* @__PURE__ */ new Map();
3039
+ for (const input of sessionOrderInputs) {
3040
+ const previous = sessionOrderSnapshot.accounts[input.accountKey];
3041
+ ordered.set(input.accountKey, nextSessionOrderAccount({
3042
+ baseIds: input.sessionIds,
3043
+ updatedAtById: input.updatedAtById,
3044
+ previous
3045
+ }).order);
3046
+ }
3047
+ return ordered;
3048
+ }, [sessionOrderInputs, sessionOrderSnapshot]);
3049
+ (0, react.useEffect)(() => {
3050
+ if (mode !== "worktree" || readState.status !== "ready") return;
3051
+ for (const input of sessionOrderInputs) sessionOrder.actions.reconcile(input.accountKey, input.sessionIds, input.updatedAtById);
3052
+ sessionOrder.actions.retain(sessionOrderInputs.map((input) => input.accountKey));
3053
+ }, [
3054
+ mode,
3055
+ readState.status,
3056
+ sessionOrder,
3057
+ sessionOrderInputs
3058
+ ]);
2280
3059
  const currentSessionLocation = (0, react.useMemo)(() => readState.status === "ready" ? resolveCurrentSessionLocation(currentSessionId, workspaces.items, readState.views) : void 0, [
2281
3060
  currentSessionId,
2282
3061
  readState.status,
@@ -2496,7 +3275,10 @@ window.__ModuleLoader__.load({
2496
3275
  return;
2497
3276
  }
2498
3277
  setActionError(void 0);
2499
- insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId).catch((error) => {
3278
+ const currentOrder = sessionOrderSnapshot.accounts[activeDrag.groupKey]?.order ?? sessionIds;
3279
+ insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId).then(() => {
3280
+ sessionOrder.actions.setOrder(activeDrag.groupKey, reorderSessionIds(currentOrder, activeDrag.sessionId, over.sessionId, over.half));
3281
+ }).catch((error) => {
2500
3282
  setActionError(toWorktreeViewError(error));
2501
3283
  });
2502
3284
  };
@@ -2617,8 +3399,7 @@ window.__ModuleLoader__.load({
2617
3399
  expandState.actions.toggleWorktree(worktreeId);
2618
3400
  if (visuallyExpanded) clearSessionGroups(["worktree:" + worktreeId]);
2619
3401
  };
2620
- const toggleSessionGroup = (groupKey) => {
2621
- const autoExpanded = isCurrentSessionReveal("session-group:" + groupKey);
3402
+ const toggleSessionGroup = (groupKey, autoExpanded) => {
2622
3403
  const transientExpanded = expandedSessionGroups[groupKey] === true;
2623
3404
  if (autoExpanded) {
2624
3405
  suppressCurrentSessionReveal("session-group:" + groupKey);
@@ -2643,7 +3424,7 @@ window.__ModuleLoader__.load({
2643
3424
  setModalReadError(void 0);
2644
3425
  setModalReadLoading(false);
2645
3426
  };
2646
- const openWorktreeCreator = (workspace) => {
3427
+ const openWorktreeCreator = (workspace, defaults = {}) => {
2647
3428
  const view = viewByWorkspace.get(workspace.workspaceId);
2648
3429
  modalReadLoader.current.invalidate();
2649
3430
  modalReadViewRef.current = void 0;
@@ -2659,13 +3440,13 @@ window.__ModuleLoader__.load({
2659
3440
  setModalReadError(void 0);
2660
3441
  setModalReadLoading(false);
2661
3442
  if (view === void 0) {
2662
- setSelectedBranch("");
2663
- setNewBranch("");
3443
+ setSelectedBranch(defaults.baseBranch ?? "");
3444
+ setNewBranch(defaults.newBranch ?? "");
2664
3445
  loadModalWorktreeView(workspace.workspaceId);
2665
3446
  return;
2666
3447
  }
2667
- setSelectedBranch(selectDefaultBaseBranch(view.branches));
2668
- setNewBranch(createDefaultWorktreeName([...view.branches.map((branch) => branch.name), ...view.worktrees.map((worktree) => worktree.branch)]));
3448
+ setSelectedBranch(defaults.baseBranch ?? selectDefaultBaseBranch(view.branches));
3449
+ setNewBranch(defaults.newBranch ?? createDefaultWorktreeName([...view.branches.map((branch) => branch.name), ...view.worktrees.map((worktree) => worktree.branch)]));
2669
3450
  };
2670
3451
  const changeWorktreeModalMode = (mode) => {
2671
3452
  setWorktreeModalMode(mode);
@@ -2695,6 +3476,11 @@ window.__ModuleLoader__.load({
2695
3476
  ...sessionInput,
2696
3477
  sessionId: error.sessionId
2697
3478
  });
3479
+ if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
3480
+ ...sessionInput,
3481
+ sessionId: error.sessionId,
3482
+ permissionRequired: true
3483
+ });
2698
3484
  throw error;
2699
3485
  }
2700
3486
  await refresh({ preserveCurrent: true });
@@ -2756,6 +3542,11 @@ window.__ModuleLoader__.load({
2756
3542
  ...input,
2757
3543
  sessionId: error.sessionId
2758
3544
  });
3545
+ if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
3546
+ ...input,
3547
+ sessionId: error.sessionId,
3548
+ permissionRequired: true
3549
+ });
2759
3550
  setActionError(toWorktreeViewError(error));
2760
3551
  } finally {
2761
3552
  setActionPending(false);
@@ -2774,6 +3565,9 @@ window.__ModuleLoader__.load({
2774
3565
  ensureSessionWorkspace: (workspaceId, sessionId) => {
2775
3566
  ensureSessionWorkspace?.(workspaceId, sessionId);
2776
3567
  },
3568
+ permission,
3569
+ confirmFullAccess,
3570
+ onPermissionResult,
2777
3571
  openSession
2778
3572
  });
2779
3573
  setPendingSessionBinding(void 0);
@@ -2786,6 +3580,17 @@ window.__ModuleLoader__.load({
2786
3580
  setActionPending(false);
2787
3581
  }
2788
3582
  };
3583
+ const retryForkBinding = async (key) => {
3584
+ if (retryForkSession === void 0 || forkRetryKey !== void 0) return;
3585
+ setForkRetryKey(key);
3586
+ try {
3587
+ await retryForkSession(key);
3588
+ } catch (error) {
3589
+ setActionError(toNativeWorktreeViewError(error));
3590
+ } finally {
3591
+ setForkRetryKey(void 0);
3592
+ }
3593
+ };
2789
3594
  const openWorkspaceSession = (workspaceId, sessionId) => {
2790
3595
  ensureSessionWorkspace?.(workspaceId, sessionId);
2791
3596
  openWorktreeSession({ open: openSession }, sessionId);
@@ -2851,7 +3656,7 @@ window.__ModuleLoader__.load({
2851
3656
  onClick: () => {
2852
3657
  if (createWorkspace !== void 0) runMutation(createWorkspace);
2853
3658
  },
2854
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
3659
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconProjectAddOutline16, {})
2855
3660
  })
2856
3661
  ]
2857
3662
  }),
@@ -2859,6 +3664,47 @@ window.__ModuleLoader__.load({
2859
3664
  className: worktree_css_default.content,
2860
3665
  tabIndex: 0,
2861
3666
  children: [
3667
+ permissionNoticeSnapshot !== void 0 && (0, react_jsx_runtime.jsx)("div", {
3668
+ className: worktree_css_default.notice,
3669
+ role: "status",
3670
+ "data-worktree-permission-notice": true,
3671
+ children: (0, react_jsx_runtime.jsx)("p", {
3672
+ className: worktree_css_default.message,
3673
+ children: formatWorktreePermissionNotice(permissionNoticeSnapshot.result, t)
3674
+ })
3675
+ }),
3676
+ forkRecoverySnapshot.pending.map((recovery) => {
3677
+ const recoveryViewError = forkRecoveryError(recovery);
3678
+ return (0, react_jsx_runtime.jsxs)("div", {
3679
+ className: worktree_css_default.error,
3680
+ role: "alert",
3681
+ "data-fork-recovery": recovery.key,
3682
+ children: [(0, react_jsx_runtime.jsx)("p", {
3683
+ className: worktree_css_default.message,
3684
+ "data-error": "true",
3685
+ children: formatWorktreeViewError(recoveryViewError, t)
3686
+ }), (0, react_jsx_runtime.jsxs)("div", {
3687
+ className: worktree_css_default.recoveryActions,
3688
+ children: [retryForkSession !== void 0 && recoveryViewError.retryable && (0, react_jsx_runtime.jsx)("button", {
3689
+ type: "button",
3690
+ className: worktree_css_default.actionButton,
3691
+ disabled: forkRetryKey !== void 0,
3692
+ onClick: () => {
3693
+ retryForkBinding(recovery.key);
3694
+ },
3695
+ children: t("action.retryBinding")
3696
+ }), (0, react_jsx_runtime.jsx)("button", {
3697
+ type: "button",
3698
+ className: worktree_css_default.actionButton,
3699
+ disabled: forkRetryKey !== void 0,
3700
+ onClick: () => {
3701
+ openSession(recovery.childSessionId);
3702
+ },
3703
+ children: t("action.openCreatedSession")
3704
+ })]
3705
+ })]
3706
+ }, recovery.key);
3707
+ }),
2862
3708
  actionError !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
2863
3709
  className: worktree_css_default.error,
2864
3710
  role: "alert",
@@ -2879,7 +3725,7 @@ window.__ModuleLoader__.load({
2879
3725
  retrySessionBinding();
2880
3726
  },
2881
3727
  children: t("action.retryBinding")
2882
- }), (0, react_jsx_runtime.jsx)("button", {
3728
+ }), !pendingSessionBinding.permissionRequired && (0, react_jsx_runtime.jsx)("button", {
2883
3729
  type: "button",
2884
3730
  className: worktree_css_default.actionButton,
2885
3731
  disabled: actionPending,
@@ -2935,13 +3781,19 @@ window.__ModuleLoader__.load({
2935
3781
  const expanded = isWorkspaceExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("workspace:" + workspace.workspaceId);
2936
3782
  const workspaceMatchesQuery = includesText(workspace.title, query);
2937
3783
  const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
3784
+ const workspaceHasOngoingSession = hasOngoingSession(filterVisibleSessionIds(allWorkspaceSessionIds, sessions), sessionPresentations);
2938
3785
  const bindings = view?.bindings ?? [];
2939
- const visibleMainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions).filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
2940
- const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("main:" + workspace.workspaceId);
3786
+ const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
2941
3787
  const mainGroupKey = `main:${workspace.workspaceId}`;
2942
- const sessionIds = visibleMainSessionIds;
2943
- const mainSessionGroupExpanded = expandedSessionGroups[mainGroupKey] === true || sessionIds.length > 5 && isCurrentSessionReveal("session-group:" + mainGroupKey);
3788
+ const orderedMainSessionIds = orderedSessionIdsByAccount.get(mainGroupKey) ?? mainSessionIds;
3789
+ const visibleMainSessionIds = mainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
3790
+ const orderedVisibleMainSessionIds = orderedMainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
3791
+ const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("main:" + workspace.workspaceId);
3792
+ const sessionIds = orderedVisibleMainSessionIds.length === visibleMainSessionIds.length ? orderedVisibleMainSessionIds : visibleMainSessionIds;
3793
+ const mainSessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + mainGroupKey));
3794
+ const mainSessionGroupExpanded = expandedSessionGroups[mainGroupKey] === true || mainSessionGroupAutoExpanded;
2944
3795
  const worktrees = view?.worktrees ?? [];
3796
+ const workspaceWorktreeNames = [...view?.branches.map((branch) => branch.name) ?? [], ...view?.worktrees.map((worktree) => worktree.branch) ?? []];
2945
3797
  const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
2946
3798
  return (0, react_jsx_runtime.jsxs)("section", {
2947
3799
  className: worktree_css_default.workspaceGroup,
@@ -2950,6 +3802,7 @@ window.__ModuleLoader__.load({
2950
3802
  t,
2951
3803
  workspace,
2952
3804
  expanded,
3805
+ hasOngoingSession: workspaceHasOngoingSession,
2953
3806
  actionPending,
2954
3807
  menuOpen: openWorkspaceMenuId === workspace.workspaceId,
2955
3808
  drag: {
@@ -3007,11 +3860,29 @@ window.__ModuleLoader__.load({
3007
3860
  kind: "main",
3008
3861
  label: mainLabel,
3009
3862
  expanded: mainExpanded,
3863
+ hasOngoingSession: hasOngoingSession(mainSessionIds, sessionPresentations),
3010
3864
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
3011
3865
  workspaceTitle: workspace.title,
3012
3866
  onToggle: () => {
3013
3867
  toggleMain(workspace.workspaceId);
3014
3868
  },
3869
+ menu: {
3870
+ open: openMainMenuId === workspace.workspaceId,
3871
+ label: mainLabel,
3872
+ copyPath: workspace.path,
3873
+ showCreate: currentBranch !== void 0,
3874
+ showRemove: false,
3875
+ disabled: actionPending,
3876
+ onOpenChange: (open) => {
3877
+ setOpenMainMenuId(open ? workspace.workspaceId : void 0);
3878
+ },
3879
+ onCreateWorktree: currentBranch === void 0 ? void 0 : () => {
3880
+ openWorktreeCreator(workspace, {
3881
+ baseBranch: currentBranch,
3882
+ newBranch: createNumberedWorktreeName(currentBranch, workspaceWorktreeNames)
3883
+ });
3884
+ }
3885
+ },
3015
3886
  onCreateSession: createMainSession === void 0 ? void 0 : () => {
3016
3887
  createMainSession(workspace.workspaceId);
3017
3888
  }
@@ -3025,9 +3896,10 @@ window.__ModuleLoader__.load({
3025
3896
  expanded: mainSessionGroupExpanded,
3026
3897
  actionPending,
3027
3898
  sessions,
3899
+ sessionPresentations,
3028
3900
  dragState: sessionDrag,
3029
3901
  onToggleExpanded: () => {
3030
- toggleSessionGroup(mainGroupKey);
3902
+ toggleSessionGroup(mainGroupKey, mainSessionGroupAutoExpanded);
3031
3903
  },
3032
3904
  onStartDrag: (groupKey, sessionId) => {
3033
3905
  sessionDropCommitted.current = false;
@@ -3070,8 +3942,10 @@ window.__ModuleLoader__.load({
3070
3942
  if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return null;
3071
3943
  const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
3072
3944
  const worktreeGroupKey = `worktree:${record.worktreeId}`;
3073
- const sessionIds = visibleWorktreeSessionIds;
3074
- const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true || sessionIds.length > 5 && isCurrentSessionReveal("session-group:" + worktreeGroupKey);
3945
+ const orderedVisibleWorktreeSessionIds = (orderedSessionIdsByAccount.get(worktreeGroupKey) ?? worktreeSessionIds).filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
3946
+ const sessionIds = orderedVisibleWorktreeSessionIds.length === visibleWorktreeSessionIds.length ? orderedVisibleWorktreeSessionIds : visibleWorktreeSessionIds;
3947
+ const sessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + worktreeGroupKey));
3948
+ const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true || sessionGroupAutoExpanded;
3075
3949
  const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
3076
3950
  const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
3077
3951
  const worktreeExpanded = isWorktreeExpanded(expandSnapshot, record.worktreeId) || isCurrentSessionReveal("worktree:" + record.worktreeId);
@@ -3084,6 +3958,7 @@ window.__ModuleLoader__.load({
3084
3958
  label: record.branch,
3085
3959
  worktreeId: record.worktreeId,
3086
3960
  expanded: worktreeExpanded,
3961
+ hasOngoingSession: hasOngoingSession(worktreeSessionIds, sessionPresentations),
3087
3962
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
3088
3963
  workspaceTitle: workspace.title,
3089
3964
  state,
@@ -3098,18 +3973,27 @@ window.__ModuleLoader__.load({
3098
3973
  cwd: record.absolutePath
3099
3974
  });
3100
3975
  } : void 0,
3101
- menu: record.status === "active" ? {
3976
+ menu: {
3102
3977
  open: openWorktreeMenuId === record.worktreeId,
3103
3978
  label: record.branch,
3979
+ copyPath: record.absolutePath,
3980
+ showCreate: record.status === "active",
3981
+ showRemove: record.status === "active",
3104
3982
  disabled: actionPending,
3105
3983
  onOpenChange: (open) => {
3106
3984
  setOpenWorktreeMenuId(open ? record.worktreeId : void 0);
3107
3985
  },
3108
- onRemove: () => {
3986
+ onCreateWorktree: record.status === "active" ? () => {
3987
+ openWorktreeCreator(workspace, {
3988
+ baseBranch: record.branch,
3989
+ newBranch: createNumberedWorktreeName(record.branch, workspaceWorktreeNames)
3990
+ });
3991
+ } : void 0,
3992
+ onRemove: record.status === "active" ? () => {
3109
3993
  setWorktreeRemoval(record);
3110
3994
  setActionError(void 0);
3111
- }
3112
- } : void 0,
3995
+ } : void 0
3996
+ },
3113
3997
  drag: {
3114
3998
  active: sameWorkspaceWorktreeDrag,
3115
3999
  marker: worktreeDrag?.over?.worktreeId === record.worktreeId ? worktreeDrag.over.half : null,
@@ -3151,9 +4035,10 @@ window.__ModuleLoader__.load({
3151
4035
  expanded: sessionGroupExpanded,
3152
4036
  actionPending,
3153
4037
  sessions,
4038
+ sessionPresentations,
3154
4039
  dragState: sessionDrag,
3155
4040
  onToggleExpanded: () => {
3156
- toggleSessionGroup(worktreeGroupKey);
4041
+ toggleSessionGroup(worktreeGroupKey, sessionGroupAutoExpanded);
3157
4042
  },
3158
4043
  onStartDrag: (groupKey, sessionId) => {
3159
4044
  sessionDropCommitted.current = false;
@@ -3279,11 +4164,29 @@ window.__ModuleLoader__.load({
3279
4164
  workspaceId: target.workspaceId,
3280
4165
  worktreeId: target.worktreeId
3281
4166
  }
3282
- });
4167
+ }, permission, onPermissionNotice);
3283
4168
  await invalidateWorktreeContext?.(target.workspaceId);
3284
4169
  setWorktreeRemoval(void 0);
3285
4170
  });
3286
4171
  }
4172
+ }),
4173
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.RiskConfirmation, {
4174
+ open: fullAccessConfirmationSnapshot !== void 0,
4175
+ title: t("permission.fullAccessTitle"),
4176
+ description: fullAccessConfirmationSnapshot === void 0 ? "" : t("permission.fullAccessDescription", { cwd: fullAccessConfirmationSnapshot.cwd }),
4177
+ acknowledgeLabel: t("permission.fullAccessAcknowledge"),
4178
+ cancelLabel: t("dialog.cancel"),
4179
+ confirmLabel: t("permission.fullAccessEnable"),
4180
+ acknowledged: fullAccessAcknowledged,
4181
+ onAcknowledgedChange: setFullAccessAcknowledged,
4182
+ onCancel: () => {
4183
+ setFullAccessAcknowledged(false);
4184
+ fullAccessConfirmation?.resolve(false);
4185
+ },
4186
+ onConfirm: () => {
4187
+ setFullAccessAcknowledged(false);
4188
+ fullAccessConfirmation?.resolve(true);
4189
+ }
3287
4190
  })
3288
4191
  ]
3289
4192
  });
@@ -3649,6 +4552,313 @@ window.__ModuleLoader__.load({
3649
4552
  };
3650
4553
  }
3651
4554
  //#endregion
4555
+ //#region lib/client/worktree-permission.js
4556
+ /**
4557
+ * Coordinate async permission requests with the one in-page confirmation
4558
+ * rendered by the Worktree surface. Requests are serialized so concurrent
4559
+ * Worktree Session creations cannot replace one another's dialog.
4560
+ */
4561
+ function createWorktreeFullAccessConfirmationController() {
4562
+ let active;
4563
+ const queue = [];
4564
+ const listeners = /* @__PURE__ */ new Set();
4565
+ let disposed = false;
4566
+ const notify = () => {
4567
+ for (const listener of listeners) listener();
4568
+ };
4569
+ const showNext = () => {
4570
+ if (active !== void 0) return;
4571
+ active = queue.shift();
4572
+ notify();
4573
+ };
4574
+ return {
4575
+ getSnapshot: () => active?.input,
4576
+ subscribe: (listener) => {
4577
+ listeners.add(listener);
4578
+ return () => {
4579
+ listeners.delete(listener);
4580
+ };
4581
+ },
4582
+ request: (input) => {
4583
+ if (disposed) return Promise.resolve(false);
4584
+ return new Promise((resolve) => {
4585
+ queue.push({
4586
+ input,
4587
+ resolve
4588
+ });
4589
+ showNext();
4590
+ });
4591
+ },
4592
+ resolve: (confirmed) => {
4593
+ if (active === void 0) return;
4594
+ const current = active;
4595
+ active = void 0;
4596
+ current.resolve(confirmed);
4597
+ showNext();
4598
+ },
4599
+ dispose: () => {
4600
+ if (disposed) return;
4601
+ disposed = true;
4602
+ active?.resolve(false);
4603
+ active = void 0;
4604
+ for (const pending of queue.splice(0)) pending.resolve(false);
4605
+ notify();
4606
+ }
4607
+ };
4608
+ }
4609
+ //#endregion
4610
+ //#region lib/client/worktree-permission-icon.js
4611
+ const PLUGIN_ID = "@cerbur/clutch-dsh-worktree";
4612
+ const STYLE_ID = `${PLUGIN_ID}/permission-icon`;
4613
+ const WORKTREE_PERMISSION_LABEL = "Worktree Full Access";
4614
+ /** DOM marker owned only by this plugin's permission icon decorator. */
4615
+ const WORKTREE_PERMISSION_ICON_ATTRIBUTE = "data-clutch-dsh-worktree-permission-icon";
4616
+ const ICON_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path d=\"M13.0762 1.37207C14.0846 1.37228 14.9021 2.19077 14.9023 3.19922C14.9022 4.20772 14.0847 5.02518 13.0762 5.02539C12.2967 5.02539 11.6325 4.53691 11.3701 3.84961H4.35547C4.79397 4.26458 5.15861 4.7644 5.41699 5.33496L7.10645 9.06738C7.88526 10.7875 9.55104 11.9228 11.4189 12.0371C11.7085 11.4109 12.3411 10.9756 13.0762 10.9756C14.0843 10.9759 14.9023 11.7936 14.9023 12.8018C14.9023 13.81 14.0843 14.6277 13.0762 14.6279C12.2534 14.6279 11.5574 14.0832 11.3291 13.335C8.9868 13.1879 6.89981 11.7612 5.92285 9.60352L4.23242 5.87109C3.67503 4.64033 2.44878 3.84961 1.09766 3.84961V2.54883C1.10665 2.54883 1.11601 2.54975 1.125 2.5498L11.3701 2.54883C11.6326 1.86151 12.2969 1.37207 13.0762 1.37207ZM13.0762 12.2764C12.7858 12.2764 12.5508 12.5114 12.5508 12.8018C12.5508 13.0921 12.7858 13.3281 13.0762 13.3281C13.3664 13.3279 13.6025 13.092 13.6025 12.8018C13.6025 12.5115 13.3664 12.2766 13.0762 12.2764ZM13.0762 2.67285C12.7855 2.67285 12.55 2.90861 12.5498 3.19922C12.5499 3.48987 12.7855 3.72559 13.0762 3.72559C13.3667 3.72538 13.6024 3.48975 13.6025 3.19922C13.6023 2.90874 13.3666 2.67306 13.0762 2.67285Z\" fill=\"black\"/></svg>";
4617
+ function iconStyles() {
4618
+ const mask = `url("data:image/svg+xml,${encodeURIComponent(ICON_SVG)}")`;
4619
+ return `
4620
+ [${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]::before {
4621
+ content: "";
4622
+ display: inline-block;
4623
+ flex: 0 0 auto;
4624
+ width: 16px;
4625
+ height: 16px;
4626
+ background-color: var(--dsw-alias-label-tertiary, currentColor);
4627
+ -webkit-mask-image: ${mask};
4628
+ mask-image: ${mask};
4629
+ -webkit-mask-position: center;
4630
+ mask-position: center;
4631
+ -webkit-mask-repeat: no-repeat;
4632
+ mask-repeat: no-repeat;
4633
+ -webkit-mask-size: contain;
4634
+ mask-size: contain;
4635
+ }
4636
+ [${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"]::before {
4637
+ width: 14px;
4638
+ height: 14px;
4639
+ }
4640
+ @container (max-width: 460px) {
4641
+ [${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"] > span:first-of-type {
4642
+ display: none;
4643
+ }
4644
+ }
4645
+ `;
4646
+ }
4647
+ function normalizedText(element) {
4648
+ return (element.textContent ?? "").replace(/\s+/g, " ").trim();
4649
+ }
4650
+ function isWorktreeMenuItem(element) {
4651
+ return element.matches("button[role=\"menuitem\"]") && normalizedText(element) === WORKTREE_PERMISSION_LABEL && element.closest("[role=\"menu\"]") !== null;
4652
+ }
4653
+ function isWorktreeTrigger(element) {
4654
+ if (!element.matches("button[aria-label]")) return false;
4655
+ const label = element.getAttribute("aria-label") ?? "";
4656
+ return /^(?:access mode,\s*current:\s*|访问模式,当前:\s*)worktree full access$/iu.test(label.trim());
4657
+ }
4658
+ /** Mark the native custom permission row and trigger for CSS decoration. */
4659
+ function decorateWorktreePermissionIcons(document) {
4660
+ for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) {
4661
+ const kind = marked.getAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
4662
+ if (kind === "menu" && !isWorktreeMenuItem(marked) || kind === "trigger" && !isWorktreeTrigger(marked)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
4663
+ }
4664
+ for (const item of document.querySelectorAll("button[role=\"menuitem\"]")) if (isWorktreeMenuItem(item)) item.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "menu");
4665
+ for (const button of document.querySelectorAll("button[aria-label]")) if (isWorktreeTrigger(button)) button.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "trigger");
4666
+ }
4667
+ /** Install the Worktree permission icon and return a plugin-local disposer. */
4668
+ function installWorktreePermissionIcon(document) {
4669
+ for (const existing of document.querySelectorAll("style[data-plugin-css]")) if (existing.getAttribute("data-plugin-css") === STYLE_ID) existing.remove();
4670
+ const style = document.createElement("style");
4671
+ style.setAttribute("data-plugin", PLUGIN_ID);
4672
+ style.setAttribute("data-plugin-css", STYLE_ID);
4673
+ style.textContent = iconStyles();
4674
+ document.head.appendChild(style);
4675
+ let active = true;
4676
+ let queued = false;
4677
+ const scan = () => {
4678
+ if (!active || queued) return;
4679
+ queued = true;
4680
+ queueMicrotask(() => {
4681
+ queued = false;
4682
+ if (active) decorateWorktreePermissionIcons(document);
4683
+ });
4684
+ };
4685
+ decorateWorktreePermissionIcons(document);
4686
+ const observer = typeof MutationObserver === "function" ? new MutationObserver(scan) : void 0;
4687
+ observer?.observe(document.documentElement, {
4688
+ attributes: true,
4689
+ attributeFilter: ["aria-label"],
4690
+ characterData: true,
4691
+ childList: true,
4692
+ subtree: true
4693
+ });
4694
+ return () => {
4695
+ if (!active) return;
4696
+ active = false;
4697
+ observer?.disconnect();
4698
+ style.remove();
4699
+ for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
4700
+ };
4701
+ }
4702
+ //#endregion
4703
+ //#region lib/client/worktree-session-fork.js
4704
+ function recoveryKey(sourceSessionId, childSessionId) {
4705
+ return `${sourceSessionId}\u0000${childSessionId}`;
4706
+ }
4707
+ /**
4708
+ * Coordinate native Session fork with the plugin-owned Worktree relation.
4709
+ * Native Session creation always wins: plugin lookup/bind failures are kept as
4710
+ * recovery state and never turn an already-created child into a failed fork.
4711
+ */
4712
+ function createWorktreeSessionForkCoordinator(options) {
4713
+ let disposed = false;
4714
+ let revision = 0;
4715
+ let pending = /* @__PURE__ */ new Map();
4716
+ let recoverySnapshot = {
4717
+ revision: 0,
4718
+ pending: []
4719
+ };
4720
+ const subscribers = /* @__PURE__ */ new Set();
4721
+ const boundChildren = /* @__PURE__ */ new Set();
4722
+ const bindingInFlight = /* @__PURE__ */ new Map();
4723
+ let reconciliationInFlight;
4724
+ let reconciliationAgain = false;
4725
+ const publish = () => {
4726
+ revision += 1;
4727
+ recoverySnapshot = {
4728
+ revision,
4729
+ pending: [...pending.values()]
4730
+ };
4731
+ for (const subscriber of subscribers) subscriber();
4732
+ };
4733
+ const setRecovery = (sourceSessionId, childSessionId, error, target) => {
4734
+ if (disposed) return;
4735
+ const key = recoveryKey(sourceSessionId, childSessionId);
4736
+ pending = new Map(pending).set(key, {
4737
+ key,
4738
+ sourceSessionId,
4739
+ childSessionId,
4740
+ ...target === void 0 ? {} : { binding: target },
4741
+ error
4742
+ });
4743
+ publish();
4744
+ };
4745
+ const clearRecovery = (sourceSessionId, childSessionId) => {
4746
+ const key = recoveryKey(sourceSessionId, childSessionId);
4747
+ if (!pending.has(key)) return;
4748
+ const next = new Map(pending);
4749
+ next.delete(key);
4750
+ pending = next;
4751
+ publish();
4752
+ };
4753
+ const attemptBinding = async (sourceSessionId, childSessionId) => {
4754
+ if (disposed || boundChildren.has(childSessionId)) return { bound: false };
4755
+ let target;
4756
+ try {
4757
+ target = await options.findBinding(sourceSessionId);
4758
+ } catch (error) {
4759
+ setRecovery(sourceSessionId, childSessionId, error);
4760
+ return { bound: false };
4761
+ }
4762
+ if (disposed) return { bound: false };
4763
+ if (target === void 0 || target.status !== "active") {
4764
+ clearRecovery(sourceSessionId, childSessionId);
4765
+ return { bound: false };
4766
+ }
4767
+ try {
4768
+ await options.bindSession({
4769
+ workspaceId: target.workspaceId,
4770
+ worktreeId: target.worktreeId,
4771
+ sessionId: childSessionId
4772
+ });
4773
+ if (disposed) return { bound: false };
4774
+ const childBinding = {
4775
+ workspaceId: target.workspaceId,
4776
+ worktreeId: target.worktreeId,
4777
+ sessionId: childSessionId,
4778
+ status: "active"
4779
+ };
4780
+ boundChildren.add(childSessionId);
4781
+ clearRecovery(sourceSessionId, childSessionId);
4782
+ options.onBound?.(childBinding);
4783
+ publish();
4784
+ return { bound: true };
4785
+ } catch (error) {
4786
+ setRecovery(sourceSessionId, childSessionId, error, target);
4787
+ return { bound: false };
4788
+ }
4789
+ };
4790
+ const bindChild = (sourceSessionId, childSessionId) => {
4791
+ if (disposed || boundChildren.has(childSessionId)) return Promise.resolve({ bound: false });
4792
+ const key = recoveryKey(sourceSessionId, childSessionId);
4793
+ const current = bindingInFlight.get(key);
4794
+ if (current !== void 0) return current;
4795
+ const promise = attemptBinding(sourceSessionId, childSessionId).finally(() => {
4796
+ if (bindingInFlight.get(key) === promise) bindingInFlight.delete(key);
4797
+ });
4798
+ bindingInFlight.set(key, promise);
4799
+ return promise;
4800
+ };
4801
+ const reconcileNow = async () => {
4802
+ if (disposed || options.sessions === void 0) return;
4803
+ const snapshot = options.sessions.getSnapshot();
4804
+ if (snapshot.phase === "pending") return;
4805
+ if (!Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null) return;
4806
+ const candidates = snapshot.ids.flatMap((childSessionId) => {
4807
+ const summary = snapshot.byId[childSessionId];
4808
+ if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
4809
+ return [{
4810
+ childSessionId,
4811
+ sourceSessionId: summary.parentId
4812
+ }];
4813
+ });
4814
+ await Promise.all(candidates.map(({ childSessionId, sourceSessionId }) => bindChild(sourceSessionId, childSessionId).then(() => void 0)));
4815
+ };
4816
+ const reconcile = () => {
4817
+ if (reconciliationInFlight !== void 0) {
4818
+ reconciliationAgain = true;
4819
+ return reconciliationInFlight;
4820
+ }
4821
+ const run = async () => {
4822
+ do {
4823
+ reconciliationAgain = false;
4824
+ await reconcileNow();
4825
+ } while (!disposed && reconciliationAgain);
4826
+ };
4827
+ const promise = run().finally(() => {
4828
+ if (reconciliationInFlight === promise) reconciliationInFlight = void 0;
4829
+ });
4830
+ reconciliationInFlight = promise;
4831
+ return promise;
4832
+ };
4833
+ return {
4834
+ recovery: {
4835
+ getSnapshot() {
4836
+ return recoverySnapshot;
4837
+ },
4838
+ subscribe(listener) {
4839
+ subscribers.add(listener);
4840
+ return () => subscribers.delete(listener);
4841
+ }
4842
+ },
4843
+ async fork(input) {
4844
+ const childSessionId = await options.fork(input);
4845
+ if (!disposed) await bindChild(input.sessionId, childSessionId);
4846
+ return childSessionId;
4847
+ },
4848
+ reconcile,
4849
+ async retry(key) {
4850
+ const item = pending.get(key);
4851
+ if (item === void 0 || disposed) return false;
4852
+ return (await bindChild(item.sourceSessionId, item.childSessionId)).bound;
4853
+ },
4854
+ dispose() {
4855
+ disposed = true;
4856
+ bindingInFlight.clear();
4857
+ subscribers.clear();
4858
+ }
4859
+ };
4860
+ }
4861
+ //#endregion
3652
4862
  //#region lib/client/entry.js
3653
4863
  /** Required DSH Client services; Connection is the sole Worktree wire dependency. */
3654
4864
  const inject = [
@@ -3663,11 +4873,22 @@ window.__ModuleLoader__.load({
3663
4873
  * with that fiber, so slot consumers share one manager and one request lifetime.
3664
4874
  */
3665
4875
  function apply(ctx) {
4876
+ if (typeof document !== "undefined") ctx.effect(() => installWorktreePermissionIcon(document), "clutch-dsh-worktree: permission icon cleanup");
3666
4877
  ctx.effect(() => ctx.locale.register(WORKTREE_NS, {
3667
4878
  zh,
3668
4879
  en
3669
4880
  }), "clutch-dsh-worktree: locale dictionaries");
3670
4881
  const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
4882
+ const fullAccessConfirmation = createWorktreeFullAccessConfirmationController();
4883
+ const permissionNotice = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(void 0);
4884
+ const permissionManager = typeof document !== "undefined" ? manager : void 0;
4885
+ const reportPermissionNotice = (input, result) => {
4886
+ const visible = result.status === "fallback-workspace-write" || result.status === "user-restricted" || result.status === "unverified";
4887
+ permissionNotice.set(visible ? {
4888
+ ...input,
4889
+ result
4890
+ } : void 0);
4891
+ };
3671
4892
  const sessions = ctx.sessions;
3672
4893
  const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
3673
4894
  const contextProjection = createWorktreeContextProjection({
@@ -3677,11 +4898,14 @@ window.__ModuleLoader__.load({
3677
4898
  storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
3678
4899
  });
3679
4900
  ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
4901
+ ctx.effect(() => () => fullAccessConfirmation.dispose(), "clutch-dsh-worktree: Full Access confirmation cleanup");
3680
4902
  ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
3681
4903
  ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
3682
4904
  contextProjection.refresh();
3683
4905
  const viewStore = createWorktreeViewStore();
3684
4906
  const expandState = createWorktreeExpandStateStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
4907
+ const sessionOrder = createWorktreeSessionOrderStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
4908
+ ctx.effect(() => () => sessionOrder.dispose(), "clutch-dsh-worktree: Session order cleanup");
3685
4909
  const ensureSessionWorkspace = (workspaceId, sessionId) => {
3686
4910
  virtualWorkspaceMembership.ensure({
3687
4911
  workspaceId,
@@ -3691,12 +4915,48 @@ window.__ModuleLoader__.load({
3691
4915
  const syncSessionWorkspaces = (bindings) => {
3692
4916
  virtualWorkspaceMembership.sync(bindings);
3693
4917
  };
4918
+ const forkableSessions = ctx.sessions;
4919
+ const nativeFork = forkableSessions.fork;
4920
+ const findWorktreeSessionBinding = async (sessionId) => {
4921
+ const workspaceIds = ctx.workspaces.list.getSnapshot().items.map((workspace) => workspace.workspaceId);
4922
+ const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
4923
+ return (await manager.listBindings({ workspaceId })).find((binding) => binding.sessionId === sessionId && binding.status === "active");
4924
+ }));
4925
+ const found = results.find((result) => result.status === "fulfilled" && result.value !== void 0);
4926
+ if (found !== void 0) return found.value;
4927
+ const failed = results.find((result) => result.status === "rejected");
4928
+ if (failed !== void 0) throw failed.reason;
4929
+ };
4930
+ const forkCoordinator = typeof nativeFork !== "function" ? void 0 : createWorktreeSessionForkCoordinator({
4931
+ fork: (input) => nativeFork.call(ctx.sessions, input),
4932
+ findBinding: findWorktreeSessionBinding,
4933
+ bindSession: (input) => manager.bindSession(input),
4934
+ sessions: ctx.sessions.list
4935
+ });
4936
+ if (forkCoordinator !== void 0) {
4937
+ forkableSessions.fork = (input) => forkCoordinator.fork(input);
4938
+ const reconcileForkChildren = () => {
4939
+ forkCoordinator.reconcile();
4940
+ };
4941
+ const unsubscribeSessionList = ctx.sessions.list.subscribe(reconcileForkChildren);
4942
+ const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildren);
4943
+ ctx.effect(() => () => {
4944
+ unsubscribeSessionList();
4945
+ unsubscribeWorkspaceList();
4946
+ forkCoordinator.dispose();
4947
+ forkableSessions.fork = nativeFork;
4948
+ }, "clutch-dsh-worktree: Session fork cleanup");
4949
+ forkCoordinator.reconcile();
4950
+ }
3694
4951
  const worktreeSessionConnector = createWorktreeSessionConnector({
3695
4952
  manager,
3696
4953
  sessions: ctx.sessions.list,
3697
4954
  archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
3698
4955
  createSession: async (input) => String(await sessions.create(input)),
3699
4956
  ensureSessionWorkspace,
4957
+ permission: permissionManager,
4958
+ confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
4959
+ onPermissionResult: reportPermissionNotice,
3700
4960
  openSession: (sessionId) => {
3701
4961
  ctx.sessions.open(sessionId);
3702
4962
  }
@@ -3724,8 +4984,15 @@ window.__ModuleLoader__.load({
3724
4984
  inject: () => ({
3725
4985
  available: true,
3726
4986
  expandState,
4987
+ sessionOrder,
3727
4988
  hooks: { worktreeContext: contextProjection.store },
3728
4989
  manager,
4990
+ permission: permissionManager,
4991
+ confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
4992
+ fullAccessConfirmation: typeof document === "undefined" ? void 0 : fullAccessConfirmation,
4993
+ onPermissionResult: reportPermissionNotice,
4994
+ onPermissionNotice: reportPermissionNotice,
4995
+ permissionNotice,
3729
4996
  createWorkspace: async () => {
3730
4997
  const workspacePath = await ctx.workspaces.pickDirectory();
3731
4998
  if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
@@ -3759,6 +5026,7 @@ window.__ModuleLoader__.load({
3759
5026
  if (!result.ok) throw new Error(result.error.message);
3760
5027
  },
3761
5028
  forkSession: (sessionId) => {
5029
+ if (forkableSessions.fork === void 0) return;
3762
5030
  ctx.sessions.fork({
3763
5031
  sessionId,
3764
5032
  increaseTitle: true
@@ -3769,6 +5037,10 @@ window.__ModuleLoader__.load({
3769
5037
  archiveSession: (sessionId) => ctx.workspaces.archiveSession(sessionId),
3770
5038
  ensureSessionWorkspace,
3771
5039
  syncSessionWorkspaces,
5040
+ forkRecovery: forkCoordinator?.recovery,
5041
+ retryForkSession: forkCoordinator === void 0 ? void 0 : async (key) => {
5042
+ await forkCoordinator.retry(key);
5043
+ },
3772
5044
  openSession: (sessionId) => {
3773
5045
  ctx.sessions.open(sessionId);
3774
5046
  }