@cerbur/clutch-dsh-worktree 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -23
- package/README.zh.md +107 -13
- package/cordis.patch.yml +21 -0
- package/lib/client/WorktreeContext.d.ts.map +1 -1
- package/lib/client/WorktreeContext.js +2 -2
- package/lib/client/WorktreeContext.js.map +1 -1
- package/lib/client/WorktreeSurface.d.ts +2 -2
- package/lib/client/WorktreeSurface.d.ts.map +1 -1
- package/lib/client/WorktreeSurface.js +291 -70
- package/lib/client/WorktreeSurface.js.map +1 -1
- package/lib/client/entry.d.ts.map +1 -1
- package/lib/client/entry.js +84 -2
- package/lib/client/entry.js.map +1 -1
- package/lib/client/index.d.ts +3 -0
- package/lib/client/index.d.ts.map +1 -1
- package/lib/client/index.js +2 -0
- package/lib/client/index.js.map +1 -1
- package/lib/client/locales.d.ts +70 -0
- package/lib/client/locales.d.ts.map +1 -1
- package/lib/client/locales.js +70 -0
- package/lib/client/locales.js.map +1 -1
- package/lib/client/session-view.d.ts +34 -0
- package/lib/client/session-view.d.ts.map +1 -1
- package/lib/client/session-view.js +119 -1
- package/lib/client/session-view.js.map +1 -1
- package/lib/client/worktree-connection.d.ts +4 -2
- package/lib/client/worktree-connection.d.ts.map +1 -1
- package/lib/client/worktree-connection.js +4 -0
- package/lib/client/worktree-connection.js.map +1 -1
- package/lib/client/worktree-context.js +1 -1
- package/lib/client/worktree-context.js.map +1 -1
- package/lib/client/worktree-error-copy.d.ts +2 -0
- package/lib/client/worktree-error-copy.d.ts.map +1 -1
- package/lib/client/worktree-error-copy.js +24 -0
- package/lib/client/worktree-error-copy.js.map +1 -1
- package/lib/client/worktree-permission-icon.d.ts +7 -0
- package/lib/client/worktree-permission-icon.d.ts.map +1 -0
- package/lib/client/worktree-permission-icon.js +119 -0
- package/lib/client/worktree-permission-icon.js.map +1 -0
- package/lib/client/worktree-permission.d.ts +21 -0
- package/lib/client/worktree-permission.d.ts.map +1 -0
- package/lib/client/worktree-permission.js +70 -0
- package/lib/client/worktree-permission.js.map +1 -0
- package/lib/client/worktree-session-fork.d.ts +65 -0
- package/lib/client/worktree-session-fork.d.ts.map +1 -0
- package/lib/client/worktree-session-fork.js +174 -0
- package/lib/client/worktree-session-fork.js.map +1 -0
- package/lib/client/worktree-session-order.d.ts +36 -0
- package/lib/client/worktree-session-order.d.ts.map +1 -0
- package/lib/client/worktree-session-order.js +215 -0
- package/lib/client/worktree-session-order.js.map +1 -0
- package/lib/client/worktree-session.d.ts +34 -1
- package/lib/client/worktree-session.d.ts.map +1 -1
- package/lib/client/worktree-session.js +101 -3
- package/lib/client/worktree-session.js.map +1 -1
- package/lib/client/worktree-surface-rows.d.ts +4 -4
- package/lib/client/worktree-surface-rows.d.ts.map +1 -1
- package/lib/client/worktree-surface-rows.js +139 -47
- package/lib/client/worktree-surface-rows.js.map +1 -1
- package/lib/client/worktree-surface-selectors.d.ts +2 -0
- package/lib/client/worktree-surface-selectors.d.ts.map +1 -1
- package/lib/client/worktree-surface-selectors.js +8 -0
- package/lib/client/worktree-surface-selectors.js.map +1 -1
- package/lib/client/worktree-surface-types.d.ts +46 -3
- package/lib/client/worktree-surface-types.d.ts.map +1 -1
- package/lib/client/worktree-view-actions.d.ts +8 -3
- package/lib/client/worktree-view-actions.d.ts.map +1 -1
- package/lib/client/worktree-view-actions.js +28 -2
- package/lib/client/worktree-view-actions.js.map +1 -1
- package/lib/client/worktree-view-errors.d.ts +10 -0
- package/lib/client/worktree-view-errors.d.ts.map +1 -1
- package/lib/client/worktree-view-errors.js +22 -1
- package/lib/client/worktree-view-errors.js.map +1 -1
- package/lib/client.js +1515 -207
- package/lib/client.js.map +1 -1
- package/lib/contract/index.contract.js +2 -0
- package/lib/contract/index.contract.js.map +1 -1
- package/lib/contract/index.d.ts +11 -3
- package/lib/contract/index.d.ts.map +1 -1
- package/lib/contract/index.js +8 -0
- package/lib/contract/index.js.map +1 -1
- package/lib/contract/worktree-permission.d.ts +73 -0
- package/lib/contract/worktree-permission.d.ts.map +1 -0
- package/lib/contract/worktree-permission.js +32 -0
- package/lib/contract/worktree-permission.js.map +1 -0
- package/lib/host/dsh-read-adapter.d.ts +1 -0
- package/lib/host/dsh-read-adapter.d.ts.map +1 -1
- package/lib/host/dsh-read-adapter.js +6 -0
- package/lib/host/dsh-read-adapter.js.map +1 -1
- package/lib/host/index.d.ts +4 -0
- package/lib/host/index.d.ts.map +1 -1
- package/lib/host/index.js +2 -0
- package/lib/host/index.js.map +1 -1
- package/lib/host/remote.d.ts +2 -2
- package/lib/host/remote.d.ts.map +1 -1
- package/lib/host/remote.js +7 -1
- package/lib/host/remote.js.map +1 -1
- package/lib/host/service.d.ts +5 -1
- package/lib/host/service.d.ts.map +1 -1
- package/lib/host/service.js +42 -3
- package/lib/host/service.js.map +1 -1
- package/lib/host/worktree-permission-manager.d.ts +14 -0
- package/lib/host/worktree-permission-manager.d.ts.map +1 -0
- package/lib/host/worktree-permission-manager.js +113 -0
- package/lib/host/worktree-permission-manager.js.map +1 -0
- package/lib/host/worktree-permission.d.ts +38 -0
- package/lib/host/worktree-permission.d.ts.map +1 -0
- package/lib/host/worktree-permission.js +156 -0
- package/lib/host/worktree-permission.js.map +1 -0
- package/lib/index.d.ts +6 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/manage/manager-context.d.ts +2 -0
- package/lib/manage/manager-context.d.ts.map +1 -1
- package/lib/manage/manager-worktrees.d.ts +5 -0
- package/lib/manage/manager-worktrees.d.ts.map +1 -1
- package/lib/manage/manager-worktrees.js +125 -37
- package/lib/manage/manager-worktrees.js.map +1 -1
- package/lib/manage/manager.d.ts +20 -0
- package/lib/manage/manager.d.ts.map +1 -1
- package/lib/manage/manager.js +91 -13
- package/lib/manage/manager.js.map +1 -1
- package/lib/manage/types.d.ts +9 -1
- package/lib/manage/types.d.ts.map +1 -1
- package/lib/manage/worktree-permission.d.ts +3 -0
- package/lib/manage/worktree-permission.d.ts.map +1 -0
- package/lib/manage/worktree-permission.js +3 -0
- package/lib/manage/worktree-permission.js.map +1 -0
- package/lib/provider/git.d.ts +37 -9
- package/lib/provider/git.d.ts.map +1 -1
- package/lib/provider/git.js +162 -61
- package/lib/provider/git.js.map +1 -1
- package/lib/provider/index.d.ts +5 -1
- package/lib/provider/index.d.ts.map +1 -1
- package/lib/provider/index.js +4 -0
- package/lib/provider/index.js.map +1 -1
- package/lib/provider/mutation-lock.d.ts +37 -0
- package/lib/provider/mutation-lock.d.ts.map +1 -0
- package/lib/provider/mutation-lock.js +270 -0
- package/lib/provider/mutation-lock.js.map +1 -0
- package/lib/provider/mutation-token.d.ts +8 -0
- package/lib/provider/mutation-token.d.ts.map +1 -0
- package/lib/provider/mutation-token.js +20 -0
- package/lib/provider/mutation-token.js.map +1 -0
- package/lib/provider/repository-fingerprint.d.ts +8 -0
- package/lib/provider/repository-fingerprint.d.ts.map +1 -0
- package/lib/provider/repository-fingerprint.js +13 -0
- package/lib/provider/repository-fingerprint.js.map +1 -0
- package/lib/provider/sidecar-persistence.d.ts +7 -3
- package/lib/provider/sidecar-persistence.d.ts.map +1 -1
- package/lib/provider/sidecar-persistence.js +118 -44
- package/lib/provider/sidecar-persistence.js.map +1 -1
- package/lib/provider/sidecar-schema.d.ts +1 -1
- package/lib/provider/sidecar-schema.d.ts.map +1 -1
- package/lib/provider/sidecar-schema.js +140 -8
- package/lib/provider/sidecar-schema.js.map +1 -1
- package/lib/provider/sidecar.d.ts +3 -1
- package/lib/provider/sidecar.d.ts.map +1 -1
- package/lib/provider/sidecar.js +6 -1
- package/lib/provider/sidecar.js.map +1 -1
- package/lib/provider/subprocess.d.ts +37 -0
- package/lib/provider/subprocess.d.ts.map +1 -0
- package/lib/provider/subprocess.js +319 -0
- package/lib/provider/subprocess.js.map +1 -0
- package/lib/provider/transaction.d.ts +65 -0
- package/lib/provider/transaction.d.ts.map +1 -0
- package/lib/provider/transaction.js +1011 -0
- package/lib/provider/transaction.js.map +1 -0
- package/lib/provider/types.d.ts +98 -7
- package/lib/provider/types.d.ts.map +1 -1
- package/lib/provider/types.js +1 -1
- package/lib/provider/types.js.map +1 -1
- package/lib/typert.host.js +133 -30
- package/lib/typert.remote-client.d.ts +7 -3
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +133 -30
- package/package.json +3 -1
package/lib/client.js
CHANGED
|
@@ -36,10 +36,13 @@ window.__ModuleLoader__.load({
|
|
|
36
36
|
"worktree.mainWithBranch": "本地({branch})",
|
|
37
37
|
"worktree.detached": "已分离 Worktree",
|
|
38
38
|
"worktree.repair": "Worktree 需要修复",
|
|
39
|
+
"worktree.recovery": "Worktree 需要恢复",
|
|
39
40
|
"worktree.ready": "活动 Worktree 已就绪",
|
|
40
41
|
"worktree.expand": "展开 {name}",
|
|
41
42
|
"worktree.collapse": "收起 {name}",
|
|
42
43
|
"worktree.options": "Worktree 选项:{name}",
|
|
44
|
+
"worktree.copyPath": "复制路径",
|
|
45
|
+
"worktree.createNew": "创建新的 Worktree",
|
|
43
46
|
"worktree.remove": "移除 Worktree",
|
|
44
47
|
"worktree.removeDescription": "移除“{name}”?Session 会保留在 DSH 中,并作为已分离关系继续可用。",
|
|
45
48
|
"worktree.removeExternalDescription": "移除“{name}”?这会删除关联的外部 Worktree 目录。Session 会保留在 DSH 中,并作为已分离关系继续可用。",
|
|
@@ -70,9 +73,27 @@ window.__ModuleLoader__.load({
|
|
|
70
73
|
"session.rename": "重命名会话",
|
|
71
74
|
"session.fork": "Fork 会话",
|
|
72
75
|
"session.archive": "归档会话",
|
|
76
|
+
"session.copyId": "复制 Session ID",
|
|
73
77
|
"session.expandMore": "展开其余 {count} 个会话",
|
|
74
78
|
"session.collapse": "收起",
|
|
75
79
|
"session.name": "会话名称",
|
|
80
|
+
"session.status.running": "进行中",
|
|
81
|
+
"session.status.subagentsRunning.one": "{n} 个子代理运行中",
|
|
82
|
+
"session.status.subagentsRunning.other": "{n} 个子代理运行中",
|
|
83
|
+
"session.status.idle": "空闲",
|
|
84
|
+
"session.status.waitingApproval": "等待审批",
|
|
85
|
+
"session.status.planReview": "计划待审",
|
|
86
|
+
"session.status.waitingAnswer": "等待回答",
|
|
87
|
+
"session.status.completed": "已完成",
|
|
88
|
+
copy: "复制",
|
|
89
|
+
"hover.copied": "已复制",
|
|
90
|
+
"session.time.now": "刚刚",
|
|
91
|
+
"session.time.minutes": "{n}分钟",
|
|
92
|
+
"session.time.hours": "{n}小时",
|
|
93
|
+
"session.time.days": "{n}天",
|
|
94
|
+
"session.time.months": "{n}个月",
|
|
95
|
+
"session.time.years": "{n}年",
|
|
96
|
+
"session.time.ago": "{t}前",
|
|
76
97
|
"dialog.close": "关闭",
|
|
77
98
|
"dialog.closeWorkspaceRename": "关闭重命名工作区对话框",
|
|
78
99
|
"dialog.closeWorkspaceDelete": "关闭删除工作区对话框",
|
|
@@ -84,6 +105,14 @@ window.__ModuleLoader__.load({
|
|
|
84
105
|
"action.retry": "重试",
|
|
85
106
|
"action.retryBinding": "重试绑定",
|
|
86
107
|
"action.openCreatedSession": "打开已创建的 Session",
|
|
108
|
+
"permission.fallbackWorkspaceWrite": "无法使用 Worktree 完全访问预设,已降级为 workspace-write;保留审批提示。",
|
|
109
|
+
"permission.userRestricted": "已保留你在 DSH 原生权限界面选择的限制,未自动提升此 Worktree Session。",
|
|
110
|
+
"permission.unverified": "无法验证 Worktree Session 的权限服务;Session 已保留,但完全访问未得到确认。",
|
|
111
|
+
"permission.unavailable": "Worktree Session 权限状态暂时不可用,请重试。",
|
|
112
|
+
"permission.fullAccessTitle": "确认启用 Worktree Full access?",
|
|
113
|
+
"permission.fullAccessDescription": "启用 Worktree Full access 后,此 Session 可能访问 Session 目录之外的关联 Git 元数据和 Worktree 文件。完全访问会关闭此 Session 的文件系统沙箱,但会保留审批提示;网络和进程策略不变。目标 Worktree:{cwd}",
|
|
114
|
+
"permission.fullAccessAcknowledge": "我已了解风险,并愿意继续",
|
|
115
|
+
"permission.fullAccessEnable": "启用 Worktree Full access",
|
|
87
116
|
"status.loading": "正在加载工作区…",
|
|
88
117
|
"error.worktreeDataUnavailable": "Worktree 数据不可用,请重试。",
|
|
89
118
|
"error.gitNotInstalled": "Git 未安装或不可用,请安装 Git 后重试。",
|
|
@@ -98,12 +127,18 @@ window.__ModuleLoader__.load({
|
|
|
98
127
|
"error.worktreeRecordMissing": "Worktree 注册未返回 Worktree 记录,请重试请求。",
|
|
99
128
|
"error.worktreeImportInvalid": "这个 Worktree 无法导入,请选择同一 Workspace 中有效的绝对路径。",
|
|
100
129
|
"error.worktreeAlreadyManaged": "这个 Worktree 已由插件管理。",
|
|
130
|
+
"error.worktreeMutationBusy": "另一个 DSH 实例正在修改 Worktree 状态,请稍后重试。",
|
|
131
|
+
"error.worktreeStateConflict": "Worktree 状态已经变化,请刷新后重试。",
|
|
132
|
+
"error.worktreeRecoveryRequired": "Worktree 状态需要恢复;请先完成恢复后再重试破坏性操作。",
|
|
133
|
+
"error.worktreeIdentityChanged": "Worktree 或 repository 身份已经变化,需要恢复后再操作。",
|
|
101
134
|
"error.worktreeRegistrationSessionUnavailable": "Worktree 已注册,但 Session 创建不可用,请重新连接后重试。",
|
|
102
135
|
"error.workspaceRenameUnavailable": "工作区重命名不可用,请重新连接后重试。",
|
|
103
136
|
"error.workspaceDeleteUnavailable": "工作区删除不可用,请重新连接后重试。",
|
|
104
137
|
"error.sessionRenameUnavailable": "会话重命名不可用,请重新连接后重试。",
|
|
105
138
|
"error.sessionBindingFailed": "Session {sessionId} 已创建,但 Worktree 绑定失败:{reason}",
|
|
106
139
|
"error.sessionAlreadyBound": "Session 已绑定到其他 Worktree,未创建新的 Session。",
|
|
140
|
+
"error.worktreePermissionConfirmationRequired": "Session 和绑定已保留;确认完全访问后重试,未打开 Session。",
|
|
141
|
+
"error.worktreePermissionFailed": "Worktree Session 权限设置失败,可重试:{reason}",
|
|
107
142
|
"error.sessionListNotReady": "Session 列表尚未就绪,请重试。",
|
|
108
143
|
"error.sessionFactsIncomplete": "Session 信息尚未完整,请重试。",
|
|
109
144
|
"error.worktreeSessionRepairRequired": "当前 Worktree 的 Session 绑定需要修复,请重试。",
|
|
@@ -138,10 +173,13 @@ window.__ModuleLoader__.load({
|
|
|
138
173
|
"worktree.mainWithBranch": "Local ({branch})",
|
|
139
174
|
"worktree.detached": "Detached Worktree",
|
|
140
175
|
"worktree.repair": "Worktree needs repair",
|
|
176
|
+
"worktree.recovery": "Worktree requires recovery",
|
|
141
177
|
"worktree.ready": "Active Worktree ready",
|
|
142
178
|
"worktree.expand": "Expand {name}",
|
|
143
179
|
"worktree.collapse": "Collapse {name}",
|
|
144
180
|
"worktree.options": "Worktree options for {name}",
|
|
181
|
+
"worktree.copyPath": "Copy path",
|
|
182
|
+
"worktree.createNew": "Create new Worktree",
|
|
145
183
|
"worktree.remove": "Remove Worktree",
|
|
146
184
|
"worktree.removeDescription": "Remove {name}? Sessions stay in DSH and remain available as detached bindings.",
|
|
147
185
|
"worktree.removeExternalDescription": "Remove {name}? This deletes the linked external Worktree directory. Sessions stay in DSH and remain available as detached bindings.",
|
|
@@ -172,9 +210,27 @@ window.__ModuleLoader__.load({
|
|
|
172
210
|
"session.rename": "Rename session",
|
|
173
211
|
"session.fork": "Fork session",
|
|
174
212
|
"session.archive": "Archive session",
|
|
213
|
+
"session.copyId": "Copy session ID",
|
|
175
214
|
"session.expandMore": "Expand {count} more",
|
|
176
215
|
"session.collapse": "Collapse",
|
|
177
216
|
"session.name": "Session name",
|
|
217
|
+
"session.status.running": "Running",
|
|
218
|
+
"session.status.subagentsRunning.one": "{n} subagent running",
|
|
219
|
+
"session.status.subagentsRunning.other": "{n} subagents running",
|
|
220
|
+
"session.status.idle": "Idle",
|
|
221
|
+
"session.status.waitingApproval": "Waiting for approval",
|
|
222
|
+
"session.status.planReview": "Plan awaiting review",
|
|
223
|
+
"session.status.waitingAnswer": "Waiting for answer",
|
|
224
|
+
"session.status.completed": "Completed",
|
|
225
|
+
copy: "Copy",
|
|
226
|
+
"hover.copied": "Copied",
|
|
227
|
+
"session.time.now": "now",
|
|
228
|
+
"session.time.minutes": "{n}min",
|
|
229
|
+
"session.time.hours": "{n}h",
|
|
230
|
+
"session.time.days": "{n}d",
|
|
231
|
+
"session.time.months": "{n}mo",
|
|
232
|
+
"session.time.years": "{n}y",
|
|
233
|
+
"session.time.ago": "{t} ago",
|
|
178
234
|
"dialog.close": "Close",
|
|
179
235
|
"dialog.closeWorkspaceRename": "Close Rename Workspace dialog",
|
|
180
236
|
"dialog.closeWorkspaceDelete": "Close Delete Workspace dialog",
|
|
@@ -186,6 +242,14 @@ window.__ModuleLoader__.load({
|
|
|
186
242
|
"action.retry": "Retry",
|
|
187
243
|
"action.retryBinding": "Retry Binding",
|
|
188
244
|
"action.openCreatedSession": "Open Created Session",
|
|
245
|
+
"permission.fallbackWorkspaceWrite": "The Worktree Full Access preset is unavailable; fell back to workspace-write with approval prompts enabled.",
|
|
246
|
+
"permission.userRestricted": "The restriction selected in DSH’s native permission UI was preserved; this Worktree Session was not elevated.",
|
|
247
|
+
"permission.unverified": "The Worktree Session permission service could not be verified; the Session was retained, but Full Access is not confirmed.",
|
|
248
|
+
"permission.unavailable": "The Worktree Session permission state is temporarily unavailable; retry the request.",
|
|
249
|
+
"permission.fullAccessTitle": "Enable Worktree Full access?",
|
|
250
|
+
"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}",
|
|
251
|
+
"permission.fullAccessAcknowledge": "I understand the risks and want to continue",
|
|
252
|
+
"permission.fullAccessEnable": "Enable Worktree Full access",
|
|
189
253
|
"status.loading": "Loading Workspaces…",
|
|
190
254
|
"error.worktreeDataUnavailable": "Worktree data is unavailable. Retry the request.",
|
|
191
255
|
"error.gitNotInstalled": "Git is not installed or unavailable. Install Git and retry.",
|
|
@@ -200,12 +264,18 @@ window.__ModuleLoader__.load({
|
|
|
200
264
|
"error.worktreeRecordMissing": "Worktree registration returned no Worktree record; retry the request.",
|
|
201
265
|
"error.worktreeImportInvalid": "This Worktree cannot be imported. Choose a valid absolute path in this Workspace.",
|
|
202
266
|
"error.worktreeAlreadyManaged": "This Worktree is already managed by the plugin.",
|
|
267
|
+
"error.worktreeMutationBusy": "Another DSH instance is mutating Worktree state; retry shortly.",
|
|
268
|
+
"error.worktreeStateConflict": "The Worktree state changed; refresh and retry the request.",
|
|
269
|
+
"error.worktreeRecoveryRequired": "Worktree state requires recovery; resolve it before retrying destructive actions.",
|
|
270
|
+
"error.worktreeIdentityChanged": "The Worktree or repository identity changed; recovery is required before acting.",
|
|
203
271
|
"error.worktreeRegistrationSessionUnavailable": "The Worktree was registered, but Session creation is unavailable; retry after reconnecting.",
|
|
204
272
|
"error.workspaceRenameUnavailable": "Workspace rename is unavailable; retry after reconnecting.",
|
|
205
273
|
"error.workspaceDeleteUnavailable": "Workspace delete is unavailable; retry after reconnecting.",
|
|
206
274
|
"error.sessionRenameUnavailable": "Session rename is unavailable; retry after reconnecting.",
|
|
207
275
|
"error.sessionBindingFailed": "Session {sessionId} was created, but Worktree binding failed: {reason}",
|
|
208
276
|
"error.sessionAlreadyBound": "The Session is already bound to another Worktree; no new Session was created.",
|
|
277
|
+
"error.worktreePermissionConfirmationRequired": "The Session and binding were retained; confirm Full Access and retry. The Session was not opened.",
|
|
278
|
+
"error.worktreePermissionFailed": "Worktree Session permission setup failed; retryable error: {reason}",
|
|
209
279
|
"error.sessionListNotReady": "The Session list is not ready yet; retry the request.",
|
|
210
280
|
"error.sessionFactsIncomplete": "Session facts are incomplete; retry the request.",
|
|
211
281
|
"error.worktreeSessionRepairRequired": "The current Worktree Session binding needs repair; retry the request.",
|
|
@@ -231,7 +301,9 @@ window.__ModuleLoader__.load({
|
|
|
231
301
|
removeWorktree: "worktreeManager/removeWorktree",
|
|
232
302
|
insertWorktreeBefore: "worktreeManager/insertWorktreeBefore",
|
|
233
303
|
listBindings: "worktreeManager/listBindings",
|
|
234
|
-
bindSession: "worktreeManager/bindSession"
|
|
304
|
+
bindSession: "worktreeManager/bindSession",
|
|
305
|
+
ensureWorktreePermission: "worktreeManager/ensureWorktreePermission",
|
|
306
|
+
normalizeDetachedWorktreePermissions: "worktreeManager/normalizeDetachedWorktreePermissions"
|
|
235
307
|
});
|
|
236
308
|
/** Browser-safe error shared by transport, Gateway, endpoint and domain failures. */
|
|
237
309
|
var WorktreeConnectionError = class extends Error {
|
|
@@ -246,14 +318,14 @@ window.__ModuleLoader__.load({
|
|
|
246
318
|
this.retryable = options.retryable;
|
|
247
319
|
}
|
|
248
320
|
};
|
|
249
|
-
function isRecord$
|
|
321
|
+
function isRecord$2(value) {
|
|
250
322
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
251
323
|
}
|
|
252
324
|
function isWorktreeError(value) {
|
|
253
|
-
return isRecord$
|
|
325
|
+
return isRecord$2(value) && typeof value.code === "string" && typeof value.message === "string" && isRecord$2(value.details);
|
|
254
326
|
}
|
|
255
327
|
function isWorktreeRemoteResult(value) {
|
|
256
|
-
if (!isRecord$
|
|
328
|
+
if (!isRecord$2(value) || typeof value.ok !== "boolean") return false;
|
|
257
329
|
return value.ok || isWorktreeError(value.error) && value.error.details !== void 0;
|
|
258
330
|
}
|
|
259
331
|
function disposedError() {
|
|
@@ -274,7 +346,7 @@ window.__ModuleLoader__.load({
|
|
|
274
346
|
});
|
|
275
347
|
}
|
|
276
348
|
function gatewayFailure(endpoint, result) {
|
|
277
|
-
const rawDetails = isRecord$
|
|
349
|
+
const rawDetails = isRecord$2(result.error.details) ? result.error.details : {};
|
|
278
350
|
throw new WorktreeConnectionError({
|
|
279
351
|
code: result.error.code,
|
|
280
352
|
message: result.error.message,
|
|
@@ -343,6 +415,8 @@ window.__ModuleLoader__.load({
|
|
|
343
415
|
},
|
|
344
416
|
listBindings: (input) => invoke("listBindings", input),
|
|
345
417
|
bindSession: (input) => invoke("bindSession", input),
|
|
418
|
+
ensureWorktreePermission: (input) => invoke("ensureWorktreePermission", input),
|
|
419
|
+
normalizeDetachedWorktreePermissions: (input) => invoke("normalizeDetachedWorktreePermissions", input),
|
|
346
420
|
dispose() {
|
|
347
421
|
if (disposed) return;
|
|
348
422
|
disposed = true;
|
|
@@ -352,7 +426,7 @@ window.__ModuleLoader__.load({
|
|
|
352
426
|
};
|
|
353
427
|
}
|
|
354
428
|
//#endregion
|
|
355
|
-
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/
|
|
429
|
+
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_4ab905d8-c228-470f-9208-36c3552257a4/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
|
|
356
430
|
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
431
|
const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
|
|
358
432
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
|
|
@@ -375,18 +449,25 @@ window.__ModuleLoader__.load({
|
|
|
375
449
|
function WorktreeContextLabel({ value, t }) {
|
|
376
450
|
if (value.kind === "none") return null;
|
|
377
451
|
const ariaLabel = value.kind === "main" ? t("context.main", { name: value.label }) : t("context.worktree", { name: value.label });
|
|
378
|
-
return (0, react_jsx_runtime.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
452
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
453
|
+
anchor: (0, react_jsx_runtime.jsxs)("span", {
|
|
454
|
+
className: worktree_context_css_default.headerContext,
|
|
455
|
+
title: value.label,
|
|
456
|
+
"aria-label": ariaLabel,
|
|
457
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {
|
|
458
|
+
size: 14,
|
|
459
|
+
className: worktree_context_css_default.contextIcon,
|
|
460
|
+
"aria-hidden": "true"
|
|
461
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
462
|
+
className: worktree_context_css_default.contextLabel,
|
|
463
|
+
children: value.label
|
|
464
|
+
})]
|
|
465
|
+
}),
|
|
466
|
+
content: (0, react_jsx_runtime.jsx)("div", {
|
|
467
|
+
className: worktree_context_css_default.contextHoverTitle,
|
|
388
468
|
children: value.label
|
|
389
|
-
})
|
|
469
|
+
}),
|
|
470
|
+
openDelayMs: 500
|
|
390
471
|
});
|
|
391
472
|
}
|
|
392
473
|
/** Render the current branch or active Worktree branch beside the Session title. */
|
|
@@ -399,8 +480,8 @@ window.__ModuleLoader__.load({
|
|
|
399
480
|
});
|
|
400
481
|
}
|
|
401
482
|
//#endregion
|
|
402
|
-
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/
|
|
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";
|
|
483
|
+
//#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_4ab905d8-c228-470f-9208-36c3552257a4/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
|
|
484
|
+
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
485
|
const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
|
|
405
486
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
|
|
406
487
|
const tag = document.createElement("style");
|
|
@@ -427,6 +508,7 @@ window.__ModuleLoader__.load({
|
|
|
427
508
|
"workspaceLabel": "-cerbur-clutch-dsh-worktree-workspaceLabel",
|
|
428
509
|
"content": "-cerbur-clutch-dsh-worktree-content",
|
|
429
510
|
"error": "-cerbur-clutch-dsh-worktree-error",
|
|
511
|
+
"notice": "-cerbur-clutch-dsh-worktree-notice",
|
|
430
512
|
"retryButton": "-cerbur-clutch-dsh-worktree-retryButton",
|
|
431
513
|
"actionButton": "-cerbur-clutch-dsh-worktree-actionButton",
|
|
432
514
|
"recoveryActions": "-cerbur-clutch-dsh-worktree-recoveryActions",
|
|
@@ -459,9 +541,14 @@ window.__ModuleLoader__.load({
|
|
|
459
541
|
"worktreeState": "-cerbur-clutch-dsh-worktree-worktreeState",
|
|
460
542
|
"workspaceTitle": "-cerbur-clutch-dsh-worktree-workspaceTitle",
|
|
461
543
|
"worktreeHoverTitle": "-cerbur-clutch-dsh-worktree-worktreeHoverTitle",
|
|
544
|
+
"sessionHoverContent": "-cerbur-clutch-dsh-worktree-sessionHoverContent",
|
|
545
|
+
"sessionHoverTitle": "-cerbur-clutch-dsh-worktree-sessionHoverTitle",
|
|
546
|
+
"sessionHoverTime": "-cerbur-clutch-dsh-worktree-sessionHoverTime",
|
|
547
|
+
"sessionHoverStatus": "-cerbur-clutch-dsh-worktree-sessionHoverStatus",
|
|
462
548
|
"treeActionSlot": "-cerbur-clutch-dsh-worktree-treeActionSlot",
|
|
463
549
|
"workspaceActions": "-cerbur-clutch-dsh-worktree-workspaceActions",
|
|
464
550
|
"menuAction": "-cerbur-clutch-dsh-worktree-menuAction",
|
|
551
|
+
"groupActivity": "-cerbur-clutch-dsh-worktree-groupActivity",
|
|
465
552
|
"dropBefore": "-cerbur-clutch-dsh-worktree-dropBefore",
|
|
466
553
|
"dropAfter": "-cerbur-clutch-dsh-worktree-dropAfter",
|
|
467
554
|
"treeChildren": "-cerbur-clutch-dsh-worktree-treeChildren",
|
|
@@ -470,7 +557,11 @@ window.__ModuleLoader__.load({
|
|
|
470
557
|
"worktreeGroup": "-cerbur-clutch-dsh-worktree-worktreeGroup",
|
|
471
558
|
"treeSessionRow": "-cerbur-clutch-dsh-worktree-treeSessionRow",
|
|
472
559
|
"treeSessionContent": "-cerbur-clutch-dsh-worktree-treeSessionContent",
|
|
560
|
+
"sessionTrailing": "-cerbur-clutch-dsh-worktree-sessionTrailing",
|
|
561
|
+
"sessionMeta": "-cerbur-clutch-dsh-worktree-sessionMeta",
|
|
473
562
|
"rowActions": "-cerbur-clutch-dsh-worktree-rowActions",
|
|
563
|
+
"sessionStatus": "-cerbur-clutch-dsh-worktree-sessionStatus",
|
|
564
|
+
"sessionTime": "-cerbur-clutch-dsh-worktree-sessionTime",
|
|
474
565
|
"sessionOverflowButton": "-cerbur-clutch-dsh-worktree-sessionOverflowButton",
|
|
475
566
|
"renameInput": "-cerbur-clutch-dsh-worktree-renameInput",
|
|
476
567
|
"renameError": "-cerbur-clutch-dsh-worktree-renameError",
|
|
@@ -746,27 +837,27 @@ window.__ModuleLoader__.load({
|
|
|
746
837
|
//#region lib/client/worktree-expand-state.js
|
|
747
838
|
/** Browser-local storage identity; never sent to DSH or the plugin sidecar. */
|
|
748
839
|
const WORKTREE_EXPAND_STATE_STORAGE_KEY = "clutch-dsh-worktree.expand-state";
|
|
749
|
-
function emptyState() {
|
|
840
|
+
function emptyState$1() {
|
|
750
841
|
return {
|
|
751
842
|
collapsedWorkspaceIds: {},
|
|
752
843
|
collapsedMainWorkspaceIds: {},
|
|
753
844
|
collapsedWorktreeIds: {}
|
|
754
845
|
};
|
|
755
846
|
}
|
|
756
|
-
function isRecord(value) {
|
|
847
|
+
function isRecord$1(value) {
|
|
757
848
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
758
849
|
}
|
|
759
|
-
function normalizeIds(value) {
|
|
760
|
-
if (!isRecord(value)) return {};
|
|
850
|
+
function normalizeIds$1(value) {
|
|
851
|
+
if (!isRecord$1(value)) return {};
|
|
761
852
|
return Object.fromEntries(Object.entries(value).filter(([id, collapsed]) => id.length > 0 && collapsed === true));
|
|
762
853
|
}
|
|
763
854
|
/** Turn any persisted JSON value into the current state shape. */
|
|
764
855
|
function normalizeWorktreeExpandState(value) {
|
|
765
|
-
const source = isRecord(value) ? value : {};
|
|
856
|
+
const source = isRecord$1(value) ? value : {};
|
|
766
857
|
return {
|
|
767
|
-
collapsedWorkspaceIds: normalizeIds(source.collapsedWorkspaceIds),
|
|
768
|
-
collapsedMainWorkspaceIds: normalizeIds(source.collapsedMainWorkspaceIds),
|
|
769
|
-
collapsedWorktreeIds: normalizeIds(source.collapsedWorktreeIds)
|
|
858
|
+
collapsedWorkspaceIds: normalizeIds$1(source.collapsedWorkspaceIds),
|
|
859
|
+
collapsedMainWorkspaceIds: normalizeIds$1(source.collapsedMainWorkspaceIds),
|
|
860
|
+
collapsedWorktreeIds: normalizeIds$1(source.collapsedWorktreeIds)
|
|
770
861
|
};
|
|
771
862
|
}
|
|
772
863
|
function isWorkspaceExpanded(state, workspaceId) {
|
|
@@ -790,9 +881,9 @@ window.__ModuleLoader__.load({
|
|
|
790
881
|
function createWorktreeExpandStateStore(snapshotStoreFactory) {
|
|
791
882
|
let store;
|
|
792
883
|
try {
|
|
793
|
-
store = snapshotStoreFactory(emptyState(), { persist: { name: WORKTREE_EXPAND_STATE_STORAGE_KEY } });
|
|
884
|
+
store = snapshotStoreFactory(emptyState$1(), { persist: { name: WORKTREE_EXPAND_STATE_STORAGE_KEY } });
|
|
794
885
|
} catch {
|
|
795
|
-
store = snapshotStoreFactory(emptyState());
|
|
886
|
+
store = snapshotStoreFactory(emptyState$1());
|
|
796
887
|
}
|
|
797
888
|
store.set(normalizeWorktreeExpandState(store.getSnapshot()));
|
|
798
889
|
return Object.assign(store, { actions: {
|
|
@@ -883,6 +974,14 @@ window.__ModuleLoader__.load({
|
|
|
883
974
|
function reason(error, t) {
|
|
884
975
|
return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
|
|
885
976
|
}
|
|
977
|
+
function formatWorktreePermissionNotice(result, t) {
|
|
978
|
+
switch (result.status) {
|
|
979
|
+
case "fallback-workspace-write": return t("permission.fallbackWorkspaceWrite");
|
|
980
|
+
case "user-restricted": return t("permission.userRestricted");
|
|
981
|
+
case "unverified": return t("permission.unverified");
|
|
982
|
+
default: return t("permission.unavailable");
|
|
983
|
+
}
|
|
984
|
+
}
|
|
886
985
|
function formatWorktreeViewError(error, t) {
|
|
887
986
|
switch (error.code) {
|
|
888
987
|
case "CLIENT_DISPOSED": return t("error.connectionDisposed");
|
|
@@ -899,6 +998,10 @@ window.__ModuleLoader__.load({
|
|
|
899
998
|
case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
|
|
900
999
|
case "WORKTREE_IMPORT_INVALID": return t("error.worktreeImportInvalid");
|
|
901
1000
|
case "WORKTREE_ALREADY_MANAGED": return t("error.worktreeAlreadyManaged");
|
|
1001
|
+
case "WORKTREE_MUTATION_BUSY": return t("error.worktreeMutationBusy");
|
|
1002
|
+
case "WORKTREE_STATE_CONFLICT": return t("error.worktreeStateConflict");
|
|
1003
|
+
case "WORKTREE_RECOVERY_REQUIRED": return t("error.worktreeRecoveryRequired");
|
|
1004
|
+
case "WORKTREE_IDENTITY_CHANGED": return t("error.worktreeIdentityChanged");
|
|
902
1005
|
case "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE": return t("error.worktreeRegistrationSessionUnavailable");
|
|
903
1006
|
case "WORKSPACE_RENAME_UNAVAILABLE": return t("error.workspaceRenameUnavailable");
|
|
904
1007
|
case "WORKSPACE_DELETE_UNAVAILABLE": return t("error.workspaceDeleteUnavailable");
|
|
@@ -908,6 +1011,8 @@ window.__ModuleLoader__.load({
|
|
|
908
1011
|
reason: reason(error, t)
|
|
909
1012
|
});
|
|
910
1013
|
case "SESSION_ALREADY_BOUND": return t("error.sessionAlreadyBound");
|
|
1014
|
+
case "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED": return t("error.worktreePermissionConfirmationRequired");
|
|
1015
|
+
case "WORKTREE_PERMISSION_FAILED": return t("error.worktreePermissionFailed", { reason: reason(error, t) });
|
|
911
1016
|
case "SESSION_LIST_NOT_READY": return t("error.sessionListNotReady");
|
|
912
1017
|
case "SESSION_FACTS_INCOMPLETE": return t("error.sessionFactsIncomplete");
|
|
913
1018
|
case "WORKTREE_SESSION_REPAIR_REQUIRED": return t("error.worktreeSessionRepairRequired");
|
|
@@ -919,6 +1024,127 @@ window.__ModuleLoader__.load({
|
|
|
919
1024
|
}
|
|
920
1025
|
//#endregion
|
|
921
1026
|
//#region lib/client/session-view.js
|
|
1027
|
+
function isPendingInteractionStatus(value) {
|
|
1028
|
+
return value === "approval" || value === "plan-review" || value === "question";
|
|
1029
|
+
}
|
|
1030
|
+
function validUpdatedAt(value) {
|
|
1031
|
+
return value !== void 0 && Number.isFinite(value);
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Native-compatible subagent lineage index. The upstream runtime's public client
|
|
1035
|
+
* entry is a browser module-loader bundle, so keeping this pure mirror local lets
|
|
1036
|
+
* the browser Consumer and its Node tests share the same status semantics.
|
|
1037
|
+
*/
|
|
1038
|
+
function indexSubagentDescendants(summaries) {
|
|
1039
|
+
const indexed = /* @__PURE__ */ new Map();
|
|
1040
|
+
for (const descendant of Object.values(summaries)) {
|
|
1041
|
+
if (descendant.origin !== "subagent") continue;
|
|
1042
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1043
|
+
let current = descendant;
|
|
1044
|
+
while (current?.origin === "subagent" && current.parentId !== void 0 && !seen.has(current.id)) {
|
|
1045
|
+
seen.add(current.id);
|
|
1046
|
+
const aggregate = indexed.get(current.parentId);
|
|
1047
|
+
if (aggregate === void 0) indexed.set(current.parentId, {
|
|
1048
|
+
count: 1,
|
|
1049
|
+
runningCount: descendant.running ? 1 : 0
|
|
1050
|
+
});
|
|
1051
|
+
else {
|
|
1052
|
+
aggregate.count += 1;
|
|
1053
|
+
if (descendant.running) aggregate.runningCount += 1;
|
|
1054
|
+
}
|
|
1055
|
+
current = summaries[current.parentId];
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return indexed;
|
|
1059
|
+
}
|
|
1060
|
+
/** Native Workspace relative-time buckets, kept pure for deterministic rendering/tests. */
|
|
1061
|
+
function relativeTime(updatedAt, now) {
|
|
1062
|
+
if (!validUpdatedAt(updatedAt) || !Number.isFinite(now)) return void 0;
|
|
1063
|
+
const MIN = 6e4;
|
|
1064
|
+
const HOUR = 36e5;
|
|
1065
|
+
const DAY = 864e5;
|
|
1066
|
+
const diff = Math.max(0, now - updatedAt);
|
|
1067
|
+
if (diff < MIN) return {
|
|
1068
|
+
unit: "now",
|
|
1069
|
+
n: 0
|
|
1070
|
+
};
|
|
1071
|
+
if (diff < HOUR) return {
|
|
1072
|
+
unit: "minutes",
|
|
1073
|
+
n: Math.floor(diff / MIN)
|
|
1074
|
+
};
|
|
1075
|
+
if (diff < DAY) return {
|
|
1076
|
+
unit: "hours",
|
|
1077
|
+
n: Math.floor(diff / HOUR)
|
|
1078
|
+
};
|
|
1079
|
+
if (diff < 30 * DAY) return {
|
|
1080
|
+
unit: "days",
|
|
1081
|
+
n: Math.floor(diff / DAY)
|
|
1082
|
+
};
|
|
1083
|
+
if (diff < 365 * DAY) return {
|
|
1084
|
+
unit: "months",
|
|
1085
|
+
n: Math.floor(diff / (30 * DAY))
|
|
1086
|
+
};
|
|
1087
|
+
return {
|
|
1088
|
+
unit: "years",
|
|
1089
|
+
n: Math.floor(diff / (365 * DAY))
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
/** Match native Workspace status priority while retaining the aggregate subagent count. */
|
|
1093
|
+
function sessionStatus(session, runningSubagentCount) {
|
|
1094
|
+
const count = Number.isFinite(runningSubagentCount) && runningSubagentCount > 0 ? Math.floor(runningSubagentCount) : 0;
|
|
1095
|
+
if (isPendingInteractionStatus(session.pendingInteraction)) return {
|
|
1096
|
+
state: "warning",
|
|
1097
|
+
labelKey: session.pendingInteraction === "approval" ? "waitingApproval" : session.pendingInteraction === "plan-review" ? "planReview" : "waitingAnswer",
|
|
1098
|
+
runningSubagentCount: count
|
|
1099
|
+
};
|
|
1100
|
+
if (session.running === true) return {
|
|
1101
|
+
state: "ongoing",
|
|
1102
|
+
labelKey: "running",
|
|
1103
|
+
runningSubagentCount: count
|
|
1104
|
+
};
|
|
1105
|
+
if (count > 0) return {
|
|
1106
|
+
state: "ongoing",
|
|
1107
|
+
labelKey: "subagentsRunning",
|
|
1108
|
+
runningSubagentCount: count
|
|
1109
|
+
};
|
|
1110
|
+
if (session.completed === true) return {
|
|
1111
|
+
state: "done",
|
|
1112
|
+
labelKey: "completed",
|
|
1113
|
+
runningSubagentCount: 0
|
|
1114
|
+
};
|
|
1115
|
+
return {
|
|
1116
|
+
state: "done",
|
|
1117
|
+
labelKey: "idle",
|
|
1118
|
+
runningSubagentCount: 0
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
function toLineageSummary(sessionId, summary) {
|
|
1122
|
+
return {
|
|
1123
|
+
id: sessionId,
|
|
1124
|
+
running: summary.running === true,
|
|
1125
|
+
...summary.parentId === void 0 ? {} : { parentId: summary.parentId },
|
|
1126
|
+
...summary.origin === "subagent" ? { origin: "subagent" } : {}
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
/** Derive row and group activity facts from one retained DSH Session snapshot. */
|
|
1130
|
+
function deriveSessionPresentationIndex(sessions) {
|
|
1131
|
+
const descendants = indexSubagentDescendants(Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => [sessionId, toLineageSummary(sessionId, summary)])));
|
|
1132
|
+
return Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => {
|
|
1133
|
+
const runningSubagentCount = descendants.get(sessionId)?.runningCount ?? 0;
|
|
1134
|
+
return [sessionId, {
|
|
1135
|
+
status: sessionStatus(summary, runningSubagentCount),
|
|
1136
|
+
running: summary.running === true,
|
|
1137
|
+
ongoing: summary.running === true || runningSubagentCount > 0,
|
|
1138
|
+
runningSubagentCount,
|
|
1139
|
+
completed: summary.completed === true,
|
|
1140
|
+
...validUpdatedAt(summary.updatedAt) ? { updatedAt: summary.updatedAt } : {}
|
|
1141
|
+
}];
|
|
1142
|
+
}));
|
|
1143
|
+
}
|
|
1144
|
+
/** Aggregate only live ongoing activity; callers decide which IDs are in the group. */
|
|
1145
|
+
function hasOngoingSession(sessionIds, presentations) {
|
|
1146
|
+
return sessionIds.some((sessionId) => presentations[sessionId]?.ongoing === true);
|
|
1147
|
+
}
|
|
922
1148
|
/** Read the native blank flag without inferring blankness from title or id. */
|
|
923
1149
|
function isBlankSession(sessionId, sessions) {
|
|
924
1150
|
return sessions.byId[sessionId]?.blank === true;
|
|
@@ -943,6 +1169,193 @@ window.__ModuleLoader__.load({
|
|
|
943
1169
|
return (summary?.displayTitle ?? sessionId).toLocaleLowerCase().includes(normalizedQuery);
|
|
944
1170
|
}
|
|
945
1171
|
//#endregion
|
|
1172
|
+
//#region lib/client/worktree-session-order.js
|
|
1173
|
+
/** Browser-only persistence key; this state never crosses the DSH or sidecar boundary. */
|
|
1174
|
+
const WORKTREE_SESSION_ORDER_STORAGE_KEY = "clutch-dsh-worktree.session-order";
|
|
1175
|
+
function emptyState() {
|
|
1176
|
+
return { accounts: {} };
|
|
1177
|
+
}
|
|
1178
|
+
function isRecord(value) {
|
|
1179
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1180
|
+
}
|
|
1181
|
+
function isValidTimestamp(value) {
|
|
1182
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
1183
|
+
}
|
|
1184
|
+
function normalizeIds(value) {
|
|
1185
|
+
if (!Array.isArray(value)) return [];
|
|
1186
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1187
|
+
const ids = [];
|
|
1188
|
+
for (const id of value) {
|
|
1189
|
+
if (typeof id !== "string" || id.length === 0 || seen.has(id)) continue;
|
|
1190
|
+
seen.add(id);
|
|
1191
|
+
ids.push(id);
|
|
1192
|
+
}
|
|
1193
|
+
return ids;
|
|
1194
|
+
}
|
|
1195
|
+
function normalizeAccount(value) {
|
|
1196
|
+
if (!isRecord(value)) return void 0;
|
|
1197
|
+
const order = normalizeIds(value.order);
|
|
1198
|
+
const allowed = new Set(order);
|
|
1199
|
+
const observedUpdatedAt = {};
|
|
1200
|
+
if (isRecord(value.observedUpdatedAt)) {
|
|
1201
|
+
for (const [id, timestamp] of Object.entries(value.observedUpdatedAt)) if (allowed.has(id) && isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
|
|
1202
|
+
}
|
|
1203
|
+
return {
|
|
1204
|
+
order,
|
|
1205
|
+
observedUpdatedAt
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
/** Normalize persisted state without trusting any browser-local JSON shape. */
|
|
1209
|
+
function normalizeWorktreeSessionOrderState(value) {
|
|
1210
|
+
if (!isRecord(value) || !isRecord(value.accounts)) return emptyState();
|
|
1211
|
+
const accounts = {};
|
|
1212
|
+
for (const [accountKey, account] of Object.entries(value.accounts)) {
|
|
1213
|
+
if (accountKey.length === 0) continue;
|
|
1214
|
+
const normalized = normalizeAccount(account);
|
|
1215
|
+
if (normalized !== void 0) accounts[accountKey] = normalized;
|
|
1216
|
+
}
|
|
1217
|
+
return { accounts };
|
|
1218
|
+
}
|
|
1219
|
+
function validIds(ids) {
|
|
1220
|
+
return normalizeIds([...ids]);
|
|
1221
|
+
}
|
|
1222
|
+
function sameRecord(left, right) {
|
|
1223
|
+
if (left === void 0) return false;
|
|
1224
|
+
const leftKeys = Object.keys(left);
|
|
1225
|
+
const rightKeys = Object.keys(right);
|
|
1226
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
1227
|
+
return rightKeys.every((key) => left[key] === right[key]);
|
|
1228
|
+
}
|
|
1229
|
+
function sameAccount(left, right) {
|
|
1230
|
+
return left !== void 0 && left.order.length === right.order.length && left.order.every((id, index) => id === right.order[index]) && sameRecord(left.observedUpdatedAt, right.observedUpdatedAt);
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Native-style activity order transition. The first observation records timestamps
|
|
1234
|
+
* without turning an existing list into a recency sort.
|
|
1235
|
+
*/
|
|
1236
|
+
function nextSessionOrderAccount(input) {
|
|
1237
|
+
const baseIds = validIds(input.baseIds);
|
|
1238
|
+
const previous = input.previous;
|
|
1239
|
+
if (previous === void 0) {
|
|
1240
|
+
const observedUpdatedAt = {};
|
|
1241
|
+
for (const id of baseIds) {
|
|
1242
|
+
const timestamp = input.updatedAtById[id];
|
|
1243
|
+
if (isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
|
|
1244
|
+
}
|
|
1245
|
+
return {
|
|
1246
|
+
order: baseIds,
|
|
1247
|
+
observedUpdatedAt
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
const available = new Set(baseIds);
|
|
1251
|
+
const order = [];
|
|
1252
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1253
|
+
for (const id of previous.order) if (available.has(id) && !seen.has(id)) {
|
|
1254
|
+
seen.add(id);
|
|
1255
|
+
order.push(id);
|
|
1256
|
+
}
|
|
1257
|
+
for (const id of baseIds) if (!seen.has(id)) {
|
|
1258
|
+
seen.add(id);
|
|
1259
|
+
order.push(id);
|
|
1260
|
+
}
|
|
1261
|
+
const observedUpdatedAt = {};
|
|
1262
|
+
const previousIds = new Set(previous.order);
|
|
1263
|
+
const newlyObserved = [];
|
|
1264
|
+
const promoted = [];
|
|
1265
|
+
for (const [index, id] of order.entries()) {
|
|
1266
|
+
if (!previousIds.has(id)) newlyObserved.push(id);
|
|
1267
|
+
const previousTimestamp = previous.observedUpdatedAt[id];
|
|
1268
|
+
const timestamp = input.updatedAtById[id];
|
|
1269
|
+
if (isValidTimestamp(previousTimestamp)) observedUpdatedAt[id] = previousTimestamp;
|
|
1270
|
+
if (isValidTimestamp(timestamp)) {
|
|
1271
|
+
if (!isValidTimestamp(previousTimestamp) || timestamp > previousTimestamp) {
|
|
1272
|
+
if (isValidTimestamp(previousTimestamp)) promoted.push({
|
|
1273
|
+
id,
|
|
1274
|
+
timestamp,
|
|
1275
|
+
index
|
|
1276
|
+
});
|
|
1277
|
+
observedUpdatedAt[id] = Math.max(observedUpdatedAt[id] ?? timestamp, timestamp);
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
promoted.sort((left, right) => right.timestamp - left.timestamp || left.index - right.index);
|
|
1282
|
+
const promotedIds = /* @__PURE__ */ new Set([...newlyObserved, ...promoted.map(({ id }) => id)]);
|
|
1283
|
+
return {
|
|
1284
|
+
order: [
|
|
1285
|
+
...newlyObserved,
|
|
1286
|
+
...promoted.map(({ id }) => id),
|
|
1287
|
+
...order.filter((id) => !promotedIds.has(id))
|
|
1288
|
+
],
|
|
1289
|
+
observedUpdatedAt
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
/** Apply a successful manual drag without dropping IDs hidden by search. */
|
|
1293
|
+
function reorderSessionIds(order, sessionId, overSessionId, half) {
|
|
1294
|
+
const next = order.filter((id) => id !== sessionId);
|
|
1295
|
+
const targetIndex = next.indexOf(overSessionId);
|
|
1296
|
+
if (targetIndex === -1) return [...order];
|
|
1297
|
+
next.splice(half === "before" ? targetIndex : targetIndex + 1, 0, sessionId);
|
|
1298
|
+
return next;
|
|
1299
|
+
}
|
|
1300
|
+
function cloneAccount(account) {
|
|
1301
|
+
return {
|
|
1302
|
+
order: [...account.order],
|
|
1303
|
+
observedUpdatedAt: { ...account.observedUpdatedAt }
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
/** Create one apply-scoped, browser-local Session ordering store. */
|
|
1307
|
+
function createWorktreeSessionOrderStore(snapshotStoreFactory) {
|
|
1308
|
+
let store;
|
|
1309
|
+
try {
|
|
1310
|
+
store = snapshotStoreFactory(emptyState(), { persist: { name: WORKTREE_SESSION_ORDER_STORAGE_KEY } });
|
|
1311
|
+
} catch {
|
|
1312
|
+
store = snapshotStoreFactory(emptyState());
|
|
1313
|
+
}
|
|
1314
|
+
store.set(normalizeWorktreeSessionOrderState(store.getSnapshot()));
|
|
1315
|
+
let disposed = false;
|
|
1316
|
+
return Object.assign(store, {
|
|
1317
|
+
actions: {
|
|
1318
|
+
reconcile: (accountKey, baseIds, updatedAtById) => {
|
|
1319
|
+
if (disposed || accountKey.length === 0) return;
|
|
1320
|
+
store.update((draft) => {
|
|
1321
|
+
const next = nextSessionOrderAccount({
|
|
1322
|
+
baseIds,
|
|
1323
|
+
updatedAtById,
|
|
1324
|
+
previous: draft.accounts[accountKey]
|
|
1325
|
+
});
|
|
1326
|
+
if (sameAccount(draft.accounts[accountKey], next)) return;
|
|
1327
|
+
draft.accounts[accountKey] = cloneAccount(next);
|
|
1328
|
+
});
|
|
1329
|
+
},
|
|
1330
|
+
setOrder: (accountKey, order) => {
|
|
1331
|
+
if (disposed || accountKey.length === 0) return;
|
|
1332
|
+
store.update((draft) => {
|
|
1333
|
+
const current = draft.accounts[accountKey] ?? {
|
|
1334
|
+
order: [],
|
|
1335
|
+
observedUpdatedAt: {}
|
|
1336
|
+
};
|
|
1337
|
+
const next = {
|
|
1338
|
+
order: validIds(order),
|
|
1339
|
+
observedUpdatedAt: { ...current.observedUpdatedAt }
|
|
1340
|
+
};
|
|
1341
|
+
if (sameAccount(current, next)) return;
|
|
1342
|
+
draft.accounts[accountKey] = next;
|
|
1343
|
+
});
|
|
1344
|
+
},
|
|
1345
|
+
retain: (accountKeys) => {
|
|
1346
|
+
if (disposed) return;
|
|
1347
|
+
store.update((draft) => {
|
|
1348
|
+
const allowed = new Set(accountKeys);
|
|
1349
|
+
for (const accountKey of Object.keys(draft.accounts)) if (!allowed.has(accountKey)) delete draft.accounts[accountKey];
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
},
|
|
1353
|
+
dispose: () => {
|
|
1354
|
+
disposed = true;
|
|
1355
|
+
}
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
//#endregion
|
|
946
1359
|
//#region lib/client/worktree-view-errors.js
|
|
947
1360
|
/** A DSH Session exists even when the external Worktree binding needs repair. */
|
|
948
1361
|
var WorktreeSessionBindingError = class extends Error {
|
|
@@ -964,6 +1377,25 @@ window.__ModuleLoader__.load({
|
|
|
964
1377
|
this.cause = cause;
|
|
965
1378
|
}
|
|
966
1379
|
};
|
|
1380
|
+
/** A Session is retained after permission confirmation or permission setup needs retry. */
|
|
1381
|
+
var WorktreeSessionPermissionError = class extends Error {
|
|
1382
|
+
code;
|
|
1383
|
+
retryable = true;
|
|
1384
|
+
details;
|
|
1385
|
+
sessionId;
|
|
1386
|
+
createdSession;
|
|
1387
|
+
cause;
|
|
1388
|
+
constructor(sessionId, createdSession, cause) {
|
|
1389
|
+
const reason = cause instanceof Error ? cause.message : cause === void 0 ? "" : String(cause);
|
|
1390
|
+
super(reason);
|
|
1391
|
+
this.name = "WorktreeSessionPermissionError";
|
|
1392
|
+
this.code = cause === void 0 ? "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED" : "WORKTREE_PERMISSION_FAILED";
|
|
1393
|
+
this.details = { sessionId };
|
|
1394
|
+
this.sessionId = sessionId;
|
|
1395
|
+
this.createdSession = createdSession;
|
|
1396
|
+
this.cause = cause;
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
967
1399
|
function recordDetails(value) {
|
|
968
1400
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
969
1401
|
const details = value.details;
|
|
@@ -974,7 +1406,7 @@ window.__ModuleLoader__.load({
|
|
|
974
1406
|
function toWorktreeViewError(error) {
|
|
975
1407
|
if (typeof error === "object" && error !== null) {
|
|
976
1408
|
const candidate = error;
|
|
977
|
-
const details = error instanceof WorktreeSessionBindingError ? {
|
|
1409
|
+
const details = error instanceof WorktreeSessionBindingError || error instanceof WorktreeSessionPermissionError ? {
|
|
978
1410
|
...recordDetails(error) ?? {},
|
|
979
1411
|
sessionId: error.sessionId
|
|
980
1412
|
} : recordDetails(error);
|
|
@@ -1016,6 +1448,21 @@ window.__ModuleLoader__.load({
|
|
|
1016
1448
|
}
|
|
1017
1449
|
throw new Error("Unable to generate an available default Worktree name.");
|
|
1018
1450
|
}
|
|
1451
|
+
/** Generate the next available numeric sibling name for a selected Worktree. */
|
|
1452
|
+
function createNumberedWorktreeName(baseName, existingNames) {
|
|
1453
|
+
const normalizedBaseName = baseName.trim();
|
|
1454
|
+
const usedNames = new Set([...existingNames].map((name) => name.trim()));
|
|
1455
|
+
const numberedBase = normalizedBaseName.match(/^(.*)-(\d+)$/);
|
|
1456
|
+
const prefix = numberedBase?.[1] || normalizedBaseName || "worktree";
|
|
1457
|
+
const parsedNumber = numberedBase === null ? 1 : Number(numberedBase[2]);
|
|
1458
|
+
let number = Number.isSafeInteger(parsedNumber) ? parsedNumber + 1 : 2;
|
|
1459
|
+
for (let attempt = 0; attempt < 1e4; attempt += 1) {
|
|
1460
|
+
const candidate = `${prefix}-${number}`;
|
|
1461
|
+
if (!usedNames.has(candidate)) return candidate;
|
|
1462
|
+
number += 1;
|
|
1463
|
+
}
|
|
1464
|
+
throw new Error("Unable to generate an available numbered Worktree name.");
|
|
1465
|
+
}
|
|
1019
1466
|
/** Resolve a row-half drop target to native-style optional before-anchor semantics. */
|
|
1020
1467
|
function resolveWorktreeMove(worktreeIds, sourceWorktreeId, targetWorktreeId, half) {
|
|
1021
1468
|
const sourceIndex = worktreeIds.indexOf(sourceWorktreeId);
|
|
@@ -1028,11 +1475,19 @@ window.__ModuleLoader__.load({
|
|
|
1028
1475
|
return beforeWorktreeId === void 0 ? {} : { beforeWorktreeId };
|
|
1029
1476
|
}
|
|
1030
1477
|
/** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
|
|
1031
|
-
async function executeWorktreeAction(manager, action) {
|
|
1478
|
+
async function executeWorktreeAction(manager, action, permission, onPermissionResult) {
|
|
1032
1479
|
if (action.type === "createWorktree") return manager.createWorktree(action.input);
|
|
1033
1480
|
if (action.type === "importWorktree") return manager.importWorktree(action.input);
|
|
1034
1481
|
if (action.type === "removeWorktree") {
|
|
1035
1482
|
await manager.removeWorktree(action.input);
|
|
1483
|
+
const result = await permission?.normalizeDetachedWorktreePermissions({
|
|
1484
|
+
workspaceId: action.input.workspaceId,
|
|
1485
|
+
worktreeId: action.input.worktreeId
|
|
1486
|
+
});
|
|
1487
|
+
if (result !== void 0) onPermissionResult?.({
|
|
1488
|
+
workspaceId: action.input.workspaceId,
|
|
1489
|
+
worktreeId: action.input.worktreeId
|
|
1490
|
+
}, result);
|
|
1036
1491
|
return;
|
|
1037
1492
|
}
|
|
1038
1493
|
}
|
|
@@ -1051,7 +1506,7 @@ window.__ModuleLoader__.load({
|
|
|
1051
1506
|
} catch (error) {
|
|
1052
1507
|
throw new WorktreeSessionBindingError(sessionId, error);
|
|
1053
1508
|
}
|
|
1054
|
-
input.beforeOpen?.(sessionId);
|
|
1509
|
+
await input.beforeOpen?.(sessionId);
|
|
1055
1510
|
input.openSession(sessionId);
|
|
1056
1511
|
return sessionId;
|
|
1057
1512
|
}
|
|
@@ -1210,8 +1665,56 @@ window.__ModuleLoader__.load({
|
|
|
1210
1665
|
this.details = details;
|
|
1211
1666
|
}
|
|
1212
1667
|
};
|
|
1668
|
+
/**
|
|
1669
|
+
* Keep the confirmation and second permission call in one place for new,
|
|
1670
|
+
* reused, and retried Sessions. The Host still validates the relation.
|
|
1671
|
+
*/
|
|
1672
|
+
async function ensureWorktreeSessionPermission(input) {
|
|
1673
|
+
if (input.permission === void 0) return;
|
|
1674
|
+
const request = {
|
|
1675
|
+
workspaceId: input.workspaceId,
|
|
1676
|
+
worktreeId: input.worktreeId,
|
|
1677
|
+
sessionId: input.sessionId,
|
|
1678
|
+
binding: "active"
|
|
1679
|
+
};
|
|
1680
|
+
let result;
|
|
1681
|
+
try {
|
|
1682
|
+
result = await input.permission.ensureWorktreePermission(request);
|
|
1683
|
+
} catch (error) {
|
|
1684
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1685
|
+
}
|
|
1686
|
+
if (result.status === "confirmation-required") {
|
|
1687
|
+
let confirmed;
|
|
1688
|
+
try {
|
|
1689
|
+
confirmed = input.confirmFullAccess === void 0 ? false : await input.confirmFullAccess({
|
|
1690
|
+
workspaceId: input.workspaceId,
|
|
1691
|
+
worktreeId: input.worktreeId,
|
|
1692
|
+
sessionId: input.sessionId,
|
|
1693
|
+
cwd: input.cwd
|
|
1694
|
+
});
|
|
1695
|
+
} catch (error) {
|
|
1696
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1697
|
+
}
|
|
1698
|
+
if (!confirmed) throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
|
|
1699
|
+
try {
|
|
1700
|
+
result = await input.permission.ensureWorktreePermission({
|
|
1701
|
+
...request,
|
|
1702
|
+
confirmed: true
|
|
1703
|
+
});
|
|
1704
|
+
} catch (error) {
|
|
1705
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
if (result.status === "confirmation-required") throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
|
|
1709
|
+
input.onPermissionResult?.({
|
|
1710
|
+
workspaceId: input.workspaceId,
|
|
1711
|
+
worktreeId: input.worktreeId,
|
|
1712
|
+
sessionId: input.sessionId,
|
|
1713
|
+
cwd: input.cwd
|
|
1714
|
+
}, result);
|
|
1715
|
+
}
|
|
1213
1716
|
function resolveWorktreeSessionAction(input) {
|
|
1214
|
-
if (input.target.status !== "active" || input.target.health === "repair") return {
|
|
1717
|
+
if (input.target.status !== "active" || input.target.health === "repair" || input.target.health === "recovery-needed") return {
|
|
1215
1718
|
kind: "reject",
|
|
1216
1719
|
reason: "worktree-not-available"
|
|
1217
1720
|
};
|
|
@@ -1273,6 +1776,16 @@ window.__ModuleLoader__.load({
|
|
|
1273
1776
|
} catch (error) {
|
|
1274
1777
|
throw new WorktreeSessionBindingError(input.pending.sessionId, error);
|
|
1275
1778
|
}
|
|
1779
|
+
await ensureWorktreeSessionPermission({
|
|
1780
|
+
permission: input.permission,
|
|
1781
|
+
confirmFullAccess: input.confirmFullAccess,
|
|
1782
|
+
onPermissionResult: input.onPermissionResult,
|
|
1783
|
+
sessionId: input.pending.sessionId,
|
|
1784
|
+
workspaceId: input.pending.workspaceId,
|
|
1785
|
+
worktreeId: input.pending.worktreeId,
|
|
1786
|
+
cwd: input.pending.cwd,
|
|
1787
|
+
createdSession: true
|
|
1788
|
+
});
|
|
1276
1789
|
input.ensureSessionWorkspace(input.pending.workspaceId, input.pending.sessionId);
|
|
1277
1790
|
input.openSession(input.pending.sessionId);
|
|
1278
1791
|
return input.pending.sessionId;
|
|
@@ -1296,6 +1809,16 @@ window.__ModuleLoader__.load({
|
|
|
1296
1809
|
bindings
|
|
1297
1810
|
});
|
|
1298
1811
|
if (action.kind === "open-bound") {
|
|
1812
|
+
await ensureWorktreeSessionPermission({
|
|
1813
|
+
permission: options.permission,
|
|
1814
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1815
|
+
onPermissionResult: options.onPermissionResult,
|
|
1816
|
+
sessionId: action.sessionId,
|
|
1817
|
+
workspaceId: input.workspaceId,
|
|
1818
|
+
worktreeId: input.worktreeId,
|
|
1819
|
+
cwd: input.cwd,
|
|
1820
|
+
createdSession: false
|
|
1821
|
+
});
|
|
1299
1822
|
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1300
1823
|
if (!disposed) options.openSession(action.sessionId);
|
|
1301
1824
|
return action.sessionId;
|
|
@@ -1310,6 +1833,16 @@ window.__ModuleLoader__.load({
|
|
|
1310
1833
|
} catch (error) {
|
|
1311
1834
|
throw new WorktreeSessionBindingError(action.sessionId, error);
|
|
1312
1835
|
}
|
|
1836
|
+
await ensureWorktreeSessionPermission({
|
|
1837
|
+
permission: options.permission,
|
|
1838
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1839
|
+
onPermissionResult: options.onPermissionResult,
|
|
1840
|
+
sessionId: action.sessionId,
|
|
1841
|
+
workspaceId: input.workspaceId,
|
|
1842
|
+
worktreeId: input.worktreeId,
|
|
1843
|
+
cwd: input.cwd,
|
|
1844
|
+
createdSession: false
|
|
1845
|
+
});
|
|
1313
1846
|
if (!disposed) {
|
|
1314
1847
|
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1315
1848
|
if (!disposed) options.openSession(action.sessionId);
|
|
@@ -1322,9 +1855,18 @@ window.__ModuleLoader__.load({
|
|
|
1322
1855
|
...input,
|
|
1323
1856
|
createSession: options.createSession,
|
|
1324
1857
|
manager: options.manager,
|
|
1325
|
-
beforeOpen: (sessionId) => {
|
|
1858
|
+
beforeOpen: async (sessionId) => {
|
|
1326
1859
|
if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
|
|
1327
|
-
|
|
1860
|
+
await ensureWorktreeSessionPermission({
|
|
1861
|
+
permission: options.permission,
|
|
1862
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1863
|
+
onPermissionResult: options.onPermissionResult,
|
|
1864
|
+
sessionId,
|
|
1865
|
+
workspaceId: input.workspaceId,
|
|
1866
|
+
worktreeId: input.worktreeId,
|
|
1867
|
+
cwd: input.cwd,
|
|
1868
|
+
createdSession: true
|
|
1869
|
+
});
|
|
1328
1870
|
},
|
|
1329
1871
|
openSession: (sessionId) => {
|
|
1330
1872
|
if (!disposed) options.openSession(sessionId);
|
|
@@ -1734,6 +2276,13 @@ window.__ModuleLoader__.load({
|
|
|
1734
2276
|
"session-group:" + location.groupKey
|
|
1735
2277
|
];
|
|
1736
2278
|
}
|
|
2279
|
+
function shouldRevealCurrentSessionGroup(sessionIds, currentSessionId) {
|
|
2280
|
+
if (currentSessionId === void 0 || sessionIds.length <= 5) return false;
|
|
2281
|
+
return sessionIds.indexOf(currentSessionId) >= 5;
|
|
2282
|
+
}
|
|
2283
|
+
function isSessionGroupAutoExpanded(sessionIds, currentSessionId, currentSessionRevealActive) {
|
|
2284
|
+
return currentSessionRevealActive && shouldRevealCurrentSessionGroup(sessionIds, currentSessionId);
|
|
2285
|
+
}
|
|
1737
2286
|
//#endregion
|
|
1738
2287
|
//#region lib/client/worktree-session-position.js
|
|
1739
2288
|
function scrollCurrentSessionIntoView(root, sessionId) {
|
|
@@ -1749,8 +2298,65 @@ window.__ModuleLoader__.load({
|
|
|
1749
2298
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
1750
2299
|
return event.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
1751
2300
|
}
|
|
2301
|
+
function sessionStatusLabel(t, status) {
|
|
2302
|
+
switch (status.labelKey) {
|
|
2303
|
+
case "running": return t("session.status.running");
|
|
2304
|
+
case "subagentsRunning": return t(status.runningSubagentCount === 1 ? "session.status.subagentsRunning.one" : "session.status.subagentsRunning.other", { n: status.runningSubagentCount });
|
|
2305
|
+
case "idle": return t("session.status.idle");
|
|
2306
|
+
case "waitingApproval": return t("session.status.waitingApproval");
|
|
2307
|
+
case "planReview": return t("session.status.planReview");
|
|
2308
|
+
case "waitingAnswer": return t("session.status.waitingAnswer");
|
|
2309
|
+
case "completed": return t("session.status.completed");
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
function sessionTimeLabel(t, value) {
|
|
2313
|
+
switch (value.unit) {
|
|
2314
|
+
case "now": return t("session.time.now");
|
|
2315
|
+
case "minutes": return t("session.time.minutes", { n: value.n });
|
|
2316
|
+
case "hours": return t("session.time.hours", { n: value.n });
|
|
2317
|
+
case "days": return t("session.time.days", { n: value.n });
|
|
2318
|
+
case "months": return t("session.time.months", { n: value.n });
|
|
2319
|
+
case "years": return t("session.time.years", { n: value.n });
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
/** Native Workspace hover-card time copy, including the trailing "ago" marker. */
|
|
2323
|
+
function sessionHoverTimeLabel(t, value) {
|
|
2324
|
+
const label = sessionTimeLabel(t, value);
|
|
2325
|
+
return value.unit === "now" ? label : t("session.time.ago", { t: label });
|
|
2326
|
+
}
|
|
2327
|
+
/** Native Workspace hover-card status list, including a secondary subagent status when relevant. */
|
|
2328
|
+
function sessionHoverStatuses(presentation) {
|
|
2329
|
+
if (presentation.runningSubagentCount === 0 || presentation.status.labelKey === "subagentsRunning") return [presentation.status];
|
|
2330
|
+
return [presentation.status, {
|
|
2331
|
+
state: "ongoing",
|
|
2332
|
+
labelKey: "subagentsRunning",
|
|
2333
|
+
runningSubagentCount: presentation.runningSubagentCount
|
|
2334
|
+
}];
|
|
2335
|
+
}
|
|
2336
|
+
/** Native Workspace Session hover-card details, adapted to the Worktree row projection. */
|
|
2337
|
+
function WorktreeSessionHoverContent({ label, blank, presentation, t }) {
|
|
2338
|
+
const statuses = presentation === void 0 ? [] : sessionHoverStatuses(presentation);
|
|
2339
|
+
const timeValue = !blank && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
|
|
2340
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2341
|
+
className: worktree_css_default.sessionHoverContent,
|
|
2342
|
+
children: [
|
|
2343
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
2344
|
+
className: worktree_css_default.sessionHoverTitle,
|
|
2345
|
+
children: label
|
|
2346
|
+
}),
|
|
2347
|
+
!blank && timeValue !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
2348
|
+
className: worktree_css_default.sessionHoverTime,
|
|
2349
|
+
children: sessionHoverTimeLabel(t, timeValue)
|
|
2350
|
+
}),
|
|
2351
|
+
statuses.map((status) => (0, react_jsx_runtime.jsxs)("div", {
|
|
2352
|
+
className: worktree_css_default.sessionHoverStatus,
|
|
2353
|
+
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) })]
|
|
2354
|
+
}, `${status.labelKey}-${status.runningSubagentCount}`))
|
|
2355
|
+
]
|
|
2356
|
+
});
|
|
2357
|
+
}
|
|
1752
2358
|
/** 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 }) {
|
|
2359
|
+
function WorktreeWorkspaceRow({ t, workspace, expanded, hasOngoingSession, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
|
|
1754
2360
|
const workspaceMenuItems = [{
|
|
1755
2361
|
id: "rename",
|
|
1756
2362
|
label: t("workspace.rename"),
|
|
@@ -1767,6 +2373,7 @@ window.__ModuleLoader__.load({
|
|
|
1767
2373
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
1768
2374
|
className: `${worktree_css_default.workspaceRow} ${markerClass}`,
|
|
1769
2375
|
"data-workspace-drag": drag.active ? "active" : void 0,
|
|
2376
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
1770
2377
|
"data-menu-open": menuOpen || void 0,
|
|
1771
2378
|
draggable: true,
|
|
1772
2379
|
onClick: () => {
|
|
@@ -1812,50 +2419,61 @@ window.__ModuleLoader__.load({
|
|
|
1812
2419
|
}),
|
|
1813
2420
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
1814
2421
|
className: `${worktree_css_default.treeActionSlot} ${worktree_css_default.workspaceActions}`,
|
|
1815
|
-
children: [
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
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);
|
|
2422
|
+
children: [
|
|
2423
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2424
|
+
className: worktree_css_default.groupActivity,
|
|
2425
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
2426
|
+
role: hasOngoingSession && !expanded ? "img" : void 0,
|
|
2427
|
+
"aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2428
|
+
title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2429
|
+
children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
|
|
2430
|
+
}),
|
|
2431
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2432
|
+
className: worktree_css_default.menuAction,
|
|
2433
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2434
|
+
open: menuOpen,
|
|
2435
|
+
onClose: () => {
|
|
2436
|
+
onMenuOpenChange(false);
|
|
1838
2437
|
},
|
|
1839
|
-
|
|
2438
|
+
items: workspaceMenuItems,
|
|
2439
|
+
onSelect: (id) => {
|
|
2440
|
+
onMenuOpenChange(false);
|
|
2441
|
+
if (id === "rename") onRename();
|
|
2442
|
+
if (id === "delete") onDelete();
|
|
2443
|
+
},
|
|
2444
|
+
portal: true,
|
|
2445
|
+
closeOnPointerLeave: true,
|
|
2446
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2447
|
+
type: "button",
|
|
2448
|
+
className: worktree_css_default.iconButton,
|
|
2449
|
+
"data-workspace-menu": true,
|
|
2450
|
+
"aria-label": t("workspace.options", { name: workspace.title }),
|
|
2451
|
+
onClick: (event) => {
|
|
2452
|
+
event.stopPropagation();
|
|
2453
|
+
onMenuOpenChange(!menuOpen);
|
|
2454
|
+
},
|
|
2455
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2456
|
+
})
|
|
1840
2457
|
})
|
|
2458
|
+
}),
|
|
2459
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
2460
|
+
type: "button",
|
|
2461
|
+
className: worktree_css_default.iconButton,
|
|
2462
|
+
"data-add-worktree": true,
|
|
2463
|
+
"aria-label": t("workspace.addWorktree", { name: workspace.title }),
|
|
2464
|
+
onClick: (event) => {
|
|
2465
|
+
event.stopPropagation();
|
|
2466
|
+
onCreateWorktree();
|
|
2467
|
+
},
|
|
2468
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1841
2469
|
})
|
|
1842
|
-
|
|
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
|
-
})]
|
|
2470
|
+
]
|
|
1853
2471
|
})
|
|
1854
2472
|
]
|
|
1855
2473
|
});
|
|
1856
2474
|
}
|
|
1857
2475
|
/** 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 }) {
|
|
2476
|
+
function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, hasOngoingSession, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
|
|
1859
2477
|
const main = kind === "main";
|
|
1860
2478
|
const markerClass = drag?.marker === "before" ? worktree_css_default.dropBefore : drag?.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
1861
2479
|
const dragProps = drag === void 0 ? {} : {
|
|
@@ -1882,6 +2500,7 @@ window.__ModuleLoader__.load({
|
|
|
1882
2500
|
className: `${worktree_css_default.worktreeRow} ${markerClass}`,
|
|
1883
2501
|
"data-main-group": main ? "true" : void 0,
|
|
1884
2502
|
"data-main-expanded": main ? String(expanded) : void 0,
|
|
2503
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
1885
2504
|
"data-menu-open": menu?.open ? "true" : void 0,
|
|
1886
2505
|
"data-worktree-drag": drag?.active ? "active" : void 0,
|
|
1887
2506
|
...dragProps,
|
|
@@ -1916,50 +2535,77 @@ window.__ModuleLoader__.load({
|
|
|
1916
2535
|
}),
|
|
1917
2536
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
1918
2537
|
className: worktree_css_default.treeActionSlot,
|
|
1919
|
-
children: [
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
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);
|
|
2538
|
+
children: [
|
|
2539
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2540
|
+
className: worktree_css_default.groupActivity,
|
|
2541
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
2542
|
+
role: hasOngoingSession && !expanded ? "img" : void 0,
|
|
2543
|
+
"aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2544
|
+
title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2545
|
+
children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
|
|
2546
|
+
}),
|
|
2547
|
+
menu !== void 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
2548
|
+
className: worktree_css_default.menuAction,
|
|
2549
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2550
|
+
open: menu.open,
|
|
2551
|
+
onClose: () => {
|
|
2552
|
+
menu.onOpenChange(false);
|
|
1947
2553
|
},
|
|
1948
|
-
|
|
2554
|
+
items: [
|
|
2555
|
+
...menu.showCreate ? [{
|
|
2556
|
+
id: "create",
|
|
2557
|
+
label: t("worktree.createNew"),
|
|
2558
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {}),
|
|
2559
|
+
disabled: menu.disabled || menu.onCreateWorktree === void 0
|
|
2560
|
+
}] : [],
|
|
2561
|
+
{
|
|
2562
|
+
id: "copy-path",
|
|
2563
|
+
label: t("worktree.copyPath"),
|
|
2564
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}),
|
|
2565
|
+
disabled: menu.disabled
|
|
2566
|
+
},
|
|
2567
|
+
...menu.showRemove ? [{
|
|
2568
|
+
id: "remove",
|
|
2569
|
+
label: t("worktree.remove"),
|
|
2570
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}),
|
|
2571
|
+
danger: true,
|
|
2572
|
+
disabled: menu.disabled || menu.onRemove === void 0
|
|
2573
|
+
}] : []
|
|
2574
|
+
],
|
|
2575
|
+
onSelect: (id) => {
|
|
2576
|
+
menu.onOpenChange(false);
|
|
2577
|
+
if (id === "create" && menu.showCreate) menu.onCreateWorktree?.();
|
|
2578
|
+
if (id === "copy-path") (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(menu.copyPath);
|
|
2579
|
+
if (id === "remove" && menu.showRemove) menu.onRemove?.();
|
|
2580
|
+
},
|
|
2581
|
+
portal: true,
|
|
2582
|
+
closeOnPointerLeave: true,
|
|
2583
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2584
|
+
type: "button",
|
|
2585
|
+
className: worktree_css_default.iconButton,
|
|
2586
|
+
"data-worktree-menu": true,
|
|
2587
|
+
"aria-label": t("worktree.options", { name: menu.label }),
|
|
2588
|
+
onClick: (event) => {
|
|
2589
|
+
event.stopPropagation();
|
|
2590
|
+
menu.onOpenChange(!menu.open);
|
|
2591
|
+
},
|
|
2592
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2593
|
+
})
|
|
1949
2594
|
})
|
|
2595
|
+
}),
|
|
2596
|
+
onCreateSession !== void 0 && (0, react_jsx_runtime.jsx)("button", {
|
|
2597
|
+
type: "button",
|
|
2598
|
+
className: worktree_css_default.iconButton,
|
|
2599
|
+
"data-add-main-session": main ? "true" : void 0,
|
|
2600
|
+
"data-add-session": main ? void 0 : "true",
|
|
2601
|
+
"aria-label": t("worktree.addSession", { name: workspaceTitle }),
|
|
2602
|
+
onClick: (event) => {
|
|
2603
|
+
event.stopPropagation();
|
|
2604
|
+
onCreateSession();
|
|
2605
|
+
},
|
|
2606
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1950
2607
|
})
|
|
1951
|
-
|
|
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
|
-
})]
|
|
2608
|
+
]
|
|
1963
2609
|
})
|
|
1964
2610
|
]
|
|
1965
2611
|
});
|
|
@@ -1975,7 +2621,7 @@ window.__ModuleLoader__.load({
|
|
|
1975
2621
|
});
|
|
1976
2622
|
}
|
|
1977
2623
|
/** 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 }) {
|
|
2624
|
+
function WorktreeSessionRow({ t, sessionId, blank, current, label, drag, actionPending, onOpen, onRename, onFork, onArchive, presentation }) {
|
|
1979
2625
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
1980
2626
|
const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
1981
2627
|
const sessionMenuItems = [
|
|
@@ -1996,75 +2642,115 @@ window.__ModuleLoader__.load({
|
|
|
1996
2642
|
label: t("session.archive"),
|
|
1997
2643
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }),
|
|
1998
2644
|
disabled: onArchive === void 0 || actionPending
|
|
2645
|
+
},
|
|
2646
|
+
{
|
|
2647
|
+
id: "copy-session-id",
|
|
2648
|
+
label: t("session.copyId"),
|
|
2649
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {})
|
|
1999
2650
|
}
|
|
2000
2651
|
];
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
drag.
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
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, {})
|
|
2652
|
+
const statusLabel = presentation === void 0 ? void 0 : sessionStatusLabel(t, presentation.status);
|
|
2653
|
+
const showTrailingStatus = !blank && presentation !== void 0 && (presentation.status.state !== "done" || presentation.completed);
|
|
2654
|
+
const timeValue = !blank && !showTrailingStatus && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
|
|
2655
|
+
const timeLabel = timeValue === void 0 ? void 0 : sessionTimeLabel(t, timeValue);
|
|
2656
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
2657
|
+
anchor: (0, react_jsx_runtime.jsxs)("div", {
|
|
2658
|
+
className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
|
|
2659
|
+
"data-session-id": sessionId,
|
|
2660
|
+
"data-session-blank": blank ? "true" : void 0,
|
|
2661
|
+
"data-session-current": current ? "true" : void 0,
|
|
2662
|
+
"data-session-drag": drag.active ? "active" : void 0,
|
|
2663
|
+
"data-menu-open": menuOpen || void 0,
|
|
2664
|
+
role: "treeitem",
|
|
2665
|
+
"aria-current": current ? "true" : void 0,
|
|
2666
|
+
draggable: true,
|
|
2667
|
+
onDragStart: (event) => {
|
|
2668
|
+
event.dataTransfer.effectAllowed = "move";
|
|
2669
|
+
event.dataTransfer.setData("text/plain", sessionId);
|
|
2670
|
+
drag.start();
|
|
2671
|
+
},
|
|
2672
|
+
onDragEnd: drag.end,
|
|
2673
|
+
onDragOver: (event) => {
|
|
2674
|
+
if (!drag.active) return;
|
|
2675
|
+
event.preventDefault();
|
|
2676
|
+
event.dataTransfer.dropEffect = "move";
|
|
2677
|
+
drag.hover(rowHalf(event));
|
|
2678
|
+
},
|
|
2679
|
+
onDrop: (event) => {
|
|
2680
|
+
if (!drag.active) return;
|
|
2681
|
+
event.preventDefault();
|
|
2682
|
+
drag.drop(rowHalf(event));
|
|
2683
|
+
},
|
|
2684
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
2685
|
+
type: "button",
|
|
2686
|
+
className: worktree_css_default.treeSessionContent,
|
|
2687
|
+
onClick: onOpen,
|
|
2688
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
2689
|
+
className: worktree_css_default.sessionLabel,
|
|
2690
|
+
children: label
|
|
2062
2691
|
})
|
|
2063
|
-
})
|
|
2064
|
-
|
|
2692
|
+
}), !blank && (0, react_jsx_runtime.jsxs)("span", {
|
|
2693
|
+
className: worktree_css_default.sessionTrailing,
|
|
2694
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
2695
|
+
className: worktree_css_default.sessionMeta,
|
|
2696
|
+
children: showTrailingStatus && presentation !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
2697
|
+
className: worktree_css_default.sessionStatus,
|
|
2698
|
+
"data-session-status": statusLabel,
|
|
2699
|
+
role: "img",
|
|
2700
|
+
"aria-label": statusLabel,
|
|
2701
|
+
title: statusLabel,
|
|
2702
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: presentation.status.state })
|
|
2703
|
+
}) : timeLabel !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
2704
|
+
className: worktree_css_default.sessionTime,
|
|
2705
|
+
"data-session-time": true,
|
|
2706
|
+
children: timeLabel
|
|
2707
|
+
}) : null
|
|
2708
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
2709
|
+
className: worktree_css_default.rowActions,
|
|
2710
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2711
|
+
open: menuOpen,
|
|
2712
|
+
onClose: () => {
|
|
2713
|
+
setMenuOpen(false);
|
|
2714
|
+
},
|
|
2715
|
+
items: sessionMenuItems,
|
|
2716
|
+
onSelect: (id) => {
|
|
2717
|
+
setMenuOpen(false);
|
|
2718
|
+
if (id === "rename") onRename?.(sessionId, label);
|
|
2719
|
+
if (id === "fork") onFork?.(sessionId);
|
|
2720
|
+
if (id === "archive") onArchive?.(sessionId);
|
|
2721
|
+
if (id === "copy-session-id") (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(sessionId);
|
|
2722
|
+
},
|
|
2723
|
+
portal: true,
|
|
2724
|
+
closeOnPointerLeave: true,
|
|
2725
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2726
|
+
type: "button",
|
|
2727
|
+
className: worktree_css_default.iconButton,
|
|
2728
|
+
"data-session-menu": true,
|
|
2729
|
+
"aria-label": t("session.options", { name: label }),
|
|
2730
|
+
onClick: (event) => {
|
|
2731
|
+
event.stopPropagation();
|
|
2732
|
+
setMenuOpen((current) => !current);
|
|
2733
|
+
},
|
|
2734
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2735
|
+
})
|
|
2736
|
+
})
|
|
2737
|
+
})]
|
|
2738
|
+
})]
|
|
2739
|
+
}),
|
|
2740
|
+
content: (0, react_jsx_runtime.jsx)(WorktreeSessionHoverContent, {
|
|
2741
|
+
label,
|
|
2742
|
+
blank,
|
|
2743
|
+
presentation,
|
|
2744
|
+
t
|
|
2745
|
+
}),
|
|
2746
|
+
openDelayMs: 500,
|
|
2747
|
+
disabled: menuOpen || drag.active,
|
|
2748
|
+
copyText: blank ? void 0 : label,
|
|
2749
|
+
copyLabel: t("copy"),
|
|
2750
|
+
copiedLabel: t("hover.copied")
|
|
2065
2751
|
});
|
|
2066
2752
|
}
|
|
2067
|
-
function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, currentSessionId, expanded, actionPending, sessions, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
|
|
2753
|
+
function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, currentSessionId, expanded, actionPending, sessions, sessionPresentations, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
|
|
2068
2754
|
const visibleSessionIds = expanded ? sessionIds : sessionIds.slice(0, 5);
|
|
2069
2755
|
const sameGroupDrag = dragState?.groupKey === groupKey;
|
|
2070
2756
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
|
|
@@ -2073,6 +2759,7 @@ window.__ModuleLoader__.load({
|
|
|
2073
2759
|
blank: isBlankSession(sessionId, sessions),
|
|
2074
2760
|
current: sessionId === currentSessionId,
|
|
2075
2761
|
label: sessionLabel(sessionId, sessions, t),
|
|
2762
|
+
presentation: sessionPresentations[sessionId],
|
|
2076
2763
|
drag: {
|
|
2077
2764
|
active: sameGroupDrag,
|
|
2078
2765
|
marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
|
|
@@ -2124,6 +2811,33 @@ window.__ModuleLoader__.load({
|
|
|
2124
2811
|
status: "idle",
|
|
2125
2812
|
views: []
|
|
2126
2813
|
};
|
|
2814
|
+
const EMPTY_PERMISSION_NOTICE = void 0;
|
|
2815
|
+
const EMPTY_PERMISSION_NOTICE_SUBSCRIBE = () => () => {};
|
|
2816
|
+
const EMPTY_PERMISSION_NOTICE_SNAPSHOT = () => EMPTY_PERMISSION_NOTICE;
|
|
2817
|
+
const EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE = () => () => {};
|
|
2818
|
+
const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => void 0;
|
|
2819
|
+
const EMPTY_FORK_RECOVERY_SNAPSHOT = {
|
|
2820
|
+
revision: 0,
|
|
2821
|
+
pending: []
|
|
2822
|
+
};
|
|
2823
|
+
const EMPTY_FORK_RECOVERY_STORE = {
|
|
2824
|
+
getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
|
|
2825
|
+
subscribe: () => () => {}
|
|
2826
|
+
};
|
|
2827
|
+
function updatedAtById(sessionIds, sessions) {
|
|
2828
|
+
return Object.fromEntries(sessionIds.map((sessionId) => [sessionId, sessions.byId[sessionId]?.updatedAt]));
|
|
2829
|
+
}
|
|
2830
|
+
function forkRecoveryError(recovery) {
|
|
2831
|
+
const error = toNativeWorktreeViewError(recovery.error);
|
|
2832
|
+
return {
|
|
2833
|
+
...error,
|
|
2834
|
+
code: error.code === "WORKTREE_VIEW_FAILED" ? "SESSION_BINDING_FAILED" : error.code,
|
|
2835
|
+
details: {
|
|
2836
|
+
...error.details ?? {},
|
|
2837
|
+
sessionId: recovery.childSessionId
|
|
2838
|
+
}
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2127
2841
|
function useStableWorkspaceIds(workspaces) {
|
|
2128
2842
|
const next = workspaces.map((workspace) => workspace.workspaceId);
|
|
2129
2843
|
const previousRef = (0, react.useRef)([]);
|
|
@@ -2135,14 +2849,30 @@ window.__ModuleLoader__.load({
|
|
|
2135
2849
|
* Peer Worktree navigation surface. It keeps the original DSH Workspace mode
|
|
2136
2850
|
* intact and renders a browser-local Workspace → Worktree → Session projection.
|
|
2137
2851
|
*/
|
|
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 }) {
|
|
2852
|
+
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
2853
|
const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
|
|
2140
2854
|
const sessions = useSessions((state) => state);
|
|
2141
2855
|
const workspaces = useWorkspaces((state) => state);
|
|
2856
|
+
const forkRecoveryStore = forkRecovery ?? EMPTY_FORK_RECOVERY_STORE;
|
|
2857
|
+
const forkRecoverySnapshot = (0, react.useSyncExternalStore)(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
|
|
2142
2858
|
const currentSessionId = sessions.current;
|
|
2143
2859
|
const workspaceIds = useStableWorkspaceIds(workspaces.items);
|
|
2144
2860
|
const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
|
|
2145
2861
|
const expandSnapshot = (0, react.useSyncExternalStore)(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
|
|
2862
|
+
const permissionNoticeSnapshot = (0, react.useSyncExternalStore)(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
|
|
2863
|
+
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);
|
|
2864
|
+
const fullAccessConfirmationKey = fullAccessConfirmationSnapshot === void 0 ? "" : [
|
|
2865
|
+
fullAccessConfirmationSnapshot.workspaceId,
|
|
2866
|
+
fullAccessConfirmationSnapshot.worktreeId,
|
|
2867
|
+
fullAccessConfirmationSnapshot.sessionId,
|
|
2868
|
+
fullAccessConfirmationSnapshot.cwd
|
|
2869
|
+
].join("\0");
|
|
2870
|
+
const [fullAccessAcknowledged, setFullAccessAcknowledged] = (0, react.useState)(false);
|
|
2871
|
+
(0, react.useEffect)(() => {
|
|
2872
|
+
setFullAccessAcknowledged(false);
|
|
2873
|
+
}, [fullAccessConfirmationKey]);
|
|
2874
|
+
const sessionOrderSnapshot = (0, react.useSyncExternalStore)(sessionOrder.subscribe, sessionOrder.getSnapshot, sessionOrder.getSnapshot);
|
|
2875
|
+
const sessionPresentations = (0, react.useMemo)(() => deriveSessionPresentationIndex(sessions), [sessions.byId]);
|
|
2146
2876
|
const readStateRef = (0, react.useRef)(readState);
|
|
2147
2877
|
readStateRef.current = readState;
|
|
2148
2878
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
@@ -2161,6 +2891,7 @@ window.__ModuleLoader__.load({
|
|
|
2161
2891
|
});
|
|
2162
2892
|
const [selectedImportPath, setSelectedImportPath] = (0, react.useState)();
|
|
2163
2893
|
const [openWorkspaceMenuId, setOpenWorkspaceMenuId] = (0, react.useState)();
|
|
2894
|
+
const [openMainMenuId, setOpenMainMenuId] = (0, react.useState)();
|
|
2164
2895
|
const [openWorktreeMenuId, setOpenWorktreeMenuId] = (0, react.useState)();
|
|
2165
2896
|
const [worktreeRemoval, setWorktreeRemoval] = (0, react.useState)();
|
|
2166
2897
|
const [selectedBranch, setSelectedBranch] = (0, react.useState)("");
|
|
@@ -2168,6 +2899,7 @@ window.__ModuleLoader__.load({
|
|
|
2168
2899
|
const [pendingSessionBinding, setPendingSessionBinding] = (0, react.useState)();
|
|
2169
2900
|
const [actionError, setActionError] = (0, react.useState)();
|
|
2170
2901
|
const [actionPending, setActionPending] = (0, react.useState)(false);
|
|
2902
|
+
const [forkRetryKey, setForkRetryKey] = (0, react.useState)();
|
|
2171
2903
|
const [sessionRenameTarget, setSessionRenameTarget] = (0, react.useState)();
|
|
2172
2904
|
const [sessionRenameDraft, setSessionRenameDraft] = (0, react.useState)("");
|
|
2173
2905
|
const [sessionRenamePending, setSessionRenamePending] = (0, react.useState)(false);
|
|
@@ -2187,6 +2919,7 @@ window.__ModuleLoader__.load({
|
|
|
2187
2919
|
const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
|
|
2188
2920
|
const worktreeDropCommitted = (0, react.useRef)(false);
|
|
2189
2921
|
const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
|
|
2922
|
+
const forkRecoveryRevisionRef = (0, react.useRef)(forkRecoverySnapshot.revision);
|
|
2190
2923
|
const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader());
|
|
2191
2924
|
const modalReadViewRef = (0, react.useRef)();
|
|
2192
2925
|
const importCandidatesGuard = (0, react.useRef)(createWorktreeRefreshGuard());
|
|
@@ -2265,6 +2998,20 @@ window.__ModuleLoader__.load({
|
|
|
2265
2998
|
setReadState(EMPTY_READ_STATE);
|
|
2266
2999
|
}
|
|
2267
3000
|
}, [mode, refresh]);
|
|
3001
|
+
(0, react.useEffect)(() => {
|
|
3002
|
+
if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision) return;
|
|
3003
|
+
forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
|
|
3004
|
+
if (mode !== "worktree" || manager === void 0) return;
|
|
3005
|
+
refresh({
|
|
3006
|
+
preserveCurrent: readStateRef.current.status === "ready",
|
|
3007
|
+
invalidateContext: false
|
|
3008
|
+
}).catch(() => {});
|
|
3009
|
+
}, [
|
|
3010
|
+
forkRecoverySnapshot.revision,
|
|
3011
|
+
manager,
|
|
3012
|
+
mode,
|
|
3013
|
+
refresh
|
|
3014
|
+
]);
|
|
2268
3015
|
(0, react.useEffect)(() => {
|
|
2269
3016
|
if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
|
|
2270
3017
|
syncSessionWorkspaces(readState.views.flatMap((view) => view.bindings.map((binding) => ({
|
|
@@ -2277,6 +3024,60 @@ window.__ModuleLoader__.load({
|
|
|
2277
3024
|
syncSessionWorkspaces
|
|
2278
3025
|
]);
|
|
2279
3026
|
const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
|
|
3027
|
+
const sessionOrderInputs = (0, react.useMemo)(() => {
|
|
3028
|
+
if (readState.status !== "ready") return [];
|
|
3029
|
+
const inputs = [];
|
|
3030
|
+
for (const workspace of workspaces.items) {
|
|
3031
|
+
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
3032
|
+
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
3033
|
+
const bindings = view?.bindings ?? [];
|
|
3034
|
+
const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
|
|
3035
|
+
inputs.push({
|
|
3036
|
+
accountKey: `main:${workspace.workspaceId}`,
|
|
3037
|
+
sessionIds: mainSessionIds,
|
|
3038
|
+
updatedAtById: updatedAtById(mainSessionIds, sessions)
|
|
3039
|
+
});
|
|
3040
|
+
for (const record of view?.worktrees ?? []) {
|
|
3041
|
+
const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
|
|
3042
|
+
inputs.push({
|
|
3043
|
+
accountKey: `worktree:${record.worktreeId}`,
|
|
3044
|
+
sessionIds: worktreeSessionIds,
|
|
3045
|
+
updatedAtById: updatedAtById(worktreeSessionIds, sessions)
|
|
3046
|
+
});
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
return inputs;
|
|
3050
|
+
}, [
|
|
3051
|
+
archivedSessionIds,
|
|
3052
|
+
readState.status,
|
|
3053
|
+
sessions.byId,
|
|
3054
|
+
sessions.ids,
|
|
3055
|
+
viewByWorkspace,
|
|
3056
|
+
workspaces,
|
|
3057
|
+
workspaces.items
|
|
3058
|
+
]);
|
|
3059
|
+
const orderedSessionIdsByAccount = (0, react.useMemo)(() => {
|
|
3060
|
+
const ordered = /* @__PURE__ */ new Map();
|
|
3061
|
+
for (const input of sessionOrderInputs) {
|
|
3062
|
+
const previous = sessionOrderSnapshot.accounts[input.accountKey];
|
|
3063
|
+
ordered.set(input.accountKey, nextSessionOrderAccount({
|
|
3064
|
+
baseIds: input.sessionIds,
|
|
3065
|
+
updatedAtById: input.updatedAtById,
|
|
3066
|
+
previous
|
|
3067
|
+
}).order);
|
|
3068
|
+
}
|
|
3069
|
+
return ordered;
|
|
3070
|
+
}, [sessionOrderInputs, sessionOrderSnapshot]);
|
|
3071
|
+
(0, react.useEffect)(() => {
|
|
3072
|
+
if (mode !== "worktree" || readState.status !== "ready") return;
|
|
3073
|
+
for (const input of sessionOrderInputs) sessionOrder.actions.reconcile(input.accountKey, input.sessionIds, input.updatedAtById);
|
|
3074
|
+
sessionOrder.actions.retain(sessionOrderInputs.map((input) => input.accountKey));
|
|
3075
|
+
}, [
|
|
3076
|
+
mode,
|
|
3077
|
+
readState.status,
|
|
3078
|
+
sessionOrder,
|
|
3079
|
+
sessionOrderInputs
|
|
3080
|
+
]);
|
|
2280
3081
|
const currentSessionLocation = (0, react.useMemo)(() => readState.status === "ready" ? resolveCurrentSessionLocation(currentSessionId, workspaces.items, readState.views) : void 0, [
|
|
2281
3082
|
currentSessionId,
|
|
2282
3083
|
readState.status,
|
|
@@ -2496,7 +3297,10 @@ window.__ModuleLoader__.load({
|
|
|
2496
3297
|
return;
|
|
2497
3298
|
}
|
|
2498
3299
|
setActionError(void 0);
|
|
2499
|
-
|
|
3300
|
+
const currentOrder = sessionOrderSnapshot.accounts[activeDrag.groupKey]?.order ?? sessionIds;
|
|
3301
|
+
insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId).then(() => {
|
|
3302
|
+
sessionOrder.actions.setOrder(activeDrag.groupKey, reorderSessionIds(currentOrder, activeDrag.sessionId, over.sessionId, over.half));
|
|
3303
|
+
}).catch((error) => {
|
|
2500
3304
|
setActionError(toWorktreeViewError(error));
|
|
2501
3305
|
});
|
|
2502
3306
|
};
|
|
@@ -2617,8 +3421,7 @@ window.__ModuleLoader__.load({
|
|
|
2617
3421
|
expandState.actions.toggleWorktree(worktreeId);
|
|
2618
3422
|
if (visuallyExpanded) clearSessionGroups(["worktree:" + worktreeId]);
|
|
2619
3423
|
};
|
|
2620
|
-
const toggleSessionGroup = (groupKey) => {
|
|
2621
|
-
const autoExpanded = isCurrentSessionReveal("session-group:" + groupKey);
|
|
3424
|
+
const toggleSessionGroup = (groupKey, autoExpanded) => {
|
|
2622
3425
|
const transientExpanded = expandedSessionGroups[groupKey] === true;
|
|
2623
3426
|
if (autoExpanded) {
|
|
2624
3427
|
suppressCurrentSessionReveal("session-group:" + groupKey);
|
|
@@ -2643,7 +3446,7 @@ window.__ModuleLoader__.load({
|
|
|
2643
3446
|
setModalReadError(void 0);
|
|
2644
3447
|
setModalReadLoading(false);
|
|
2645
3448
|
};
|
|
2646
|
-
const openWorktreeCreator = (workspace) => {
|
|
3449
|
+
const openWorktreeCreator = (workspace, defaults = {}) => {
|
|
2647
3450
|
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
2648
3451
|
modalReadLoader.current.invalidate();
|
|
2649
3452
|
modalReadViewRef.current = void 0;
|
|
@@ -2659,13 +3462,13 @@ window.__ModuleLoader__.load({
|
|
|
2659
3462
|
setModalReadError(void 0);
|
|
2660
3463
|
setModalReadLoading(false);
|
|
2661
3464
|
if (view === void 0) {
|
|
2662
|
-
setSelectedBranch("");
|
|
2663
|
-
setNewBranch("");
|
|
3465
|
+
setSelectedBranch(defaults.baseBranch ?? "");
|
|
3466
|
+
setNewBranch(defaults.newBranch ?? "");
|
|
2664
3467
|
loadModalWorktreeView(workspace.workspaceId);
|
|
2665
3468
|
return;
|
|
2666
3469
|
}
|
|
2667
|
-
setSelectedBranch(selectDefaultBaseBranch(view.branches));
|
|
2668
|
-
setNewBranch(createDefaultWorktreeName([...view.branches.map((branch) => branch.name), ...view.worktrees.map((worktree) => worktree.branch)]));
|
|
3470
|
+
setSelectedBranch(defaults.baseBranch ?? selectDefaultBaseBranch(view.branches));
|
|
3471
|
+
setNewBranch(defaults.newBranch ?? createDefaultWorktreeName([...view.branches.map((branch) => branch.name), ...view.worktrees.map((worktree) => worktree.branch)]));
|
|
2669
3472
|
};
|
|
2670
3473
|
const changeWorktreeModalMode = (mode) => {
|
|
2671
3474
|
setWorktreeModalMode(mode);
|
|
@@ -2695,6 +3498,11 @@ window.__ModuleLoader__.load({
|
|
|
2695
3498
|
...sessionInput,
|
|
2696
3499
|
sessionId: error.sessionId
|
|
2697
3500
|
});
|
|
3501
|
+
if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
|
|
3502
|
+
...sessionInput,
|
|
3503
|
+
sessionId: error.sessionId,
|
|
3504
|
+
permissionRequired: true
|
|
3505
|
+
});
|
|
2698
3506
|
throw error;
|
|
2699
3507
|
}
|
|
2700
3508
|
await refresh({ preserveCurrent: true });
|
|
@@ -2756,6 +3564,11 @@ window.__ModuleLoader__.load({
|
|
|
2756
3564
|
...input,
|
|
2757
3565
|
sessionId: error.sessionId
|
|
2758
3566
|
});
|
|
3567
|
+
if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
|
|
3568
|
+
...input,
|
|
3569
|
+
sessionId: error.sessionId,
|
|
3570
|
+
permissionRequired: true
|
|
3571
|
+
});
|
|
2759
3572
|
setActionError(toWorktreeViewError(error));
|
|
2760
3573
|
} finally {
|
|
2761
3574
|
setActionPending(false);
|
|
@@ -2774,6 +3587,9 @@ window.__ModuleLoader__.load({
|
|
|
2774
3587
|
ensureSessionWorkspace: (workspaceId, sessionId) => {
|
|
2775
3588
|
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2776
3589
|
},
|
|
3590
|
+
permission,
|
|
3591
|
+
confirmFullAccess,
|
|
3592
|
+
onPermissionResult,
|
|
2777
3593
|
openSession
|
|
2778
3594
|
});
|
|
2779
3595
|
setPendingSessionBinding(void 0);
|
|
@@ -2786,6 +3602,17 @@ window.__ModuleLoader__.load({
|
|
|
2786
3602
|
setActionPending(false);
|
|
2787
3603
|
}
|
|
2788
3604
|
};
|
|
3605
|
+
const retryForkBinding = async (key) => {
|
|
3606
|
+
if (retryForkSession === void 0 || forkRetryKey !== void 0) return;
|
|
3607
|
+
setForkRetryKey(key);
|
|
3608
|
+
try {
|
|
3609
|
+
await retryForkSession(key);
|
|
3610
|
+
} catch (error) {
|
|
3611
|
+
setActionError(toNativeWorktreeViewError(error));
|
|
3612
|
+
} finally {
|
|
3613
|
+
setForkRetryKey(void 0);
|
|
3614
|
+
}
|
|
3615
|
+
};
|
|
2789
3616
|
const openWorkspaceSession = (workspaceId, sessionId) => {
|
|
2790
3617
|
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2791
3618
|
openWorktreeSession({ open: openSession }, sessionId);
|
|
@@ -2851,7 +3678,7 @@ window.__ModuleLoader__.load({
|
|
|
2851
3678
|
onClick: () => {
|
|
2852
3679
|
if (createWorkspace !== void 0) runMutation(createWorkspace);
|
|
2853
3680
|
},
|
|
2854
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
3681
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconProjectAddOutline16, {})
|
|
2855
3682
|
})
|
|
2856
3683
|
]
|
|
2857
3684
|
}),
|
|
@@ -2859,6 +3686,47 @@ window.__ModuleLoader__.load({
|
|
|
2859
3686
|
className: worktree_css_default.content,
|
|
2860
3687
|
tabIndex: 0,
|
|
2861
3688
|
children: [
|
|
3689
|
+
permissionNoticeSnapshot !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
3690
|
+
className: worktree_css_default.notice,
|
|
3691
|
+
role: "status",
|
|
3692
|
+
"data-worktree-permission-notice": true,
|
|
3693
|
+
children: (0, react_jsx_runtime.jsx)("p", {
|
|
3694
|
+
className: worktree_css_default.message,
|
|
3695
|
+
children: formatWorktreePermissionNotice(permissionNoticeSnapshot.result, t)
|
|
3696
|
+
})
|
|
3697
|
+
}),
|
|
3698
|
+
forkRecoverySnapshot.pending.map((recovery) => {
|
|
3699
|
+
const recoveryViewError = forkRecoveryError(recovery);
|
|
3700
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3701
|
+
className: worktree_css_default.error,
|
|
3702
|
+
role: "alert",
|
|
3703
|
+
"data-fork-recovery": recovery.key,
|
|
3704
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
3705
|
+
className: worktree_css_default.message,
|
|
3706
|
+
"data-error": "true",
|
|
3707
|
+
children: formatWorktreeViewError(recoveryViewError, t)
|
|
3708
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
3709
|
+
className: worktree_css_default.recoveryActions,
|
|
3710
|
+
children: [retryForkSession !== void 0 && recoveryViewError.retryable && (0, react_jsx_runtime.jsx)("button", {
|
|
3711
|
+
type: "button",
|
|
3712
|
+
className: worktree_css_default.actionButton,
|
|
3713
|
+
disabled: forkRetryKey !== void 0,
|
|
3714
|
+
onClick: () => {
|
|
3715
|
+
retryForkBinding(recovery.key);
|
|
3716
|
+
},
|
|
3717
|
+
children: t("action.retryBinding")
|
|
3718
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
3719
|
+
type: "button",
|
|
3720
|
+
className: worktree_css_default.actionButton,
|
|
3721
|
+
disabled: forkRetryKey !== void 0,
|
|
3722
|
+
onClick: () => {
|
|
3723
|
+
openSession(recovery.childSessionId);
|
|
3724
|
+
},
|
|
3725
|
+
children: t("action.openCreatedSession")
|
|
3726
|
+
})]
|
|
3727
|
+
})]
|
|
3728
|
+
}, recovery.key);
|
|
3729
|
+
}),
|
|
2862
3730
|
actionError !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
2863
3731
|
className: worktree_css_default.error,
|
|
2864
3732
|
role: "alert",
|
|
@@ -2879,7 +3747,7 @@ window.__ModuleLoader__.load({
|
|
|
2879
3747
|
retrySessionBinding();
|
|
2880
3748
|
},
|
|
2881
3749
|
children: t("action.retryBinding")
|
|
2882
|
-
}), (0, react_jsx_runtime.jsx)("button", {
|
|
3750
|
+
}), !pendingSessionBinding.permissionRequired && (0, react_jsx_runtime.jsx)("button", {
|
|
2883
3751
|
type: "button",
|
|
2884
3752
|
className: worktree_css_default.actionButton,
|
|
2885
3753
|
disabled: actionPending,
|
|
@@ -2935,13 +3803,19 @@ window.__ModuleLoader__.load({
|
|
|
2935
3803
|
const expanded = isWorkspaceExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("workspace:" + workspace.workspaceId);
|
|
2936
3804
|
const workspaceMatchesQuery = includesText(workspace.title, query);
|
|
2937
3805
|
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
3806
|
+
const workspaceHasOngoingSession = hasOngoingSession(filterVisibleSessionIds(allWorkspaceSessionIds, sessions), sessionPresentations);
|
|
2938
3807
|
const bindings = view?.bindings ?? [];
|
|
2939
|
-
const
|
|
2940
|
-
const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("main:" + workspace.workspaceId);
|
|
3808
|
+
const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
|
|
2941
3809
|
const mainGroupKey = `main:${workspace.workspaceId}`;
|
|
2942
|
-
const
|
|
2943
|
-
const
|
|
3810
|
+
const orderedMainSessionIds = orderedSessionIdsByAccount.get(mainGroupKey) ?? mainSessionIds;
|
|
3811
|
+
const visibleMainSessionIds = mainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3812
|
+
const orderedVisibleMainSessionIds = orderedMainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3813
|
+
const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("main:" + workspace.workspaceId);
|
|
3814
|
+
const sessionIds = orderedVisibleMainSessionIds.length === visibleMainSessionIds.length ? orderedVisibleMainSessionIds : visibleMainSessionIds;
|
|
3815
|
+
const mainSessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + mainGroupKey));
|
|
3816
|
+
const mainSessionGroupExpanded = expandedSessionGroups[mainGroupKey] === true || mainSessionGroupAutoExpanded;
|
|
2944
3817
|
const worktrees = view?.worktrees ?? [];
|
|
3818
|
+
const workspaceWorktreeNames = [...view?.branches.map((branch) => branch.name) ?? [], ...view?.worktrees.map((worktree) => worktree.branch) ?? []];
|
|
2945
3819
|
const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
|
|
2946
3820
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
2947
3821
|
className: worktree_css_default.workspaceGroup,
|
|
@@ -2950,6 +3824,7 @@ window.__ModuleLoader__.load({
|
|
|
2950
3824
|
t,
|
|
2951
3825
|
workspace,
|
|
2952
3826
|
expanded,
|
|
3827
|
+
hasOngoingSession: workspaceHasOngoingSession,
|
|
2953
3828
|
actionPending,
|
|
2954
3829
|
menuOpen: openWorkspaceMenuId === workspace.workspaceId,
|
|
2955
3830
|
drag: {
|
|
@@ -3007,11 +3882,29 @@ window.__ModuleLoader__.load({
|
|
|
3007
3882
|
kind: "main",
|
|
3008
3883
|
label: mainLabel,
|
|
3009
3884
|
expanded: mainExpanded,
|
|
3885
|
+
hasOngoingSession: hasOngoingSession(mainSessionIds, sessionPresentations),
|
|
3010
3886
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
3011
3887
|
workspaceTitle: workspace.title,
|
|
3012
3888
|
onToggle: () => {
|
|
3013
3889
|
toggleMain(workspace.workspaceId);
|
|
3014
3890
|
},
|
|
3891
|
+
menu: {
|
|
3892
|
+
open: openMainMenuId === workspace.workspaceId,
|
|
3893
|
+
label: mainLabel,
|
|
3894
|
+
copyPath: workspace.path,
|
|
3895
|
+
showCreate: currentBranch !== void 0,
|
|
3896
|
+
showRemove: false,
|
|
3897
|
+
disabled: actionPending,
|
|
3898
|
+
onOpenChange: (open) => {
|
|
3899
|
+
setOpenMainMenuId(open ? workspace.workspaceId : void 0);
|
|
3900
|
+
},
|
|
3901
|
+
onCreateWorktree: currentBranch === void 0 ? void 0 : () => {
|
|
3902
|
+
openWorktreeCreator(workspace, {
|
|
3903
|
+
baseBranch: currentBranch,
|
|
3904
|
+
newBranch: createNumberedWorktreeName(currentBranch, workspaceWorktreeNames)
|
|
3905
|
+
});
|
|
3906
|
+
}
|
|
3907
|
+
},
|
|
3015
3908
|
onCreateSession: createMainSession === void 0 ? void 0 : () => {
|
|
3016
3909
|
createMainSession(workspace.workspaceId);
|
|
3017
3910
|
}
|
|
@@ -3025,9 +3918,10 @@ window.__ModuleLoader__.load({
|
|
|
3025
3918
|
expanded: mainSessionGroupExpanded,
|
|
3026
3919
|
actionPending,
|
|
3027
3920
|
sessions,
|
|
3921
|
+
sessionPresentations,
|
|
3028
3922
|
dragState: sessionDrag,
|
|
3029
3923
|
onToggleExpanded: () => {
|
|
3030
|
-
toggleSessionGroup(mainGroupKey);
|
|
3924
|
+
toggleSessionGroup(mainGroupKey, mainSessionGroupAutoExpanded);
|
|
3031
3925
|
},
|
|
3032
3926
|
onStartDrag: (groupKey, sessionId) => {
|
|
3033
3927
|
sessionDropCommitted.current = false;
|
|
@@ -3070,10 +3964,12 @@ window.__ModuleLoader__.load({
|
|
|
3070
3964
|
if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return null;
|
|
3071
3965
|
const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3072
3966
|
const worktreeGroupKey = `worktree:${record.worktreeId}`;
|
|
3073
|
-
const
|
|
3074
|
-
const
|
|
3075
|
-
const
|
|
3076
|
-
const
|
|
3967
|
+
const orderedVisibleWorktreeSessionIds = (orderedSessionIdsByAccount.get(worktreeGroupKey) ?? worktreeSessionIds).filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3968
|
+
const sessionIds = orderedVisibleWorktreeSessionIds.length === visibleWorktreeSessionIds.length ? orderedVisibleWorktreeSessionIds : visibleWorktreeSessionIds;
|
|
3969
|
+
const sessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + worktreeGroupKey));
|
|
3970
|
+
const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true || sessionGroupAutoExpanded;
|
|
3971
|
+
const state = record.status === "removed" ? "warning" : record.health === "repair" || record.health === "recovery-needed" ? "error" : "done";
|
|
3972
|
+
const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "recovery-needed" ? t("worktree.recovery") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
|
|
3077
3973
|
const worktreeExpanded = isWorktreeExpanded(expandSnapshot, record.worktreeId) || isCurrentSessionReveal("worktree:" + record.worktreeId);
|
|
3078
3974
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3079
3975
|
className: worktree_css_default.worktreeGroup,
|
|
@@ -3084,6 +3980,7 @@ window.__ModuleLoader__.load({
|
|
|
3084
3980
|
label: record.branch,
|
|
3085
3981
|
worktreeId: record.worktreeId,
|
|
3086
3982
|
expanded: worktreeExpanded,
|
|
3983
|
+
hasOngoingSession: hasOngoingSession(worktreeSessionIds, sessionPresentations),
|
|
3087
3984
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
3088
3985
|
workspaceTitle: workspace.title,
|
|
3089
3986
|
state,
|
|
@@ -3091,25 +3988,34 @@ window.__ModuleLoader__.load({
|
|
|
3091
3988
|
onToggle: () => {
|
|
3092
3989
|
toggleWorktree(record.worktreeId);
|
|
3093
3990
|
},
|
|
3094
|
-
onCreateSession: record.status === "active" && record.health !== "repair" ? () => {
|
|
3991
|
+
onCreateSession: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed" ? () => {
|
|
3095
3992
|
createSession({
|
|
3096
3993
|
workspaceId: record.workspaceId,
|
|
3097
3994
|
worktreeId: record.worktreeId,
|
|
3098
3995
|
cwd: record.absolutePath
|
|
3099
3996
|
});
|
|
3100
3997
|
} : void 0,
|
|
3101
|
-
menu:
|
|
3998
|
+
menu: {
|
|
3102
3999
|
open: openWorktreeMenuId === record.worktreeId,
|
|
3103
4000
|
label: record.branch,
|
|
4001
|
+
copyPath: record.absolutePath,
|
|
4002
|
+
showCreate: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed",
|
|
4003
|
+
showRemove: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed",
|
|
3104
4004
|
disabled: actionPending,
|
|
3105
4005
|
onOpenChange: (open) => {
|
|
3106
4006
|
setOpenWorktreeMenuId(open ? record.worktreeId : void 0);
|
|
3107
4007
|
},
|
|
3108
|
-
|
|
4008
|
+
onCreateWorktree: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed" ? () => {
|
|
4009
|
+
openWorktreeCreator(workspace, {
|
|
4010
|
+
baseBranch: record.branch,
|
|
4011
|
+
newBranch: createNumberedWorktreeName(record.branch, workspaceWorktreeNames)
|
|
4012
|
+
});
|
|
4013
|
+
} : void 0,
|
|
4014
|
+
onRemove: record.status === "active" ? () => {
|
|
3109
4015
|
setWorktreeRemoval(record);
|
|
3110
4016
|
setActionError(void 0);
|
|
3111
|
-
}
|
|
3112
|
-
}
|
|
4017
|
+
} : void 0
|
|
4018
|
+
},
|
|
3113
4019
|
drag: {
|
|
3114
4020
|
active: sameWorkspaceWorktreeDrag,
|
|
3115
4021
|
marker: worktreeDrag?.over?.worktreeId === record.worktreeId ? worktreeDrag.over.half : null,
|
|
@@ -3151,9 +4057,10 @@ window.__ModuleLoader__.load({
|
|
|
3151
4057
|
expanded: sessionGroupExpanded,
|
|
3152
4058
|
actionPending,
|
|
3153
4059
|
sessions,
|
|
4060
|
+
sessionPresentations,
|
|
3154
4061
|
dragState: sessionDrag,
|
|
3155
4062
|
onToggleExpanded: () => {
|
|
3156
|
-
toggleSessionGroup(worktreeGroupKey);
|
|
4063
|
+
toggleSessionGroup(worktreeGroupKey, sessionGroupAutoExpanded);
|
|
3157
4064
|
},
|
|
3158
4065
|
onStartDrag: (groupKey, sessionId) => {
|
|
3159
4066
|
sessionDropCommitted.current = false;
|
|
@@ -3272,18 +4179,50 @@ window.__ModuleLoader__.load({
|
|
|
3272
4179
|
onSubmit: () => {
|
|
3273
4180
|
if (manager === void 0 || worktreeRemoval === void 0) return;
|
|
3274
4181
|
const target = worktreeRemoval;
|
|
4182
|
+
const mutationToken = target.mutationToken;
|
|
4183
|
+
if (mutationToken === void 0) {
|
|
4184
|
+
setActionError({
|
|
4185
|
+
code: "WORKTREE_STATE_CONFLICT",
|
|
4186
|
+
message: "",
|
|
4187
|
+
retryable: true,
|
|
4188
|
+
details: {
|
|
4189
|
+
workspaceId: target.workspaceId,
|
|
4190
|
+
worktreeId: target.worktreeId
|
|
4191
|
+
}
|
|
4192
|
+
});
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
3275
4195
|
runMutation(async () => {
|
|
3276
4196
|
await executeWorktreeAction(manager, {
|
|
3277
4197
|
type: "removeWorktree",
|
|
3278
4198
|
input: {
|
|
3279
4199
|
workspaceId: target.workspaceId,
|
|
3280
|
-
worktreeId: target.worktreeId
|
|
4200
|
+
worktreeId: target.worktreeId,
|
|
4201
|
+
mutationToken
|
|
3281
4202
|
}
|
|
3282
|
-
});
|
|
4203
|
+
}, permission, onPermissionNotice);
|
|
3283
4204
|
await invalidateWorktreeContext?.(target.workspaceId);
|
|
3284
4205
|
setWorktreeRemoval(void 0);
|
|
3285
4206
|
});
|
|
3286
4207
|
}
|
|
4208
|
+
}),
|
|
4209
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.RiskConfirmation, {
|
|
4210
|
+
open: fullAccessConfirmationSnapshot !== void 0,
|
|
4211
|
+
title: t("permission.fullAccessTitle"),
|
|
4212
|
+
description: fullAccessConfirmationSnapshot === void 0 ? "" : t("permission.fullAccessDescription", { cwd: fullAccessConfirmationSnapshot.cwd }),
|
|
4213
|
+
acknowledgeLabel: t("permission.fullAccessAcknowledge"),
|
|
4214
|
+
cancelLabel: t("dialog.cancel"),
|
|
4215
|
+
confirmLabel: t("permission.fullAccessEnable"),
|
|
4216
|
+
acknowledged: fullAccessAcknowledged,
|
|
4217
|
+
onAcknowledgedChange: setFullAccessAcknowledged,
|
|
4218
|
+
onCancel: () => {
|
|
4219
|
+
setFullAccessAcknowledged(false);
|
|
4220
|
+
fullAccessConfirmation?.resolve(false);
|
|
4221
|
+
},
|
|
4222
|
+
onConfirm: () => {
|
|
4223
|
+
setFullAccessAcknowledged(false);
|
|
4224
|
+
fullAccessConfirmation?.resolve(true);
|
|
4225
|
+
}
|
|
3287
4226
|
})
|
|
3288
4227
|
]
|
|
3289
4228
|
});
|
|
@@ -3313,7 +4252,7 @@ window.__ModuleLoader__.load({
|
|
|
3313
4252
|
const record = input.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId);
|
|
3314
4253
|
if (record === void 0 || record.workspaceId !== workspace.workspaceId) return none(record === void 0 ? "stale" : "workspace-mismatch");
|
|
3315
4254
|
if (record.status !== "active") return none("stale");
|
|
3316
|
-
if (record.health === "repair") return none("repair");
|
|
4255
|
+
if (record.health === "repair" || record.health === "recovery-needed") return none("repair");
|
|
3317
4256
|
if (record.branch.length === 0) return none("not-ready");
|
|
3318
4257
|
return {
|
|
3319
4258
|
kind: "worktree",
|
|
@@ -3649,6 +4588,313 @@ window.__ModuleLoader__.load({
|
|
|
3649
4588
|
};
|
|
3650
4589
|
}
|
|
3651
4590
|
//#endregion
|
|
4591
|
+
//#region lib/client/worktree-permission.js
|
|
4592
|
+
/**
|
|
4593
|
+
* Coordinate async permission requests with the one in-page confirmation
|
|
4594
|
+
* rendered by the Worktree surface. Requests are serialized so concurrent
|
|
4595
|
+
* Worktree Session creations cannot replace one another's dialog.
|
|
4596
|
+
*/
|
|
4597
|
+
function createWorktreeFullAccessConfirmationController() {
|
|
4598
|
+
let active;
|
|
4599
|
+
const queue = [];
|
|
4600
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4601
|
+
let disposed = false;
|
|
4602
|
+
const notify = () => {
|
|
4603
|
+
for (const listener of listeners) listener();
|
|
4604
|
+
};
|
|
4605
|
+
const showNext = () => {
|
|
4606
|
+
if (active !== void 0) return;
|
|
4607
|
+
active = queue.shift();
|
|
4608
|
+
notify();
|
|
4609
|
+
};
|
|
4610
|
+
return {
|
|
4611
|
+
getSnapshot: () => active?.input,
|
|
4612
|
+
subscribe: (listener) => {
|
|
4613
|
+
listeners.add(listener);
|
|
4614
|
+
return () => {
|
|
4615
|
+
listeners.delete(listener);
|
|
4616
|
+
};
|
|
4617
|
+
},
|
|
4618
|
+
request: (input) => {
|
|
4619
|
+
if (disposed) return Promise.resolve(false);
|
|
4620
|
+
return new Promise((resolve) => {
|
|
4621
|
+
queue.push({
|
|
4622
|
+
input,
|
|
4623
|
+
resolve
|
|
4624
|
+
});
|
|
4625
|
+
showNext();
|
|
4626
|
+
});
|
|
4627
|
+
},
|
|
4628
|
+
resolve: (confirmed) => {
|
|
4629
|
+
if (active === void 0) return;
|
|
4630
|
+
const current = active;
|
|
4631
|
+
active = void 0;
|
|
4632
|
+
current.resolve(confirmed);
|
|
4633
|
+
showNext();
|
|
4634
|
+
},
|
|
4635
|
+
dispose: () => {
|
|
4636
|
+
if (disposed) return;
|
|
4637
|
+
disposed = true;
|
|
4638
|
+
active?.resolve(false);
|
|
4639
|
+
active = void 0;
|
|
4640
|
+
for (const pending of queue.splice(0)) pending.resolve(false);
|
|
4641
|
+
notify();
|
|
4642
|
+
}
|
|
4643
|
+
};
|
|
4644
|
+
}
|
|
4645
|
+
//#endregion
|
|
4646
|
+
//#region lib/client/worktree-permission-icon.js
|
|
4647
|
+
const PLUGIN_ID = "@cerbur/clutch-dsh-worktree";
|
|
4648
|
+
const STYLE_ID = `${PLUGIN_ID}/permission-icon`;
|
|
4649
|
+
const WORKTREE_PERMISSION_LABEL = "Worktree Full Access";
|
|
4650
|
+
/** DOM marker owned only by this plugin's permission icon decorator. */
|
|
4651
|
+
const WORKTREE_PERMISSION_ICON_ATTRIBUTE = "data-clutch-dsh-worktree-permission-icon";
|
|
4652
|
+
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>";
|
|
4653
|
+
function iconStyles() {
|
|
4654
|
+
const mask = `url("data:image/svg+xml,${encodeURIComponent(ICON_SVG)}")`;
|
|
4655
|
+
return `
|
|
4656
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]::before {
|
|
4657
|
+
content: "";
|
|
4658
|
+
display: inline-block;
|
|
4659
|
+
flex: 0 0 auto;
|
|
4660
|
+
width: 16px;
|
|
4661
|
+
height: 16px;
|
|
4662
|
+
background-color: var(--dsw-alias-label-tertiary, currentColor);
|
|
4663
|
+
-webkit-mask-image: ${mask};
|
|
4664
|
+
mask-image: ${mask};
|
|
4665
|
+
-webkit-mask-position: center;
|
|
4666
|
+
mask-position: center;
|
|
4667
|
+
-webkit-mask-repeat: no-repeat;
|
|
4668
|
+
mask-repeat: no-repeat;
|
|
4669
|
+
-webkit-mask-size: contain;
|
|
4670
|
+
mask-size: contain;
|
|
4671
|
+
}
|
|
4672
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"]::before {
|
|
4673
|
+
width: 14px;
|
|
4674
|
+
height: 14px;
|
|
4675
|
+
}
|
|
4676
|
+
@container (max-width: 460px) {
|
|
4677
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"] > span:first-of-type {
|
|
4678
|
+
display: none;
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
`;
|
|
4682
|
+
}
|
|
4683
|
+
function normalizedText(element) {
|
|
4684
|
+
return (element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
4685
|
+
}
|
|
4686
|
+
function isWorktreeMenuItem(element) {
|
|
4687
|
+
return element.matches("button[role=\"menuitem\"]") && normalizedText(element) === WORKTREE_PERMISSION_LABEL && element.closest("[role=\"menu\"]") !== null;
|
|
4688
|
+
}
|
|
4689
|
+
function isWorktreeTrigger(element) {
|
|
4690
|
+
if (!element.matches("button[aria-label]")) return false;
|
|
4691
|
+
const label = element.getAttribute("aria-label") ?? "";
|
|
4692
|
+
return /^(?:access mode,\s*current:\s*|访问模式,当前:\s*)worktree full access$/iu.test(label.trim());
|
|
4693
|
+
}
|
|
4694
|
+
/** Mark the native custom permission row and trigger for CSS decoration. */
|
|
4695
|
+
function decorateWorktreePermissionIcons(document) {
|
|
4696
|
+
for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) {
|
|
4697
|
+
const kind = marked.getAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4698
|
+
if (kind === "menu" && !isWorktreeMenuItem(marked) || kind === "trigger" && !isWorktreeTrigger(marked)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4699
|
+
}
|
|
4700
|
+
for (const item of document.querySelectorAll("button[role=\"menuitem\"]")) if (isWorktreeMenuItem(item)) item.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "menu");
|
|
4701
|
+
for (const button of document.querySelectorAll("button[aria-label]")) if (isWorktreeTrigger(button)) button.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "trigger");
|
|
4702
|
+
}
|
|
4703
|
+
/** Install the Worktree permission icon and return a plugin-local disposer. */
|
|
4704
|
+
function installWorktreePermissionIcon(document) {
|
|
4705
|
+
for (const existing of document.querySelectorAll("style[data-plugin-css]")) if (existing.getAttribute("data-plugin-css") === STYLE_ID) existing.remove();
|
|
4706
|
+
const style = document.createElement("style");
|
|
4707
|
+
style.setAttribute("data-plugin", PLUGIN_ID);
|
|
4708
|
+
style.setAttribute("data-plugin-css", STYLE_ID);
|
|
4709
|
+
style.textContent = iconStyles();
|
|
4710
|
+
document.head.appendChild(style);
|
|
4711
|
+
let active = true;
|
|
4712
|
+
let queued = false;
|
|
4713
|
+
const scan = () => {
|
|
4714
|
+
if (!active || queued) return;
|
|
4715
|
+
queued = true;
|
|
4716
|
+
queueMicrotask(() => {
|
|
4717
|
+
queued = false;
|
|
4718
|
+
if (active) decorateWorktreePermissionIcons(document);
|
|
4719
|
+
});
|
|
4720
|
+
};
|
|
4721
|
+
decorateWorktreePermissionIcons(document);
|
|
4722
|
+
const observer = typeof MutationObserver === "function" ? new MutationObserver(scan) : void 0;
|
|
4723
|
+
observer?.observe(document.documentElement, {
|
|
4724
|
+
attributes: true,
|
|
4725
|
+
attributeFilter: ["aria-label"],
|
|
4726
|
+
characterData: true,
|
|
4727
|
+
childList: true,
|
|
4728
|
+
subtree: true
|
|
4729
|
+
});
|
|
4730
|
+
return () => {
|
|
4731
|
+
if (!active) return;
|
|
4732
|
+
active = false;
|
|
4733
|
+
observer?.disconnect();
|
|
4734
|
+
style.remove();
|
|
4735
|
+
for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4736
|
+
};
|
|
4737
|
+
}
|
|
4738
|
+
//#endregion
|
|
4739
|
+
//#region lib/client/worktree-session-fork.js
|
|
4740
|
+
function recoveryKey(sourceSessionId, childSessionId) {
|
|
4741
|
+
return `${sourceSessionId}\u0000${childSessionId}`;
|
|
4742
|
+
}
|
|
4743
|
+
/**
|
|
4744
|
+
* Coordinate native Session fork with the plugin-owned Worktree relation.
|
|
4745
|
+
* Native Session creation always wins: plugin lookup/bind failures are kept as
|
|
4746
|
+
* recovery state and never turn an already-created child into a failed fork.
|
|
4747
|
+
*/
|
|
4748
|
+
function createWorktreeSessionForkCoordinator(options) {
|
|
4749
|
+
let disposed = false;
|
|
4750
|
+
let revision = 0;
|
|
4751
|
+
let pending = /* @__PURE__ */ new Map();
|
|
4752
|
+
let recoverySnapshot = {
|
|
4753
|
+
revision: 0,
|
|
4754
|
+
pending: []
|
|
4755
|
+
};
|
|
4756
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
4757
|
+
const boundChildren = /* @__PURE__ */ new Set();
|
|
4758
|
+
const bindingInFlight = /* @__PURE__ */ new Map();
|
|
4759
|
+
let reconciliationInFlight;
|
|
4760
|
+
let reconciliationAgain = false;
|
|
4761
|
+
const publish = () => {
|
|
4762
|
+
revision += 1;
|
|
4763
|
+
recoverySnapshot = {
|
|
4764
|
+
revision,
|
|
4765
|
+
pending: [...pending.values()]
|
|
4766
|
+
};
|
|
4767
|
+
for (const subscriber of subscribers) subscriber();
|
|
4768
|
+
};
|
|
4769
|
+
const setRecovery = (sourceSessionId, childSessionId, error, target) => {
|
|
4770
|
+
if (disposed) return;
|
|
4771
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4772
|
+
pending = new Map(pending).set(key, {
|
|
4773
|
+
key,
|
|
4774
|
+
sourceSessionId,
|
|
4775
|
+
childSessionId,
|
|
4776
|
+
...target === void 0 ? {} : { binding: target },
|
|
4777
|
+
error
|
|
4778
|
+
});
|
|
4779
|
+
publish();
|
|
4780
|
+
};
|
|
4781
|
+
const clearRecovery = (sourceSessionId, childSessionId) => {
|
|
4782
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4783
|
+
if (!pending.has(key)) return;
|
|
4784
|
+
const next = new Map(pending);
|
|
4785
|
+
next.delete(key);
|
|
4786
|
+
pending = next;
|
|
4787
|
+
publish();
|
|
4788
|
+
};
|
|
4789
|
+
const attemptBinding = async (sourceSessionId, childSessionId) => {
|
|
4790
|
+
if (disposed || boundChildren.has(childSessionId)) return { bound: false };
|
|
4791
|
+
let target;
|
|
4792
|
+
try {
|
|
4793
|
+
target = await options.findBinding(sourceSessionId);
|
|
4794
|
+
} catch (error) {
|
|
4795
|
+
setRecovery(sourceSessionId, childSessionId, error);
|
|
4796
|
+
return { bound: false };
|
|
4797
|
+
}
|
|
4798
|
+
if (disposed) return { bound: false };
|
|
4799
|
+
if (target === void 0 || target.status !== "active") {
|
|
4800
|
+
clearRecovery(sourceSessionId, childSessionId);
|
|
4801
|
+
return { bound: false };
|
|
4802
|
+
}
|
|
4803
|
+
try {
|
|
4804
|
+
await options.bindSession({
|
|
4805
|
+
workspaceId: target.workspaceId,
|
|
4806
|
+
worktreeId: target.worktreeId,
|
|
4807
|
+
sessionId: childSessionId
|
|
4808
|
+
});
|
|
4809
|
+
if (disposed) return { bound: false };
|
|
4810
|
+
const childBinding = {
|
|
4811
|
+
workspaceId: target.workspaceId,
|
|
4812
|
+
worktreeId: target.worktreeId,
|
|
4813
|
+
sessionId: childSessionId,
|
|
4814
|
+
status: "active"
|
|
4815
|
+
};
|
|
4816
|
+
boundChildren.add(childSessionId);
|
|
4817
|
+
clearRecovery(sourceSessionId, childSessionId);
|
|
4818
|
+
options.onBound?.(childBinding);
|
|
4819
|
+
publish();
|
|
4820
|
+
return { bound: true };
|
|
4821
|
+
} catch (error) {
|
|
4822
|
+
setRecovery(sourceSessionId, childSessionId, error, target);
|
|
4823
|
+
return { bound: false };
|
|
4824
|
+
}
|
|
4825
|
+
};
|
|
4826
|
+
const bindChild = (sourceSessionId, childSessionId) => {
|
|
4827
|
+
if (disposed || boundChildren.has(childSessionId)) return Promise.resolve({ bound: false });
|
|
4828
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4829
|
+
const current = bindingInFlight.get(key);
|
|
4830
|
+
if (current !== void 0) return current;
|
|
4831
|
+
const promise = attemptBinding(sourceSessionId, childSessionId).finally(() => {
|
|
4832
|
+
if (bindingInFlight.get(key) === promise) bindingInFlight.delete(key);
|
|
4833
|
+
});
|
|
4834
|
+
bindingInFlight.set(key, promise);
|
|
4835
|
+
return promise;
|
|
4836
|
+
};
|
|
4837
|
+
const reconcileNow = async () => {
|
|
4838
|
+
if (disposed || options.sessions === void 0) return;
|
|
4839
|
+
const snapshot = options.sessions.getSnapshot();
|
|
4840
|
+
if (snapshot.phase === "pending") return;
|
|
4841
|
+
if (!Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null) return;
|
|
4842
|
+
const candidates = snapshot.ids.flatMap((childSessionId) => {
|
|
4843
|
+
const summary = snapshot.byId[childSessionId];
|
|
4844
|
+
if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
|
|
4845
|
+
return [{
|
|
4846
|
+
childSessionId,
|
|
4847
|
+
sourceSessionId: summary.parentId
|
|
4848
|
+
}];
|
|
4849
|
+
});
|
|
4850
|
+
await Promise.all(candidates.map(({ childSessionId, sourceSessionId }) => bindChild(sourceSessionId, childSessionId).then(() => void 0)));
|
|
4851
|
+
};
|
|
4852
|
+
const reconcile = () => {
|
|
4853
|
+
if (reconciliationInFlight !== void 0) {
|
|
4854
|
+
reconciliationAgain = true;
|
|
4855
|
+
return reconciliationInFlight;
|
|
4856
|
+
}
|
|
4857
|
+
const run = async () => {
|
|
4858
|
+
do {
|
|
4859
|
+
reconciliationAgain = false;
|
|
4860
|
+
await reconcileNow();
|
|
4861
|
+
} while (!disposed && reconciliationAgain);
|
|
4862
|
+
};
|
|
4863
|
+
const promise = run().finally(() => {
|
|
4864
|
+
if (reconciliationInFlight === promise) reconciliationInFlight = void 0;
|
|
4865
|
+
});
|
|
4866
|
+
reconciliationInFlight = promise;
|
|
4867
|
+
return promise;
|
|
4868
|
+
};
|
|
4869
|
+
return {
|
|
4870
|
+
recovery: {
|
|
4871
|
+
getSnapshot() {
|
|
4872
|
+
return recoverySnapshot;
|
|
4873
|
+
},
|
|
4874
|
+
subscribe(listener) {
|
|
4875
|
+
subscribers.add(listener);
|
|
4876
|
+
return () => subscribers.delete(listener);
|
|
4877
|
+
}
|
|
4878
|
+
},
|
|
4879
|
+
async fork(input) {
|
|
4880
|
+
const childSessionId = await options.fork(input);
|
|
4881
|
+
if (!disposed) await bindChild(input.sessionId, childSessionId);
|
|
4882
|
+
return childSessionId;
|
|
4883
|
+
},
|
|
4884
|
+
reconcile,
|
|
4885
|
+
async retry(key) {
|
|
4886
|
+
const item = pending.get(key);
|
|
4887
|
+
if (item === void 0 || disposed) return false;
|
|
4888
|
+
return (await bindChild(item.sourceSessionId, item.childSessionId)).bound;
|
|
4889
|
+
},
|
|
4890
|
+
dispose() {
|
|
4891
|
+
disposed = true;
|
|
4892
|
+
bindingInFlight.clear();
|
|
4893
|
+
subscribers.clear();
|
|
4894
|
+
}
|
|
4895
|
+
};
|
|
4896
|
+
}
|
|
4897
|
+
//#endregion
|
|
3652
4898
|
//#region lib/client/entry.js
|
|
3653
4899
|
/** Required DSH Client services; Connection is the sole Worktree wire dependency. */
|
|
3654
4900
|
const inject = [
|
|
@@ -3663,11 +4909,22 @@ window.__ModuleLoader__.load({
|
|
|
3663
4909
|
* with that fiber, so slot consumers share one manager and one request lifetime.
|
|
3664
4910
|
*/
|
|
3665
4911
|
function apply(ctx) {
|
|
4912
|
+
if (typeof document !== "undefined") ctx.effect(() => installWorktreePermissionIcon(document), "clutch-dsh-worktree: permission icon cleanup");
|
|
3666
4913
|
ctx.effect(() => ctx.locale.register(WORKTREE_NS, {
|
|
3667
4914
|
zh,
|
|
3668
4915
|
en
|
|
3669
4916
|
}), "clutch-dsh-worktree: locale dictionaries");
|
|
3670
4917
|
const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
|
|
4918
|
+
const fullAccessConfirmation = createWorktreeFullAccessConfirmationController();
|
|
4919
|
+
const permissionNotice = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(void 0);
|
|
4920
|
+
const permissionManager = typeof document !== "undefined" ? manager : void 0;
|
|
4921
|
+
const reportPermissionNotice = (input, result) => {
|
|
4922
|
+
const visible = result.status === "fallback-workspace-write" || result.status === "user-restricted" || result.status === "unverified";
|
|
4923
|
+
permissionNotice.set(visible ? {
|
|
4924
|
+
...input,
|
|
4925
|
+
result
|
|
4926
|
+
} : void 0);
|
|
4927
|
+
};
|
|
3671
4928
|
const sessions = ctx.sessions;
|
|
3672
4929
|
const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
|
|
3673
4930
|
const contextProjection = createWorktreeContextProjection({
|
|
@@ -3677,11 +4934,14 @@ window.__ModuleLoader__.load({
|
|
|
3677
4934
|
storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
|
|
3678
4935
|
});
|
|
3679
4936
|
ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
|
|
4937
|
+
ctx.effect(() => () => fullAccessConfirmation.dispose(), "clutch-dsh-worktree: Full Access confirmation cleanup");
|
|
3680
4938
|
ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
|
|
3681
4939
|
ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
|
|
3682
4940
|
contextProjection.refresh();
|
|
3683
4941
|
const viewStore = createWorktreeViewStore();
|
|
3684
4942
|
const expandState = createWorktreeExpandStateStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
|
|
4943
|
+
const sessionOrder = createWorktreeSessionOrderStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
|
|
4944
|
+
ctx.effect(() => () => sessionOrder.dispose(), "clutch-dsh-worktree: Session order cleanup");
|
|
3685
4945
|
const ensureSessionWorkspace = (workspaceId, sessionId) => {
|
|
3686
4946
|
virtualWorkspaceMembership.ensure({
|
|
3687
4947
|
workspaceId,
|
|
@@ -3691,12 +4951,48 @@ window.__ModuleLoader__.load({
|
|
|
3691
4951
|
const syncSessionWorkspaces = (bindings) => {
|
|
3692
4952
|
virtualWorkspaceMembership.sync(bindings);
|
|
3693
4953
|
};
|
|
4954
|
+
const forkableSessions = ctx.sessions;
|
|
4955
|
+
const nativeFork = forkableSessions.fork;
|
|
4956
|
+
const findWorktreeSessionBinding = async (sessionId) => {
|
|
4957
|
+
const workspaceIds = ctx.workspaces.list.getSnapshot().items.map((workspace) => workspace.workspaceId);
|
|
4958
|
+
const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
|
|
4959
|
+
return (await manager.listBindings({ workspaceId })).find((binding) => binding.sessionId === sessionId && binding.status === "active");
|
|
4960
|
+
}));
|
|
4961
|
+
const found = results.find((result) => result.status === "fulfilled" && result.value !== void 0);
|
|
4962
|
+
if (found !== void 0) return found.value;
|
|
4963
|
+
const failed = results.find((result) => result.status === "rejected");
|
|
4964
|
+
if (failed !== void 0) throw failed.reason;
|
|
4965
|
+
};
|
|
4966
|
+
const forkCoordinator = typeof nativeFork !== "function" ? void 0 : createWorktreeSessionForkCoordinator({
|
|
4967
|
+
fork: (input) => nativeFork.call(ctx.sessions, input),
|
|
4968
|
+
findBinding: findWorktreeSessionBinding,
|
|
4969
|
+
bindSession: (input) => manager.bindSession(input),
|
|
4970
|
+
sessions: ctx.sessions.list
|
|
4971
|
+
});
|
|
4972
|
+
if (forkCoordinator !== void 0) {
|
|
4973
|
+
forkableSessions.fork = (input) => forkCoordinator.fork(input);
|
|
4974
|
+
const reconcileForkChildren = () => {
|
|
4975
|
+
forkCoordinator.reconcile();
|
|
4976
|
+
};
|
|
4977
|
+
const unsubscribeSessionList = ctx.sessions.list.subscribe(reconcileForkChildren);
|
|
4978
|
+
const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildren);
|
|
4979
|
+
ctx.effect(() => () => {
|
|
4980
|
+
unsubscribeSessionList();
|
|
4981
|
+
unsubscribeWorkspaceList();
|
|
4982
|
+
forkCoordinator.dispose();
|
|
4983
|
+
forkableSessions.fork = nativeFork;
|
|
4984
|
+
}, "clutch-dsh-worktree: Session fork cleanup");
|
|
4985
|
+
forkCoordinator.reconcile();
|
|
4986
|
+
}
|
|
3694
4987
|
const worktreeSessionConnector = createWorktreeSessionConnector({
|
|
3695
4988
|
manager,
|
|
3696
4989
|
sessions: ctx.sessions.list,
|
|
3697
4990
|
archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
|
|
3698
4991
|
createSession: async (input) => String(await sessions.create(input)),
|
|
3699
4992
|
ensureSessionWorkspace,
|
|
4993
|
+
permission: permissionManager,
|
|
4994
|
+
confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
|
|
4995
|
+
onPermissionResult: reportPermissionNotice,
|
|
3700
4996
|
openSession: (sessionId) => {
|
|
3701
4997
|
ctx.sessions.open(sessionId);
|
|
3702
4998
|
}
|
|
@@ -3724,8 +5020,15 @@ window.__ModuleLoader__.load({
|
|
|
3724
5020
|
inject: () => ({
|
|
3725
5021
|
available: true,
|
|
3726
5022
|
expandState,
|
|
5023
|
+
sessionOrder,
|
|
3727
5024
|
hooks: { worktreeContext: contextProjection.store },
|
|
3728
5025
|
manager,
|
|
5026
|
+
permission: permissionManager,
|
|
5027
|
+
confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
|
|
5028
|
+
fullAccessConfirmation: typeof document === "undefined" ? void 0 : fullAccessConfirmation,
|
|
5029
|
+
onPermissionResult: reportPermissionNotice,
|
|
5030
|
+
onPermissionNotice: reportPermissionNotice,
|
|
5031
|
+
permissionNotice,
|
|
3729
5032
|
createWorkspace: async () => {
|
|
3730
5033
|
const workspacePath = await ctx.workspaces.pickDirectory();
|
|
3731
5034
|
if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
|
|
@@ -3759,6 +5062,7 @@ window.__ModuleLoader__.load({
|
|
|
3759
5062
|
if (!result.ok) throw new Error(result.error.message);
|
|
3760
5063
|
},
|
|
3761
5064
|
forkSession: (sessionId) => {
|
|
5065
|
+
if (forkableSessions.fork === void 0) return;
|
|
3762
5066
|
ctx.sessions.fork({
|
|
3763
5067
|
sessionId,
|
|
3764
5068
|
increaseTitle: true
|
|
@@ -3769,6 +5073,10 @@ window.__ModuleLoader__.load({
|
|
|
3769
5073
|
archiveSession: (sessionId) => ctx.workspaces.archiveSession(sessionId),
|
|
3770
5074
|
ensureSessionWorkspace,
|
|
3771
5075
|
syncSessionWorkspaces,
|
|
5076
|
+
forkRecovery: forkCoordinator?.recovery,
|
|
5077
|
+
retryForkSession: forkCoordinator === void 0 ? void 0 : async (key) => {
|
|
5078
|
+
await forkCoordinator.retry(key);
|
|
5079
|
+
},
|
|
3772
5080
|
openSession: (sessionId) => {
|
|
3773
5081
|
ctx.sessions.open(sessionId);
|
|
3774
5082
|
}
|