@cerbur/clutch-dsh-worktree 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -24
- package/README.zh.md +141 -19
- 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/WorktreeHeroContext.d.ts +1 -1
- package/lib/client/WorktreeHeroContext.js +1 -1
- package/lib/client/WorktreeSurface.d.ts +2 -2
- package/lib/client/WorktreeSurface.d.ts.map +1 -1
- package/lib/client/WorktreeSurface.js +592 -124
- package/lib/client/WorktreeSurface.js.map +1 -1
- package/lib/client/entry.d.ts.map +1 -1
- package/lib/client/entry.js +87 -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 +82 -0
- package/lib/client/locales.d.ts.map +1 -1
- package/lib/client/locales.js +84 -2
- 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/virtual-workspace-membership.js +1 -1
- package/lib/client/virtual-workspace-membership.js.map +1 -1
- package/lib/client/worktree-connection.d.ts +6 -2
- package/lib/client/worktree-connection.d.ts.map +1 -1
- package/lib/client/worktree-connection.js +8 -0
- package/lib/client/worktree-connection.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 +22 -0
- package/lib/client/worktree-error-copy.js.map +1 -1
- package/lib/client/worktree-expand-state.d.ts +33 -0
- package/lib/client/worktree-expand-state.d.ts.map +1 -0
- package/lib/client/worktree-expand-state.js +83 -0
- package/lib/client/worktree-expand-state.js.map +1 -0
- 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-position.d.ts +2 -0
- package/lib/client/worktree-session-position.d.ts.map +1 -0
- package/lib/client/worktree-session-position.js +11 -0
- package/lib/client/worktree-session-position.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 +98 -2
- package/lib/client/worktree-session.js.map +1 -1
- package/lib/client/worktree-surface-dialogs.d.ts +1 -1
- package/lib/client/worktree-surface-dialogs.d.ts.map +1 -1
- package/lib/client/worktree-surface-dialogs.js +30 -13
- package/lib/client/worktree-surface-dialogs.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 +132 -47
- package/lib/client/worktree-surface-rows.js.map +1 -1
- package/lib/client/worktree-surface-selectors.d.ts +18 -0
- package/lib/client/worktree-surface-selectors.d.ts.map +1 -1
- package/lib/client/worktree-surface-selectors.js +62 -0
- package/lib/client/worktree-surface-selectors.js.map +1 -1
- package/lib/client/worktree-surface-types.d.ts +73 -3
- package/lib/client/worktree-surface-types.d.ts.map +1 -1
- package/lib/client/worktree-view-actions.d.ts +11 -3
- package/lib/client/worktree-view-actions.d.ts.map +1 -1
- package/lib/client/worktree-view-actions.js +31 -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/worktree-view-read.d.ts +8 -0
- package/lib/client/worktree-view-read.d.ts.map +1 -1
- package/lib/client/worktree-view-read.js +19 -0
- package/lib/client/worktree-view-read.js.map +1 -1
- package/lib/client.js +2047 -264
- package/lib/client.js.map +1 -1
- package/lib/contract/index.contract.js +16 -0
- package/lib/contract/index.contract.js.map +1 -1
- package/lib/contract/index.d.ts +26 -2
- 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/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 +9 -1
- package/lib/host/remote.js.map +1 -1
- package/lib/host/service.d.ts +10 -1
- package/lib/host/service.d.ts.map +1 -1
- package/lib/host/service.js +48 -2
- 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 +111 -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 +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/manage/manager-support.d.ts +2 -0
- package/lib/manage/manager-support.d.ts.map +1 -1
- package/lib/manage/manager-support.js +9 -0
- package/lib/manage/manager-support.js.map +1 -1
- package/lib/manage/manager-worktrees.d.ts +10 -1
- package/lib/manage/manager-worktrees.d.ts.map +1 -1
- package/lib/manage/manager-worktrees.js +121 -5
- package/lib/manage/manager-worktrees.js.map +1 -1
- package/lib/manage/manager.d.ts +8 -1
- package/lib/manage/manager.d.ts.map +1 -1
- package/lib/manage/manager.js +7 -1
- package/lib/manage/manager.js.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 +2 -0
- package/lib/provider/git.d.ts.map +1 -1
- package/lib/provider/git.js +23 -1
- package/lib/provider/git.js.map +1 -1
- package/lib/provider/index.d.ts +1 -1
- package/lib/provider/index.d.ts.map +1 -1
- package/lib/provider/index.js +1 -1
- package/lib/provider/index.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 +33 -37
- package/lib/provider/sidecar-schema.js.map +1 -1
- package/lib/provider/sidecar.d.ts.map +1 -1
- package/lib/provider/sidecar.js +3 -1
- package/lib/provider/sidecar.js.map +1 -1
- package/lib/provider/types.d.ts +9 -1
- package/lib/provider/types.d.ts.map +1 -1
- package/lib/provider/types.js +2 -1
- package/lib/provider/types.js.map +1 -1
- package/lib/typert.host.js +214 -21
- package/lib/typert.remote-client.d.ts +9 -1
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +214 -21
- package/package.json +30 -30
package/lib/client.js
CHANGED
|
@@ -40,12 +40,22 @@ window.__ModuleLoader__.load({
|
|
|
40
40
|
"worktree.expand": "展开 {name}",
|
|
41
41
|
"worktree.collapse": "收起 {name}",
|
|
42
42
|
"worktree.options": "Worktree 选项:{name}",
|
|
43
|
+
"worktree.copyPath": "复制路径",
|
|
44
|
+
"worktree.createNew": "创建新的 Worktree",
|
|
43
45
|
"worktree.remove": "移除 Worktree",
|
|
44
46
|
"worktree.removeDescription": "移除“{name}”?Session 会保留在 DSH 中,并作为已分离关系继续可用。",
|
|
47
|
+
"worktree.removeExternalDescription": "移除“{name}”?这会删除关联的外部 Worktree 目录。Session 会保留在 DSH 中,并作为已分离关系继续可用。",
|
|
45
48
|
"worktree.addSession": "向 {name} 添加会话",
|
|
46
49
|
"worktree.noWorktrees": "暂无 Worktree",
|
|
47
50
|
"worktree.createTitle": "新建 Worktree",
|
|
48
51
|
"worktree.createDescription": "“{name}” · Worktree 路径由 DSH 管理。",
|
|
52
|
+
"worktree.tabCreate": "创建",
|
|
53
|
+
"worktree.tabImport": "导入",
|
|
54
|
+
"worktree.importDescription": "向“{name}”注册已有的 Worktree。注册不会移动目录;之后移除会删除关联的 Worktree 目录。",
|
|
55
|
+
"worktree.importLoading": "正在查找可导入的 Worktree…",
|
|
56
|
+
"worktree.importEmpty": "没有可导入的 Worktree。",
|
|
57
|
+
"worktree.importPlaceholder": "请选择要导入的 Worktree",
|
|
58
|
+
"worktree.importSelected": "已选择",
|
|
49
59
|
"worktree.baseBranch": "Worktree 基线分支",
|
|
50
60
|
"worktree.noLocalBranch": "没有本地分支",
|
|
51
61
|
"worktree.noBranches": "此工作区中没有找到本地分支。",
|
|
@@ -56,6 +66,7 @@ window.__ModuleLoader__.load({
|
|
|
56
66
|
"worktree.setup.commands": "可复制的命令",
|
|
57
67
|
"worktree.name": "Worktree 名称",
|
|
58
68
|
"worktree.create": "创建 Worktree",
|
|
69
|
+
"worktree.import": "导入 Worktree",
|
|
59
70
|
"session.options": "会话选项:{name}",
|
|
60
71
|
"session.new": "新会话",
|
|
61
72
|
"session.rename": "重命名会话",
|
|
@@ -64,6 +75,23 @@ window.__ModuleLoader__.load({
|
|
|
64
75
|
"session.expandMore": "展开其余 {count} 个会话",
|
|
65
76
|
"session.collapse": "收起",
|
|
66
77
|
"session.name": "会话名称",
|
|
78
|
+
"session.status.running": "进行中",
|
|
79
|
+
"session.status.subagentsRunning.one": "{n} 个子代理运行中",
|
|
80
|
+
"session.status.subagentsRunning.other": "{n} 个子代理运行中",
|
|
81
|
+
"session.status.idle": "空闲",
|
|
82
|
+
"session.status.waitingApproval": "等待审批",
|
|
83
|
+
"session.status.planReview": "计划待审",
|
|
84
|
+
"session.status.waitingAnswer": "等待回答",
|
|
85
|
+
"session.status.completed": "已完成",
|
|
86
|
+
copy: "复制",
|
|
87
|
+
"hover.copied": "已复制",
|
|
88
|
+
"session.time.now": "刚刚",
|
|
89
|
+
"session.time.minutes": "{n}分钟",
|
|
90
|
+
"session.time.hours": "{n}小时",
|
|
91
|
+
"session.time.days": "{n}天",
|
|
92
|
+
"session.time.months": "{n}个月",
|
|
93
|
+
"session.time.years": "{n}年",
|
|
94
|
+
"session.time.ago": "{t}前",
|
|
67
95
|
"dialog.close": "关闭",
|
|
68
96
|
"dialog.closeWorkspaceRename": "关闭重命名工作区对话框",
|
|
69
97
|
"dialog.closeWorkspaceDelete": "关闭删除工作区对话框",
|
|
@@ -75,6 +103,14 @@ window.__ModuleLoader__.load({
|
|
|
75
103
|
"action.retry": "重试",
|
|
76
104
|
"action.retryBinding": "重试绑定",
|
|
77
105
|
"action.openCreatedSession": "打开已创建的 Session",
|
|
106
|
+
"permission.fallbackWorkspaceWrite": "无法使用 Worktree 完全访问预设,已降级为 workspace-write;保留审批提示。",
|
|
107
|
+
"permission.userRestricted": "已保留你在 DSH 原生权限界面选择的限制,未自动提升此 Worktree Session。",
|
|
108
|
+
"permission.unverified": "无法验证 Worktree Session 的权限服务;Session 已保留,但完全访问未得到确认。",
|
|
109
|
+
"permission.unavailable": "Worktree Session 权限状态暂时不可用,请重试。",
|
|
110
|
+
"permission.fullAccessTitle": "确认启用 Worktree Full access?",
|
|
111
|
+
"permission.fullAccessDescription": "启用 Worktree Full access 后,此 Session 可能访问 Session 目录之外的关联 Git 元数据和 Worktree 文件。完全访问会关闭此 Session 的文件系统沙箱,但会保留审批提示;网络和进程策略不变。目标 Worktree:{cwd}",
|
|
112
|
+
"permission.fullAccessAcknowledge": "我已了解风险,并愿意继续",
|
|
113
|
+
"permission.fullAccessEnable": "启用 Worktree Full access",
|
|
78
114
|
"status.loading": "正在加载工作区…",
|
|
79
115
|
"error.worktreeDataUnavailable": "Worktree 数据不可用,请重试。",
|
|
80
116
|
"error.gitNotInstalled": "Git 未安装或不可用,请安装 Git 后重试。",
|
|
@@ -86,12 +122,17 @@ window.__ModuleLoader__.load({
|
|
|
86
122
|
"error.worktreeOrderingUnavailable": "Worktree 排序不可用,请重新连接后重试。",
|
|
87
123
|
"error.worktreeCreatedSessionUnavailable": "Worktree 已创建,但 Session 创建不可用,请重新连接后重试。",
|
|
88
124
|
"error.sessionCreationUnavailable": "Session 创建不可用,请重新连接后重试。",
|
|
89
|
-
"error.worktreeRecordMissing": "Worktree
|
|
125
|
+
"error.worktreeRecordMissing": "Worktree 注册未返回 Worktree 记录,请重试请求。",
|
|
126
|
+
"error.worktreeImportInvalid": "这个 Worktree 无法导入,请选择同一 Workspace 中有效的绝对路径。",
|
|
127
|
+
"error.worktreeAlreadyManaged": "这个 Worktree 已由插件管理。",
|
|
128
|
+
"error.worktreeRegistrationSessionUnavailable": "Worktree 已注册,但 Session 创建不可用,请重新连接后重试。",
|
|
90
129
|
"error.workspaceRenameUnavailable": "工作区重命名不可用,请重新连接后重试。",
|
|
91
130
|
"error.workspaceDeleteUnavailable": "工作区删除不可用,请重新连接后重试。",
|
|
92
131
|
"error.sessionRenameUnavailable": "会话重命名不可用,请重新连接后重试。",
|
|
93
132
|
"error.sessionBindingFailed": "Session {sessionId} 已创建,但 Worktree 绑定失败:{reason}",
|
|
94
133
|
"error.sessionAlreadyBound": "Session 已绑定到其他 Worktree,未创建新的 Session。",
|
|
134
|
+
"error.worktreePermissionConfirmationRequired": "Session 和绑定已保留;确认完全访问后重试,未打开 Session。",
|
|
135
|
+
"error.worktreePermissionFailed": "Worktree Session 权限设置失败,可重试:{reason}",
|
|
95
136
|
"error.sessionListNotReady": "Session 列表尚未就绪,请重试。",
|
|
96
137
|
"error.sessionFactsIncomplete": "Session 信息尚未完整,请重试。",
|
|
97
138
|
"error.worktreeSessionRepairRequired": "当前 Worktree 的 Session 绑定需要修复,请重试。",
|
|
@@ -130,12 +171,22 @@ window.__ModuleLoader__.load({
|
|
|
130
171
|
"worktree.expand": "Expand {name}",
|
|
131
172
|
"worktree.collapse": "Collapse {name}",
|
|
132
173
|
"worktree.options": "Worktree options for {name}",
|
|
174
|
+
"worktree.copyPath": "Copy path",
|
|
175
|
+
"worktree.createNew": "Create new Worktree",
|
|
133
176
|
"worktree.remove": "Remove Worktree",
|
|
134
177
|
"worktree.removeDescription": "Remove {name}? Sessions stay in DSH and remain available as detached bindings.",
|
|
178
|
+
"worktree.removeExternalDescription": "Remove {name}? This deletes the linked external Worktree directory. Sessions stay in DSH and remain available as detached bindings.",
|
|
135
179
|
"worktree.addSession": "Add Session to {name}",
|
|
136
180
|
"worktree.noWorktrees": "No Worktrees",
|
|
137
181
|
"worktree.createTitle": "New Worktree",
|
|
138
182
|
"worktree.createDescription": "{name} · the Worktree path is managed by DSH.",
|
|
183
|
+
"worktree.tabCreate": "Create",
|
|
184
|
+
"worktree.tabImport": "Import",
|
|
185
|
+
"worktree.importDescription": "Register an existing Worktree for {name}. Registration leaves the directory in place; removing it later deletes the linked Worktree directory.",
|
|
186
|
+
"worktree.importLoading": "Finding importable Worktrees…",
|
|
187
|
+
"worktree.importEmpty": "No importable Worktrees found.",
|
|
188
|
+
"worktree.importPlaceholder": "Select a Worktree to import",
|
|
189
|
+
"worktree.importSelected": "Selected",
|
|
139
190
|
"worktree.baseBranch": "Worktree base branch",
|
|
140
191
|
"worktree.noLocalBranch": "No local branch",
|
|
141
192
|
"worktree.noBranches": "No local branches found in this Workspace.",
|
|
@@ -146,6 +197,7 @@ window.__ModuleLoader__.load({
|
|
|
146
197
|
"worktree.setup.commands": "Copyable commands",
|
|
147
198
|
"worktree.name": "Worktree name",
|
|
148
199
|
"worktree.create": "Create Worktree",
|
|
200
|
+
"worktree.import": "Import Worktree",
|
|
149
201
|
"session.options": "Session options for {name}",
|
|
150
202
|
"session.new": "New Session",
|
|
151
203
|
"session.rename": "Rename session",
|
|
@@ -154,6 +206,23 @@ window.__ModuleLoader__.load({
|
|
|
154
206
|
"session.expandMore": "Expand {count} more",
|
|
155
207
|
"session.collapse": "Collapse",
|
|
156
208
|
"session.name": "Session name",
|
|
209
|
+
"session.status.running": "Running",
|
|
210
|
+
"session.status.subagentsRunning.one": "{n} subagent running",
|
|
211
|
+
"session.status.subagentsRunning.other": "{n} subagents running",
|
|
212
|
+
"session.status.idle": "Idle",
|
|
213
|
+
"session.status.waitingApproval": "Waiting for approval",
|
|
214
|
+
"session.status.planReview": "Plan awaiting review",
|
|
215
|
+
"session.status.waitingAnswer": "Waiting for answer",
|
|
216
|
+
"session.status.completed": "Completed",
|
|
217
|
+
copy: "Copy",
|
|
218
|
+
"hover.copied": "Copied",
|
|
219
|
+
"session.time.now": "now",
|
|
220
|
+
"session.time.minutes": "{n}min",
|
|
221
|
+
"session.time.hours": "{n}h",
|
|
222
|
+
"session.time.days": "{n}d",
|
|
223
|
+
"session.time.months": "{n}mo",
|
|
224
|
+
"session.time.years": "{n}y",
|
|
225
|
+
"session.time.ago": "{t} ago",
|
|
157
226
|
"dialog.close": "Close",
|
|
158
227
|
"dialog.closeWorkspaceRename": "Close Rename Workspace dialog",
|
|
159
228
|
"dialog.closeWorkspaceDelete": "Close Delete Workspace dialog",
|
|
@@ -165,6 +234,14 @@ window.__ModuleLoader__.load({
|
|
|
165
234
|
"action.retry": "Retry",
|
|
166
235
|
"action.retryBinding": "Retry Binding",
|
|
167
236
|
"action.openCreatedSession": "Open Created Session",
|
|
237
|
+
"permission.fallbackWorkspaceWrite": "The Worktree Full Access preset is unavailable; fell back to workspace-write with approval prompts enabled.",
|
|
238
|
+
"permission.userRestricted": "The restriction selected in DSH’s native permission UI was preserved; this Worktree Session was not elevated.",
|
|
239
|
+
"permission.unverified": "The Worktree Session permission service could not be verified; the Session was retained, but Full Access is not confirmed.",
|
|
240
|
+
"permission.unavailable": "The Worktree Session permission state is temporarily unavailable; retry the request.",
|
|
241
|
+
"permission.fullAccessTitle": "Enable Worktree Full access?",
|
|
242
|
+
"permission.fullAccessDescription": "Worktree Full access lets this Session access linked Git metadata and Worktree files outside the Session directory. It disables filesystem confinement for this Session while keeping approval prompts enabled; network and process policy are unchanged. Target Worktree: {cwd}",
|
|
243
|
+
"permission.fullAccessAcknowledge": "I understand the risks and want to continue",
|
|
244
|
+
"permission.fullAccessEnable": "Enable Worktree Full access",
|
|
168
245
|
"status.loading": "Loading Workspaces…",
|
|
169
246
|
"error.worktreeDataUnavailable": "Worktree data is unavailable. Retry the request.",
|
|
170
247
|
"error.gitNotInstalled": "Git is not installed or unavailable. Install Git and retry.",
|
|
@@ -176,12 +253,17 @@ window.__ModuleLoader__.load({
|
|
|
176
253
|
"error.worktreeOrderingUnavailable": "Worktree ordering is unavailable; retry after reconnecting.",
|
|
177
254
|
"error.worktreeCreatedSessionUnavailable": "Worktree created, but Session creation is unavailable; retry after reconnecting.",
|
|
178
255
|
"error.sessionCreationUnavailable": "Session creation is unavailable; retry after reconnecting.",
|
|
179
|
-
"error.worktreeRecordMissing": "Worktree
|
|
256
|
+
"error.worktreeRecordMissing": "Worktree registration returned no Worktree record; retry the request.",
|
|
257
|
+
"error.worktreeImportInvalid": "This Worktree cannot be imported. Choose a valid absolute path in this Workspace.",
|
|
258
|
+
"error.worktreeAlreadyManaged": "This Worktree is already managed by the plugin.",
|
|
259
|
+
"error.worktreeRegistrationSessionUnavailable": "The Worktree was registered, but Session creation is unavailable; retry after reconnecting.",
|
|
180
260
|
"error.workspaceRenameUnavailable": "Workspace rename is unavailable; retry after reconnecting.",
|
|
181
261
|
"error.workspaceDeleteUnavailable": "Workspace delete is unavailable; retry after reconnecting.",
|
|
182
262
|
"error.sessionRenameUnavailable": "Session rename is unavailable; retry after reconnecting.",
|
|
183
263
|
"error.sessionBindingFailed": "Session {sessionId} was created, but Worktree binding failed: {reason}",
|
|
184
264
|
"error.sessionAlreadyBound": "The Session is already bound to another Worktree; no new Session was created.",
|
|
265
|
+
"error.worktreePermissionConfirmationRequired": "The Session and binding were retained; confirm Full Access and retry. The Session was not opened.",
|
|
266
|
+
"error.worktreePermissionFailed": "Worktree Session permission setup failed; retryable error: {reason}",
|
|
185
267
|
"error.sessionListNotReady": "The Session list is not ready yet; retry the request.",
|
|
186
268
|
"error.sessionFactsIncomplete": "Session facts are incomplete; retry the request.",
|
|
187
269
|
"error.worktreeSessionRepairRequired": "The current Worktree Session binding needs repair; retry the request.",
|
|
@@ -200,12 +282,16 @@ window.__ModuleLoader__.load({
|
|
|
200
282
|
*/
|
|
201
283
|
const WORKTREE_CONNECTION_ENDPOINTS = Object.freeze({
|
|
202
284
|
listWorktrees: "worktreeManager/listWorktrees",
|
|
285
|
+
listImportCandidates: "worktreeManager/listImportCandidates",
|
|
203
286
|
listBranches: "worktreeManager/listBranches",
|
|
204
287
|
createWorktree: "worktreeManager/createWorktree",
|
|
288
|
+
importWorktree: "worktreeManager/importWorktree",
|
|
205
289
|
removeWorktree: "worktreeManager/removeWorktree",
|
|
206
290
|
insertWorktreeBefore: "worktreeManager/insertWorktreeBefore",
|
|
207
291
|
listBindings: "worktreeManager/listBindings",
|
|
208
|
-
bindSession: "worktreeManager/bindSession"
|
|
292
|
+
bindSession: "worktreeManager/bindSession",
|
|
293
|
+
ensureWorktreePermission: "worktreeManager/ensureWorktreePermission",
|
|
294
|
+
normalizeDetachedWorktreePermissions: "worktreeManager/normalizeDetachedWorktreePermissions"
|
|
209
295
|
});
|
|
210
296
|
/** Browser-safe error shared by transport, Gateway, endpoint and domain failures. */
|
|
211
297
|
var WorktreeConnectionError = class extends Error {
|
|
@@ -220,14 +306,14 @@ window.__ModuleLoader__.load({
|
|
|
220
306
|
this.retryable = options.retryable;
|
|
221
307
|
}
|
|
222
308
|
};
|
|
223
|
-
function isRecord(value) {
|
|
309
|
+
function isRecord$2(value) {
|
|
224
310
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
225
311
|
}
|
|
226
312
|
function isWorktreeError(value) {
|
|
227
|
-
return isRecord(value) && typeof value.code === "string" && typeof value.message === "string" && isRecord(value.details);
|
|
313
|
+
return isRecord$2(value) && typeof value.code === "string" && typeof value.message === "string" && isRecord$2(value.details);
|
|
228
314
|
}
|
|
229
315
|
function isWorktreeRemoteResult(value) {
|
|
230
|
-
if (!isRecord(value) || typeof value.ok !== "boolean") return false;
|
|
316
|
+
if (!isRecord$2(value) || typeof value.ok !== "boolean") return false;
|
|
231
317
|
return value.ok || isWorktreeError(value.error) && value.error.details !== void 0;
|
|
232
318
|
}
|
|
233
319
|
function disposedError() {
|
|
@@ -248,7 +334,7 @@ window.__ModuleLoader__.load({
|
|
|
248
334
|
});
|
|
249
335
|
}
|
|
250
336
|
function gatewayFailure(endpoint, result) {
|
|
251
|
-
const rawDetails = isRecord(result.error.details) ? result.error.details : {};
|
|
337
|
+
const rawDetails = isRecord$2(result.error.details) ? result.error.details : {};
|
|
252
338
|
throw new WorktreeConnectionError({
|
|
253
339
|
code: result.error.code,
|
|
254
340
|
message: result.error.message,
|
|
@@ -305,8 +391,10 @@ window.__ModuleLoader__.load({
|
|
|
305
391
|
}
|
|
306
392
|
return {
|
|
307
393
|
listWorktrees: (input) => invoke("listWorktrees", input),
|
|
394
|
+
listImportCandidates: (input) => invoke("listImportCandidates", input),
|
|
308
395
|
listBranches: (input) => invoke("listBranches", input),
|
|
309
396
|
createWorktree: (input) => invoke("createWorktree", input),
|
|
397
|
+
importWorktree: (input) => invoke("importWorktree", input),
|
|
310
398
|
async removeWorktree(input) {
|
|
311
399
|
await invoke("removeWorktree", input);
|
|
312
400
|
},
|
|
@@ -315,6 +403,8 @@ window.__ModuleLoader__.load({
|
|
|
315
403
|
},
|
|
316
404
|
listBindings: (input) => invoke("listBindings", input),
|
|
317
405
|
bindSession: (input) => invoke("bindSession", input),
|
|
406
|
+
ensureWorktreePermission: (input) => invoke("ensureWorktreePermission", input),
|
|
407
|
+
normalizeDetachedWorktreePermissions: (input) => invoke("normalizeDetachedWorktreePermissions", input),
|
|
318
408
|
dispose() {
|
|
319
409
|
if (disposed) return;
|
|
320
410
|
disposed = true;
|
|
@@ -324,7 +414,7 @@ window.__ModuleLoader__.load({
|
|
|
324
414
|
};
|
|
325
415
|
}
|
|
326
416
|
//#endregion
|
|
327
|
-
//#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.
|
|
417
|
+
//#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
|
|
328
418
|
const css$1 = ".-cerbur-clutch-dsh-worktree-headerContext {\n display: inline-flex;\n min-width: 0;\n height: 22px;\n align-items: center;\n gap: 4px;\n max-width: 180px;\n overflow: hidden;\n border-radius: 6px;\n padding: 0 2px 0 0;\n background: var(--dsw-alias-fill-tsp-secondary);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 22px;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-contextIcon {\n flex: none;\n opacity: 0.7;\n}\n\n.-cerbur-clutch-dsh-worktree-contextLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-contextHoverTitle {\n max-width: 360px;\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContextHost {\n position: absolute;\n z-index: 1;\n display: block;\n width: max-content;\n max-width: 260px;\n min-height: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContext {\n display: inline-flex;\n box-sizing: border-box;\n max-width: 260px;\n min-height: 22px;\n align-items: center;\n overflow: hidden;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n padding: 0 8px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 20px;\n pointer-events: auto;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n";
|
|
329
419
|
const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
|
|
330
420
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
|
|
@@ -347,18 +437,25 @@ window.__ModuleLoader__.load({
|
|
|
347
437
|
function WorktreeContextLabel({ value, t }) {
|
|
348
438
|
if (value.kind === "none") return null;
|
|
349
439
|
const ariaLabel = value.kind === "main" ? t("context.main", { name: value.label }) : t("context.worktree", { name: value.label });
|
|
350
|
-
return (0, react_jsx_runtime.
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
440
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
441
|
+
anchor: (0, react_jsx_runtime.jsxs)("span", {
|
|
442
|
+
className: worktree_context_css_default.headerContext,
|
|
443
|
+
title: value.label,
|
|
444
|
+
"aria-label": ariaLabel,
|
|
445
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {
|
|
446
|
+
size: 14,
|
|
447
|
+
className: worktree_context_css_default.contextIcon,
|
|
448
|
+
"aria-hidden": "true"
|
|
449
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
450
|
+
className: worktree_context_css_default.contextLabel,
|
|
451
|
+
children: value.label
|
|
452
|
+
})]
|
|
453
|
+
}),
|
|
454
|
+
content: (0, react_jsx_runtime.jsx)("div", {
|
|
455
|
+
className: worktree_context_css_default.contextHoverTitle,
|
|
360
456
|
children: value.label
|
|
361
|
-
})
|
|
457
|
+
}),
|
|
458
|
+
openDelayMs: 500
|
|
362
459
|
});
|
|
363
460
|
}
|
|
364
461
|
/** Render the current branch or active Worktree branch beside the Session title. */
|
|
@@ -371,8 +468,8 @@ window.__ModuleLoader__.load({
|
|
|
371
468
|
});
|
|
372
469
|
}
|
|
373
470
|
//#endregion
|
|
374
|
-
//#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.
|
|
375
|
-
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-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 border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 24px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n flex: none;\n align-items: center;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeGuide {\n flex: none;\n width: 20px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
|
|
471
|
+
//#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
|
|
472
|
+
const css = ".-cerbur-clutch-dsh-worktree-action {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n width: calc(100% + 4px);\n height: 42px;\n margin: 4px -2px;\n box-sizing: border-box;\n border: 0;\n border-radius: 12px;\n padding: 0 10px 0 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n text-align: left;\n overflow: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-action:hover,\n.-cerbur-clutch-dsh-worktree-action[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-action[data-collapsed='true'] {\n width: 36px;\n height: 36px;\n margin: 8px 0 10px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border-radius: 50%;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n display: inline-flex;\n min-width: 0;\n align-items: center;\n height: 22px;\n overflow: hidden;\n font-weight: 400;\n line-height: 22px;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-surface {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n min-width: 56px;\n overflow: hidden;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-specific-sidebar-fill);\n color: var(--dsw-alias-label-primary);\n pointer-events: auto;\n transition: width var(--ds-transition-duration-slow) var(--ds-ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .-cerbur-clutch-dsh-worktree-surface {\n transition: none;\n }\n}\n\n.-cerbur-clutch-dsh-worktree-wideContent {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-wideContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTabs {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab {\n border: 0;\n border-bottom: 2px solid transparent;\n padding: 4px 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab[aria-selected='true'] {\n border-bottom-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportCandidates {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect {\n width: 100%;\n min-width: 0;\n padding: 7px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportError {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: none;\n min-height: 44px;\n padding: 6px 10px;\n box-sizing: border-box;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-title {\n min-width: 0;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n flex: none;\n width: 28px;\n height: 28px;\n font-size: 18px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-modeButton[data-active='true'] {\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspacePicker {\n display: block;\n width: calc(100% - 20px);\n margin: 6px 10px 8px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceLabel {\n display: block;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n padding: 0 10px 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-content:focus-visible {\n outline: 2px solid var(--dsw-alias-border-l3);\n outline-offset: -2px;\n}\n\n.-cerbur-clutch-dsh-worktree-error {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-notice {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n width: 100%;\n padding: 6px 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-recoveryActions {\n display: grid;\n gap: 6px;\n margin-top: 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton:disabled,\n.-cerbur-clutch-dsh-worktree-actionButton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.-cerbur-clutch-dsh-worktree-actions {\n display: grid;\n gap: 6px;\n margin-top: 10px;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionSelect {\n min-width: 0;\n padding: 5px 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-section {\n margin: 12px 0 0;\n}\n\n.-cerbur-clutch-dsh-worktree-sectionTitle {\n margin: 0 2px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-empty,\n.-cerbur-clutch-dsh-worktree-message {\n margin: 0;\n padding: 8px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-gitReadiness {\n display: grid;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-commandBlock {\n margin: 6px 0 0;\n padding: 8px;\n overflow-x: auto;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-secondary);\n font:\n 11px/16px ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n white-space: pre-wrap;\n}\n\n.-cerbur-clutch-dsh-worktree-message[data-error='true'] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktree,\n.-cerbur-clutch-dsh-worktree-session {\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 6px 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree {\n cursor: default;\n}\n\n.-cerbur-clutch-dsh-worktree-session {\n cursor: pointer;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree:hover,\n.-cerbur-clutch-dsh-worktree-session:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeLabel,\n.-cerbur-clutch-dsh-worktree-sessionLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-status {\n flex: none;\n margin-left: auto;\n padding-left: 8px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchRow {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchIcon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n min-width: 0;\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n outline: none;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n width: 100%;\n padding: 6px 8px;\n font-size: 13px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput:focus,\n.-cerbur-clutch-dsh-worktree-actionSelect:focus,\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect:focus {\n border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n/* Native Session hover card: full title, relative time, and current status. */\n.-cerbur-clutch-dsh-worktree-sessionHoverContent {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTitle {\n color: #FFFFFF;\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: break-word;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTime {\n color: #CFD3D6;\n font-size: 12px;\n line-height: 16px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverStatus {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #ADB2B8;\n font-size: 12px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-groupActivity {\n position: absolute;\n top: 0;\n right: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n visibility: hidden;\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 16px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: calc(100% - 22px);\n margin-left: 22px;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] .-cerbur-clutch-dsh-worktree-treeSessionContent {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionTrailing {\n position: relative;\n display: inline-flex;\n flex: 0 0 52px;\n align-items: center;\n justify-content: flex-end;\n width: 52px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-rowActions {\n position: absolute;\n inset: 0;\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta {\n color: var(--dsw-alias-label-tertiary);\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionStatus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionTime {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 4px;\n font-size: 12px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-cerbur-clutch-dsh-worktree-sessionMeta {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
|
|
376
473
|
const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
|
|
377
474
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
|
|
378
475
|
const tag = document.createElement("style");
|
|
@@ -386,6 +483,11 @@ window.__ModuleLoader__.load({
|
|
|
386
483
|
"actionLabel": "-cerbur-clutch-dsh-worktree-actionLabel",
|
|
387
484
|
"surface": "-cerbur-clutch-dsh-worktree-surface",
|
|
388
485
|
"wideContent": "-cerbur-clutch-dsh-worktree-wideContent",
|
|
486
|
+
"worktreeModalTabs": "-cerbur-clutch-dsh-worktree-worktreeModalTabs",
|
|
487
|
+
"worktreeModalTab": "-cerbur-clutch-dsh-worktree-worktreeModalTab",
|
|
488
|
+
"worktreeImportCandidates": "-cerbur-clutch-dsh-worktree-worktreeImportCandidates",
|
|
489
|
+
"worktreeImportSelect": "-cerbur-clutch-dsh-worktree-worktreeImportSelect",
|
|
490
|
+
"worktreeImportError": "-cerbur-clutch-dsh-worktree-worktreeImportError",
|
|
389
491
|
"closeButton": "-cerbur-clutch-dsh-worktree-closeButton",
|
|
390
492
|
"header": "-cerbur-clutch-dsh-worktree-header",
|
|
391
493
|
"title": "-cerbur-clutch-dsh-worktree-title",
|
|
@@ -394,6 +496,7 @@ window.__ModuleLoader__.load({
|
|
|
394
496
|
"workspaceLabel": "-cerbur-clutch-dsh-worktree-workspaceLabel",
|
|
395
497
|
"content": "-cerbur-clutch-dsh-worktree-content",
|
|
396
498
|
"error": "-cerbur-clutch-dsh-worktree-error",
|
|
499
|
+
"notice": "-cerbur-clutch-dsh-worktree-notice",
|
|
397
500
|
"retryButton": "-cerbur-clutch-dsh-worktree-retryButton",
|
|
398
501
|
"actionButton": "-cerbur-clutch-dsh-worktree-actionButton",
|
|
399
502
|
"recoveryActions": "-cerbur-clutch-dsh-worktree-recoveryActions",
|
|
@@ -426,9 +529,14 @@ window.__ModuleLoader__.load({
|
|
|
426
529
|
"worktreeState": "-cerbur-clutch-dsh-worktree-worktreeState",
|
|
427
530
|
"workspaceTitle": "-cerbur-clutch-dsh-worktree-workspaceTitle",
|
|
428
531
|
"worktreeHoverTitle": "-cerbur-clutch-dsh-worktree-worktreeHoverTitle",
|
|
532
|
+
"sessionHoverContent": "-cerbur-clutch-dsh-worktree-sessionHoverContent",
|
|
533
|
+
"sessionHoverTitle": "-cerbur-clutch-dsh-worktree-sessionHoverTitle",
|
|
534
|
+
"sessionHoverTime": "-cerbur-clutch-dsh-worktree-sessionHoverTime",
|
|
535
|
+
"sessionHoverStatus": "-cerbur-clutch-dsh-worktree-sessionHoverStatus",
|
|
429
536
|
"treeActionSlot": "-cerbur-clutch-dsh-worktree-treeActionSlot",
|
|
430
537
|
"workspaceActions": "-cerbur-clutch-dsh-worktree-workspaceActions",
|
|
431
538
|
"menuAction": "-cerbur-clutch-dsh-worktree-menuAction",
|
|
539
|
+
"groupActivity": "-cerbur-clutch-dsh-worktree-groupActivity",
|
|
432
540
|
"dropBefore": "-cerbur-clutch-dsh-worktree-dropBefore",
|
|
433
541
|
"dropAfter": "-cerbur-clutch-dsh-worktree-dropAfter",
|
|
434
542
|
"treeChildren": "-cerbur-clutch-dsh-worktree-treeChildren",
|
|
@@ -437,11 +545,14 @@ window.__ModuleLoader__.load({
|
|
|
437
545
|
"worktreeGroup": "-cerbur-clutch-dsh-worktree-worktreeGroup",
|
|
438
546
|
"treeSessionRow": "-cerbur-clutch-dsh-worktree-treeSessionRow",
|
|
439
547
|
"treeSessionContent": "-cerbur-clutch-dsh-worktree-treeSessionContent",
|
|
548
|
+
"sessionTrailing": "-cerbur-clutch-dsh-worktree-sessionTrailing",
|
|
549
|
+
"sessionMeta": "-cerbur-clutch-dsh-worktree-sessionMeta",
|
|
440
550
|
"rowActions": "-cerbur-clutch-dsh-worktree-rowActions",
|
|
551
|
+
"sessionStatus": "-cerbur-clutch-dsh-worktree-sessionStatus",
|
|
552
|
+
"sessionTime": "-cerbur-clutch-dsh-worktree-sessionTime",
|
|
441
553
|
"sessionOverflowButton": "-cerbur-clutch-dsh-worktree-sessionOverflowButton",
|
|
442
554
|
"renameInput": "-cerbur-clutch-dsh-worktree-renameInput",
|
|
443
555
|
"renameError": "-cerbur-clutch-dsh-worktree-renameError",
|
|
444
|
-
"treeGuide": "-cerbur-clutch-dsh-worktree-treeGuide",
|
|
445
556
|
"emptyNested": "-cerbur-clutch-dsh-worktree-emptyNested",
|
|
446
557
|
"modalField": "-cerbur-clutch-dsh-worktree-modalField"
|
|
447
558
|
};
|
|
@@ -512,7 +623,7 @@ window.__ModuleLoader__.load({
|
|
|
512
623
|
}
|
|
513
624
|
/**
|
|
514
625
|
* Browser-local Hero suffix. It intentionally uses the frame overlay because
|
|
515
|
-
*
|
|
626
|
+
* The current upstream DSH exposes no additive slot beside the native Hero headline.
|
|
516
627
|
*/
|
|
517
628
|
function WorktreeHeroContext({ useWorktreeContext, t }) {
|
|
518
629
|
const state = useWorktreeContext((snapshot) => snapshot);
|
|
@@ -711,6 +822,84 @@ window.__ModuleLoader__.load({
|
|
|
711
822
|
};
|
|
712
823
|
}
|
|
713
824
|
//#endregion
|
|
825
|
+
//#region lib/client/worktree-expand-state.js
|
|
826
|
+
/** Browser-local storage identity; never sent to DSH or the plugin sidecar. */
|
|
827
|
+
const WORKTREE_EXPAND_STATE_STORAGE_KEY = "clutch-dsh-worktree.expand-state";
|
|
828
|
+
function emptyState$1() {
|
|
829
|
+
return {
|
|
830
|
+
collapsedWorkspaceIds: {},
|
|
831
|
+
collapsedMainWorkspaceIds: {},
|
|
832
|
+
collapsedWorktreeIds: {}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
function isRecord$1(value) {
|
|
836
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
837
|
+
}
|
|
838
|
+
function normalizeIds$1(value) {
|
|
839
|
+
if (!isRecord$1(value)) return {};
|
|
840
|
+
return Object.fromEntries(Object.entries(value).filter(([id, collapsed]) => id.length > 0 && collapsed === true));
|
|
841
|
+
}
|
|
842
|
+
/** Turn any persisted JSON value into the current state shape. */
|
|
843
|
+
function normalizeWorktreeExpandState(value) {
|
|
844
|
+
const source = isRecord$1(value) ? value : {};
|
|
845
|
+
return {
|
|
846
|
+
collapsedWorkspaceIds: normalizeIds$1(source.collapsedWorkspaceIds),
|
|
847
|
+
collapsedMainWorkspaceIds: normalizeIds$1(source.collapsedMainWorkspaceIds),
|
|
848
|
+
collapsedWorktreeIds: normalizeIds$1(source.collapsedWorktreeIds)
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
function isWorkspaceExpanded(state, workspaceId) {
|
|
852
|
+
return state.collapsedWorkspaceIds[workspaceId] !== true;
|
|
853
|
+
}
|
|
854
|
+
function isMainExpanded(state, workspaceId) {
|
|
855
|
+
return state.collapsedMainWorkspaceIds[workspaceId] !== true;
|
|
856
|
+
}
|
|
857
|
+
function isWorktreeExpanded(state, worktreeId) {
|
|
858
|
+
return state.collapsedWorktreeIds[worktreeId] !== true;
|
|
859
|
+
}
|
|
860
|
+
function toggle(record, id) {
|
|
861
|
+
if (record[id] === true) delete record[id];
|
|
862
|
+
else record[id] = true;
|
|
863
|
+
}
|
|
864
|
+
function retain(record, ids) {
|
|
865
|
+
const allowed = new Set(ids);
|
|
866
|
+
for (const id of Object.keys(record)) if (!allowed.has(id)) delete record[id];
|
|
867
|
+
}
|
|
868
|
+
/** Create one apply-scoped store; component remounts share this instance. */
|
|
869
|
+
function createWorktreeExpandStateStore(snapshotStoreFactory) {
|
|
870
|
+
let store;
|
|
871
|
+
try {
|
|
872
|
+
store = snapshotStoreFactory(emptyState$1(), { persist: { name: WORKTREE_EXPAND_STATE_STORAGE_KEY } });
|
|
873
|
+
} catch {
|
|
874
|
+
store = snapshotStoreFactory(emptyState$1());
|
|
875
|
+
}
|
|
876
|
+
store.set(normalizeWorktreeExpandState(store.getSnapshot()));
|
|
877
|
+
return Object.assign(store, { actions: {
|
|
878
|
+
toggleWorkspace: (workspaceId) => {
|
|
879
|
+
store.update((draft) => {
|
|
880
|
+
toggle(draft.collapsedWorkspaceIds, workspaceId);
|
|
881
|
+
});
|
|
882
|
+
},
|
|
883
|
+
toggleMain: (workspaceId) => {
|
|
884
|
+
store.update((draft) => {
|
|
885
|
+
toggle(draft.collapsedMainWorkspaceIds, workspaceId);
|
|
886
|
+
});
|
|
887
|
+
},
|
|
888
|
+
toggleWorktree: (worktreeId) => {
|
|
889
|
+
store.update((draft) => {
|
|
890
|
+
toggle(draft.collapsedWorktreeIds, worktreeId);
|
|
891
|
+
});
|
|
892
|
+
},
|
|
893
|
+
retain: (workspaceIds, worktreeIds) => {
|
|
894
|
+
store.update((draft) => {
|
|
895
|
+
retain(draft.collapsedWorkspaceIds, workspaceIds);
|
|
896
|
+
retain(draft.collapsedMainWorkspaceIds, workspaceIds);
|
|
897
|
+
retain(draft.collapsedWorktreeIds, worktreeIds);
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
} });
|
|
901
|
+
}
|
|
902
|
+
//#endregion
|
|
714
903
|
//#region lib/client/view-mode.js
|
|
715
904
|
/** Browser-local storage key; it is never sent to DSH or the sidecar. */
|
|
716
905
|
const WORKTREE_VIEW_MODE_STORAGE_KEY = "clutch-dsh-worktree.view-mode";
|
|
@@ -773,6 +962,14 @@ window.__ModuleLoader__.load({
|
|
|
773
962
|
function reason(error, t) {
|
|
774
963
|
return error.message.length > 0 ? error.message : t("error.worktreeDataUnavailable");
|
|
775
964
|
}
|
|
965
|
+
function formatWorktreePermissionNotice(result, t) {
|
|
966
|
+
switch (result.status) {
|
|
967
|
+
case "fallback-workspace-write": return t("permission.fallbackWorkspaceWrite");
|
|
968
|
+
case "user-restricted": return t("permission.userRestricted");
|
|
969
|
+
case "unverified": return t("permission.unverified");
|
|
970
|
+
default: return t("permission.unavailable");
|
|
971
|
+
}
|
|
972
|
+
}
|
|
776
973
|
function formatWorktreeViewError(error, t) {
|
|
777
974
|
switch (error.code) {
|
|
778
975
|
case "CLIENT_DISPOSED": return t("error.connectionDisposed");
|
|
@@ -787,6 +984,9 @@ window.__ModuleLoader__.load({
|
|
|
787
984
|
case "SESSION_CREATE_UNAVAILABLE": return t("error.sessionCreationUnavailable");
|
|
788
985
|
case "WORKTREE_CREATED_SESSION_UNAVAILABLE": return t("error.worktreeCreatedSessionUnavailable");
|
|
789
986
|
case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
|
|
987
|
+
case "WORKTREE_IMPORT_INVALID": return t("error.worktreeImportInvalid");
|
|
988
|
+
case "WORKTREE_ALREADY_MANAGED": return t("error.worktreeAlreadyManaged");
|
|
989
|
+
case "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE": return t("error.worktreeRegistrationSessionUnavailable");
|
|
790
990
|
case "WORKSPACE_RENAME_UNAVAILABLE": return t("error.workspaceRenameUnavailable");
|
|
791
991
|
case "WORKSPACE_DELETE_UNAVAILABLE": return t("error.workspaceDeleteUnavailable");
|
|
792
992
|
case "SESSION_RENAME_UNAVAILABLE": return t("error.sessionRenameUnavailable");
|
|
@@ -795,6 +995,8 @@ window.__ModuleLoader__.load({
|
|
|
795
995
|
reason: reason(error, t)
|
|
796
996
|
});
|
|
797
997
|
case "SESSION_ALREADY_BOUND": return t("error.sessionAlreadyBound");
|
|
998
|
+
case "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED": return t("error.worktreePermissionConfirmationRequired");
|
|
999
|
+
case "WORKTREE_PERMISSION_FAILED": return t("error.worktreePermissionFailed", { reason: reason(error, t) });
|
|
798
1000
|
case "SESSION_LIST_NOT_READY": return t("error.sessionListNotReady");
|
|
799
1001
|
case "SESSION_FACTS_INCOMPLETE": return t("error.sessionFactsIncomplete");
|
|
800
1002
|
case "WORKTREE_SESSION_REPAIR_REQUIRED": return t("error.worktreeSessionRepairRequired");
|
|
@@ -806,6 +1008,127 @@ window.__ModuleLoader__.load({
|
|
|
806
1008
|
}
|
|
807
1009
|
//#endregion
|
|
808
1010
|
//#region lib/client/session-view.js
|
|
1011
|
+
function isPendingInteractionStatus(value) {
|
|
1012
|
+
return value === "approval" || value === "plan-review" || value === "question";
|
|
1013
|
+
}
|
|
1014
|
+
function validUpdatedAt(value) {
|
|
1015
|
+
return value !== void 0 && Number.isFinite(value);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Native-compatible subagent lineage index. The upstream runtime's public client
|
|
1019
|
+
* entry is a browser module-loader bundle, so keeping this pure mirror local lets
|
|
1020
|
+
* the browser Consumer and its Node tests share the same status semantics.
|
|
1021
|
+
*/
|
|
1022
|
+
function indexSubagentDescendants(summaries) {
|
|
1023
|
+
const indexed = /* @__PURE__ */ new Map();
|
|
1024
|
+
for (const descendant of Object.values(summaries)) {
|
|
1025
|
+
if (descendant.origin !== "subagent") continue;
|
|
1026
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1027
|
+
let current = descendant;
|
|
1028
|
+
while (current?.origin === "subagent" && current.parentId !== void 0 && !seen.has(current.id)) {
|
|
1029
|
+
seen.add(current.id);
|
|
1030
|
+
const aggregate = indexed.get(current.parentId);
|
|
1031
|
+
if (aggregate === void 0) indexed.set(current.parentId, {
|
|
1032
|
+
count: 1,
|
|
1033
|
+
runningCount: descendant.running ? 1 : 0
|
|
1034
|
+
});
|
|
1035
|
+
else {
|
|
1036
|
+
aggregate.count += 1;
|
|
1037
|
+
if (descendant.running) aggregate.runningCount += 1;
|
|
1038
|
+
}
|
|
1039
|
+
current = summaries[current.parentId];
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return indexed;
|
|
1043
|
+
}
|
|
1044
|
+
/** Native Workspace relative-time buckets, kept pure for deterministic rendering/tests. */
|
|
1045
|
+
function relativeTime(updatedAt, now) {
|
|
1046
|
+
if (!validUpdatedAt(updatedAt) || !Number.isFinite(now)) return void 0;
|
|
1047
|
+
const MIN = 6e4;
|
|
1048
|
+
const HOUR = 36e5;
|
|
1049
|
+
const DAY = 864e5;
|
|
1050
|
+
const diff = Math.max(0, now - updatedAt);
|
|
1051
|
+
if (diff < MIN) return {
|
|
1052
|
+
unit: "now",
|
|
1053
|
+
n: 0
|
|
1054
|
+
};
|
|
1055
|
+
if (diff < HOUR) return {
|
|
1056
|
+
unit: "minutes",
|
|
1057
|
+
n: Math.floor(diff / MIN)
|
|
1058
|
+
};
|
|
1059
|
+
if (diff < DAY) return {
|
|
1060
|
+
unit: "hours",
|
|
1061
|
+
n: Math.floor(diff / HOUR)
|
|
1062
|
+
};
|
|
1063
|
+
if (diff < 30 * DAY) return {
|
|
1064
|
+
unit: "days",
|
|
1065
|
+
n: Math.floor(diff / DAY)
|
|
1066
|
+
};
|
|
1067
|
+
if (diff < 365 * DAY) return {
|
|
1068
|
+
unit: "months",
|
|
1069
|
+
n: Math.floor(diff / (30 * DAY))
|
|
1070
|
+
};
|
|
1071
|
+
return {
|
|
1072
|
+
unit: "years",
|
|
1073
|
+
n: Math.floor(diff / (365 * DAY))
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
/** Match native Workspace status priority while retaining the aggregate subagent count. */
|
|
1077
|
+
function sessionStatus(session, runningSubagentCount) {
|
|
1078
|
+
const count = Number.isFinite(runningSubagentCount) && runningSubagentCount > 0 ? Math.floor(runningSubagentCount) : 0;
|
|
1079
|
+
if (isPendingInteractionStatus(session.pendingInteraction)) return {
|
|
1080
|
+
state: "warning",
|
|
1081
|
+
labelKey: session.pendingInteraction === "approval" ? "waitingApproval" : session.pendingInteraction === "plan-review" ? "planReview" : "waitingAnswer",
|
|
1082
|
+
runningSubagentCount: count
|
|
1083
|
+
};
|
|
1084
|
+
if (session.running === true) return {
|
|
1085
|
+
state: "ongoing",
|
|
1086
|
+
labelKey: "running",
|
|
1087
|
+
runningSubagentCount: count
|
|
1088
|
+
};
|
|
1089
|
+
if (count > 0) return {
|
|
1090
|
+
state: "ongoing",
|
|
1091
|
+
labelKey: "subagentsRunning",
|
|
1092
|
+
runningSubagentCount: count
|
|
1093
|
+
};
|
|
1094
|
+
if (session.completed === true) return {
|
|
1095
|
+
state: "done",
|
|
1096
|
+
labelKey: "completed",
|
|
1097
|
+
runningSubagentCount: 0
|
|
1098
|
+
};
|
|
1099
|
+
return {
|
|
1100
|
+
state: "done",
|
|
1101
|
+
labelKey: "idle",
|
|
1102
|
+
runningSubagentCount: 0
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
function toLineageSummary(sessionId, summary) {
|
|
1106
|
+
return {
|
|
1107
|
+
id: sessionId,
|
|
1108
|
+
running: summary.running === true,
|
|
1109
|
+
...summary.parentId === void 0 ? {} : { parentId: summary.parentId },
|
|
1110
|
+
...summary.origin === "subagent" ? { origin: "subagent" } : {}
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
/** Derive row and group activity facts from one retained DSH Session snapshot. */
|
|
1114
|
+
function deriveSessionPresentationIndex(sessions) {
|
|
1115
|
+
const descendants = indexSubagentDescendants(Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => [sessionId, toLineageSummary(sessionId, summary)])));
|
|
1116
|
+
return Object.fromEntries(Object.entries(sessions.byId).map(([sessionId, summary]) => {
|
|
1117
|
+
const runningSubagentCount = descendants.get(sessionId)?.runningCount ?? 0;
|
|
1118
|
+
return [sessionId, {
|
|
1119
|
+
status: sessionStatus(summary, runningSubagentCount),
|
|
1120
|
+
running: summary.running === true,
|
|
1121
|
+
ongoing: summary.running === true || runningSubagentCount > 0,
|
|
1122
|
+
runningSubagentCount,
|
|
1123
|
+
completed: summary.completed === true,
|
|
1124
|
+
...validUpdatedAt(summary.updatedAt) ? { updatedAt: summary.updatedAt } : {}
|
|
1125
|
+
}];
|
|
1126
|
+
}));
|
|
1127
|
+
}
|
|
1128
|
+
/** Aggregate only live ongoing activity; callers decide which IDs are in the group. */
|
|
1129
|
+
function hasOngoingSession(sessionIds, presentations) {
|
|
1130
|
+
return sessionIds.some((sessionId) => presentations[sessionId]?.ongoing === true);
|
|
1131
|
+
}
|
|
809
1132
|
/** Read the native blank flag without inferring blankness from title or id. */
|
|
810
1133
|
function isBlankSession(sessionId, sessions) {
|
|
811
1134
|
return sessions.byId[sessionId]?.blank === true;
|
|
@@ -830,6 +1153,193 @@ window.__ModuleLoader__.load({
|
|
|
830
1153
|
return (summary?.displayTitle ?? sessionId).toLocaleLowerCase().includes(normalizedQuery);
|
|
831
1154
|
}
|
|
832
1155
|
//#endregion
|
|
1156
|
+
//#region lib/client/worktree-session-order.js
|
|
1157
|
+
/** Browser-only persistence key; this state never crosses the DSH or sidecar boundary. */
|
|
1158
|
+
const WORKTREE_SESSION_ORDER_STORAGE_KEY = "clutch-dsh-worktree.session-order";
|
|
1159
|
+
function emptyState() {
|
|
1160
|
+
return { accounts: {} };
|
|
1161
|
+
}
|
|
1162
|
+
function isRecord(value) {
|
|
1163
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1164
|
+
}
|
|
1165
|
+
function isValidTimestamp(value) {
|
|
1166
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
1167
|
+
}
|
|
1168
|
+
function normalizeIds(value) {
|
|
1169
|
+
if (!Array.isArray(value)) return [];
|
|
1170
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1171
|
+
const ids = [];
|
|
1172
|
+
for (const id of value) {
|
|
1173
|
+
if (typeof id !== "string" || id.length === 0 || seen.has(id)) continue;
|
|
1174
|
+
seen.add(id);
|
|
1175
|
+
ids.push(id);
|
|
1176
|
+
}
|
|
1177
|
+
return ids;
|
|
1178
|
+
}
|
|
1179
|
+
function normalizeAccount(value) {
|
|
1180
|
+
if (!isRecord(value)) return void 0;
|
|
1181
|
+
const order = normalizeIds(value.order);
|
|
1182
|
+
const allowed = new Set(order);
|
|
1183
|
+
const observedUpdatedAt = {};
|
|
1184
|
+
if (isRecord(value.observedUpdatedAt)) {
|
|
1185
|
+
for (const [id, timestamp] of Object.entries(value.observedUpdatedAt)) if (allowed.has(id) && isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
|
|
1186
|
+
}
|
|
1187
|
+
return {
|
|
1188
|
+
order,
|
|
1189
|
+
observedUpdatedAt
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
/** Normalize persisted state without trusting any browser-local JSON shape. */
|
|
1193
|
+
function normalizeWorktreeSessionOrderState(value) {
|
|
1194
|
+
if (!isRecord(value) || !isRecord(value.accounts)) return emptyState();
|
|
1195
|
+
const accounts = {};
|
|
1196
|
+
for (const [accountKey, account] of Object.entries(value.accounts)) {
|
|
1197
|
+
if (accountKey.length === 0) continue;
|
|
1198
|
+
const normalized = normalizeAccount(account);
|
|
1199
|
+
if (normalized !== void 0) accounts[accountKey] = normalized;
|
|
1200
|
+
}
|
|
1201
|
+
return { accounts };
|
|
1202
|
+
}
|
|
1203
|
+
function validIds(ids) {
|
|
1204
|
+
return normalizeIds([...ids]);
|
|
1205
|
+
}
|
|
1206
|
+
function sameRecord(left, right) {
|
|
1207
|
+
if (left === void 0) return false;
|
|
1208
|
+
const leftKeys = Object.keys(left);
|
|
1209
|
+
const rightKeys = Object.keys(right);
|
|
1210
|
+
if (leftKeys.length !== rightKeys.length) return false;
|
|
1211
|
+
return rightKeys.every((key) => left[key] === right[key]);
|
|
1212
|
+
}
|
|
1213
|
+
function sameAccount(left, right) {
|
|
1214
|
+
return left !== void 0 && left.order.length === right.order.length && left.order.every((id, index) => id === right.order[index]) && sameRecord(left.observedUpdatedAt, right.observedUpdatedAt);
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Native-style activity order transition. The first observation records timestamps
|
|
1218
|
+
* without turning an existing list into a recency sort.
|
|
1219
|
+
*/
|
|
1220
|
+
function nextSessionOrderAccount(input) {
|
|
1221
|
+
const baseIds = validIds(input.baseIds);
|
|
1222
|
+
const previous = input.previous;
|
|
1223
|
+
if (previous === void 0) {
|
|
1224
|
+
const observedUpdatedAt = {};
|
|
1225
|
+
for (const id of baseIds) {
|
|
1226
|
+
const timestamp = input.updatedAtById[id];
|
|
1227
|
+
if (isValidTimestamp(timestamp)) observedUpdatedAt[id] = timestamp;
|
|
1228
|
+
}
|
|
1229
|
+
return {
|
|
1230
|
+
order: baseIds,
|
|
1231
|
+
observedUpdatedAt
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
const available = new Set(baseIds);
|
|
1235
|
+
const order = [];
|
|
1236
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1237
|
+
for (const id of previous.order) if (available.has(id) && !seen.has(id)) {
|
|
1238
|
+
seen.add(id);
|
|
1239
|
+
order.push(id);
|
|
1240
|
+
}
|
|
1241
|
+
for (const id of baseIds) if (!seen.has(id)) {
|
|
1242
|
+
seen.add(id);
|
|
1243
|
+
order.push(id);
|
|
1244
|
+
}
|
|
1245
|
+
const observedUpdatedAt = {};
|
|
1246
|
+
const previousIds = new Set(previous.order);
|
|
1247
|
+
const newlyObserved = [];
|
|
1248
|
+
const promoted = [];
|
|
1249
|
+
for (const [index, id] of order.entries()) {
|
|
1250
|
+
if (!previousIds.has(id)) newlyObserved.push(id);
|
|
1251
|
+
const previousTimestamp = previous.observedUpdatedAt[id];
|
|
1252
|
+
const timestamp = input.updatedAtById[id];
|
|
1253
|
+
if (isValidTimestamp(previousTimestamp)) observedUpdatedAt[id] = previousTimestamp;
|
|
1254
|
+
if (isValidTimestamp(timestamp)) {
|
|
1255
|
+
if (!isValidTimestamp(previousTimestamp) || timestamp > previousTimestamp) {
|
|
1256
|
+
if (isValidTimestamp(previousTimestamp)) promoted.push({
|
|
1257
|
+
id,
|
|
1258
|
+
timestamp,
|
|
1259
|
+
index
|
|
1260
|
+
});
|
|
1261
|
+
observedUpdatedAt[id] = Math.max(observedUpdatedAt[id] ?? timestamp, timestamp);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
promoted.sort((left, right) => right.timestamp - left.timestamp || left.index - right.index);
|
|
1266
|
+
const promotedIds = /* @__PURE__ */ new Set([...newlyObserved, ...promoted.map(({ id }) => id)]);
|
|
1267
|
+
return {
|
|
1268
|
+
order: [
|
|
1269
|
+
...newlyObserved,
|
|
1270
|
+
...promoted.map(({ id }) => id),
|
|
1271
|
+
...order.filter((id) => !promotedIds.has(id))
|
|
1272
|
+
],
|
|
1273
|
+
observedUpdatedAt
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
/** Apply a successful manual drag without dropping IDs hidden by search. */
|
|
1277
|
+
function reorderSessionIds(order, sessionId, overSessionId, half) {
|
|
1278
|
+
const next = order.filter((id) => id !== sessionId);
|
|
1279
|
+
const targetIndex = next.indexOf(overSessionId);
|
|
1280
|
+
if (targetIndex === -1) return [...order];
|
|
1281
|
+
next.splice(half === "before" ? targetIndex : targetIndex + 1, 0, sessionId);
|
|
1282
|
+
return next;
|
|
1283
|
+
}
|
|
1284
|
+
function cloneAccount(account) {
|
|
1285
|
+
return {
|
|
1286
|
+
order: [...account.order],
|
|
1287
|
+
observedUpdatedAt: { ...account.observedUpdatedAt }
|
|
1288
|
+
};
|
|
1289
|
+
}
|
|
1290
|
+
/** Create one apply-scoped, browser-local Session ordering store. */
|
|
1291
|
+
function createWorktreeSessionOrderStore(snapshotStoreFactory) {
|
|
1292
|
+
let store;
|
|
1293
|
+
try {
|
|
1294
|
+
store = snapshotStoreFactory(emptyState(), { persist: { name: WORKTREE_SESSION_ORDER_STORAGE_KEY } });
|
|
1295
|
+
} catch {
|
|
1296
|
+
store = snapshotStoreFactory(emptyState());
|
|
1297
|
+
}
|
|
1298
|
+
store.set(normalizeWorktreeSessionOrderState(store.getSnapshot()));
|
|
1299
|
+
let disposed = false;
|
|
1300
|
+
return Object.assign(store, {
|
|
1301
|
+
actions: {
|
|
1302
|
+
reconcile: (accountKey, baseIds, updatedAtById) => {
|
|
1303
|
+
if (disposed || accountKey.length === 0) return;
|
|
1304
|
+
store.update((draft) => {
|
|
1305
|
+
const next = nextSessionOrderAccount({
|
|
1306
|
+
baseIds,
|
|
1307
|
+
updatedAtById,
|
|
1308
|
+
previous: draft.accounts[accountKey]
|
|
1309
|
+
});
|
|
1310
|
+
if (sameAccount(draft.accounts[accountKey], next)) return;
|
|
1311
|
+
draft.accounts[accountKey] = cloneAccount(next);
|
|
1312
|
+
});
|
|
1313
|
+
},
|
|
1314
|
+
setOrder: (accountKey, order) => {
|
|
1315
|
+
if (disposed || accountKey.length === 0) return;
|
|
1316
|
+
store.update((draft) => {
|
|
1317
|
+
const current = draft.accounts[accountKey] ?? {
|
|
1318
|
+
order: [],
|
|
1319
|
+
observedUpdatedAt: {}
|
|
1320
|
+
};
|
|
1321
|
+
const next = {
|
|
1322
|
+
order: validIds(order),
|
|
1323
|
+
observedUpdatedAt: { ...current.observedUpdatedAt }
|
|
1324
|
+
};
|
|
1325
|
+
if (sameAccount(current, next)) return;
|
|
1326
|
+
draft.accounts[accountKey] = next;
|
|
1327
|
+
});
|
|
1328
|
+
},
|
|
1329
|
+
retain: (accountKeys) => {
|
|
1330
|
+
if (disposed) return;
|
|
1331
|
+
store.update((draft) => {
|
|
1332
|
+
const allowed = new Set(accountKeys);
|
|
1333
|
+
for (const accountKey of Object.keys(draft.accounts)) if (!allowed.has(accountKey)) delete draft.accounts[accountKey];
|
|
1334
|
+
});
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
dispose: () => {
|
|
1338
|
+
disposed = true;
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
//#endregion
|
|
833
1343
|
//#region lib/client/worktree-view-errors.js
|
|
834
1344
|
/** A DSH Session exists even when the external Worktree binding needs repair. */
|
|
835
1345
|
var WorktreeSessionBindingError = class extends Error {
|
|
@@ -851,6 +1361,25 @@ window.__ModuleLoader__.load({
|
|
|
851
1361
|
this.cause = cause;
|
|
852
1362
|
}
|
|
853
1363
|
};
|
|
1364
|
+
/** A Session is retained after permission confirmation or permission setup needs retry. */
|
|
1365
|
+
var WorktreeSessionPermissionError = class extends Error {
|
|
1366
|
+
code;
|
|
1367
|
+
retryable = true;
|
|
1368
|
+
details;
|
|
1369
|
+
sessionId;
|
|
1370
|
+
createdSession;
|
|
1371
|
+
cause;
|
|
1372
|
+
constructor(sessionId, createdSession, cause) {
|
|
1373
|
+
const reason = cause instanceof Error ? cause.message : cause === void 0 ? "" : String(cause);
|
|
1374
|
+
super(reason);
|
|
1375
|
+
this.name = "WorktreeSessionPermissionError";
|
|
1376
|
+
this.code = cause === void 0 ? "WORKTREE_PERMISSION_CONFIRMATION_REQUIRED" : "WORKTREE_PERMISSION_FAILED";
|
|
1377
|
+
this.details = { sessionId };
|
|
1378
|
+
this.sessionId = sessionId;
|
|
1379
|
+
this.createdSession = createdSession;
|
|
1380
|
+
this.cause = cause;
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
854
1383
|
function recordDetails(value) {
|
|
855
1384
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
856
1385
|
const details = value.details;
|
|
@@ -861,7 +1390,7 @@ window.__ModuleLoader__.load({
|
|
|
861
1390
|
function toWorktreeViewError(error) {
|
|
862
1391
|
if (typeof error === "object" && error !== null) {
|
|
863
1392
|
const candidate = error;
|
|
864
|
-
const details = error instanceof WorktreeSessionBindingError ? {
|
|
1393
|
+
const details = error instanceof WorktreeSessionBindingError || error instanceof WorktreeSessionPermissionError ? {
|
|
865
1394
|
...recordDetails(error) ?? {},
|
|
866
1395
|
sessionId: error.sessionId
|
|
867
1396
|
} : recordDetails(error);
|
|
@@ -903,6 +1432,21 @@ window.__ModuleLoader__.load({
|
|
|
903
1432
|
}
|
|
904
1433
|
throw new Error("Unable to generate an available default Worktree name.");
|
|
905
1434
|
}
|
|
1435
|
+
/** Generate the next available numeric sibling name for a selected Worktree. */
|
|
1436
|
+
function createNumberedWorktreeName(baseName, existingNames) {
|
|
1437
|
+
const normalizedBaseName = baseName.trim();
|
|
1438
|
+
const usedNames = new Set([...existingNames].map((name) => name.trim()));
|
|
1439
|
+
const numberedBase = normalizedBaseName.match(/^(.*)-(\d+)$/);
|
|
1440
|
+
const prefix = numberedBase?.[1] || normalizedBaseName || "worktree";
|
|
1441
|
+
const parsedNumber = numberedBase === null ? 1 : Number(numberedBase[2]);
|
|
1442
|
+
let number = Number.isSafeInteger(parsedNumber) ? parsedNumber + 1 : 2;
|
|
1443
|
+
for (let attempt = 0; attempt < 1e4; attempt += 1) {
|
|
1444
|
+
const candidate = `${prefix}-${number}`;
|
|
1445
|
+
if (!usedNames.has(candidate)) return candidate;
|
|
1446
|
+
number += 1;
|
|
1447
|
+
}
|
|
1448
|
+
throw new Error("Unable to generate an available numbered Worktree name.");
|
|
1449
|
+
}
|
|
906
1450
|
/** Resolve a row-half drop target to native-style optional before-anchor semantics. */
|
|
907
1451
|
function resolveWorktreeMove(worktreeIds, sourceWorktreeId, targetWorktreeId, half) {
|
|
908
1452
|
const sourceIndex = worktreeIds.indexOf(sourceWorktreeId);
|
|
@@ -915,10 +1459,19 @@ window.__ModuleLoader__.load({
|
|
|
915
1459
|
return beforeWorktreeId === void 0 ? {} : { beforeWorktreeId };
|
|
916
1460
|
}
|
|
917
1461
|
/** Keep mutation routing in the browser Consumer while leaving wire details to the adapter. */
|
|
918
|
-
async function executeWorktreeAction(manager, action) {
|
|
1462
|
+
async function executeWorktreeAction(manager, action, permission, onPermissionResult) {
|
|
919
1463
|
if (action.type === "createWorktree") return manager.createWorktree(action.input);
|
|
1464
|
+
if (action.type === "importWorktree") return manager.importWorktree(action.input);
|
|
920
1465
|
if (action.type === "removeWorktree") {
|
|
921
1466
|
await manager.removeWorktree(action.input);
|
|
1467
|
+
const result = await permission?.normalizeDetachedWorktreePermissions({
|
|
1468
|
+
workspaceId: action.input.workspaceId,
|
|
1469
|
+
worktreeId: action.input.worktreeId
|
|
1470
|
+
});
|
|
1471
|
+
if (result !== void 0) onPermissionResult?.({
|
|
1472
|
+
workspaceId: action.input.workspaceId,
|
|
1473
|
+
worktreeId: action.input.worktreeId
|
|
1474
|
+
}, result);
|
|
922
1475
|
return;
|
|
923
1476
|
}
|
|
924
1477
|
}
|
|
@@ -937,12 +1490,20 @@ window.__ModuleLoader__.load({
|
|
|
937
1490
|
} catch (error) {
|
|
938
1491
|
throw new WorktreeSessionBindingError(sessionId, error);
|
|
939
1492
|
}
|
|
940
|
-
input.beforeOpen?.(sessionId);
|
|
1493
|
+
await input.beforeOpen?.(sessionId);
|
|
941
1494
|
input.openSession(sessionId);
|
|
942
1495
|
return sessionId;
|
|
943
1496
|
}
|
|
944
1497
|
//#endregion
|
|
945
1498
|
//#region lib/client/worktree-view-read.js
|
|
1499
|
+
/** Merge one freshly read Workspace projection without clearing other ready views. */
|
|
1500
|
+
function mergeWorktreeView(views, nextView) {
|
|
1501
|
+
const index = views.findIndex((view) => view.workspaceId === nextView.workspaceId);
|
|
1502
|
+
if (index === -1) return [...views, nextView];
|
|
1503
|
+
const merged = [...views];
|
|
1504
|
+
merged[index] = nextView;
|
|
1505
|
+
return merged;
|
|
1506
|
+
}
|
|
946
1507
|
/** Reuse the previous ID snapshot when DSH republishes equivalent Workspace items. */
|
|
947
1508
|
function stableWorkspaceIds(previous, next) {
|
|
948
1509
|
if (previous.length !== next.length) return next;
|
|
@@ -1048,6 +1609,19 @@ window.__ModuleLoader__.load({
|
|
|
1048
1609
|
readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
|
|
1049
1610
|
};
|
|
1050
1611
|
}
|
|
1612
|
+
/** Isolate modal-target reads from full-surface refresh generations. */
|
|
1613
|
+
function createWorktreeModalViewLoader() {
|
|
1614
|
+
const guard = createWorktreeRefreshGuard();
|
|
1615
|
+
return {
|
|
1616
|
+
invalidate: guard.invalidate,
|
|
1617
|
+
load(manager, workspaceId, onSuccess, onError) {
|
|
1618
|
+
return guard.run(() => loadWorktreeView(manager, workspaceId), (data) => onSuccess({
|
|
1619
|
+
workspaceId,
|
|
1620
|
+
...data
|
|
1621
|
+
}), (error) => onError(toWorktreeViewError(error)));
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
}
|
|
1051
1625
|
/** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
|
|
1052
1626
|
async function loadWorktreeViews(manager, workspaceIds, options = {}) {
|
|
1053
1627
|
const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
|
|
@@ -1075,6 +1649,54 @@ window.__ModuleLoader__.load({
|
|
|
1075
1649
|
this.details = details;
|
|
1076
1650
|
}
|
|
1077
1651
|
};
|
|
1652
|
+
/**
|
|
1653
|
+
* Keep the confirmation and second permission call in one place for new,
|
|
1654
|
+
* reused, and retried Sessions. The Host still validates the relation.
|
|
1655
|
+
*/
|
|
1656
|
+
async function ensureWorktreeSessionPermission(input) {
|
|
1657
|
+
if (input.permission === void 0) return;
|
|
1658
|
+
const request = {
|
|
1659
|
+
workspaceId: input.workspaceId,
|
|
1660
|
+
worktreeId: input.worktreeId,
|
|
1661
|
+
sessionId: input.sessionId,
|
|
1662
|
+
binding: "active"
|
|
1663
|
+
};
|
|
1664
|
+
let result;
|
|
1665
|
+
try {
|
|
1666
|
+
result = await input.permission.ensureWorktreePermission(request);
|
|
1667
|
+
} catch (error) {
|
|
1668
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1669
|
+
}
|
|
1670
|
+
if (result.status === "confirmation-required") {
|
|
1671
|
+
let confirmed;
|
|
1672
|
+
try {
|
|
1673
|
+
confirmed = input.confirmFullAccess === void 0 ? false : await input.confirmFullAccess({
|
|
1674
|
+
workspaceId: input.workspaceId,
|
|
1675
|
+
worktreeId: input.worktreeId,
|
|
1676
|
+
sessionId: input.sessionId,
|
|
1677
|
+
cwd: input.cwd
|
|
1678
|
+
});
|
|
1679
|
+
} catch (error) {
|
|
1680
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1681
|
+
}
|
|
1682
|
+
if (!confirmed) throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
|
|
1683
|
+
try {
|
|
1684
|
+
result = await input.permission.ensureWorktreePermission({
|
|
1685
|
+
...request,
|
|
1686
|
+
confirmed: true
|
|
1687
|
+
});
|
|
1688
|
+
} catch (error) {
|
|
1689
|
+
throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession, error);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
if (result.status === "confirmation-required") throw new WorktreeSessionPermissionError(input.sessionId, input.createdSession);
|
|
1693
|
+
input.onPermissionResult?.({
|
|
1694
|
+
workspaceId: input.workspaceId,
|
|
1695
|
+
worktreeId: input.worktreeId,
|
|
1696
|
+
sessionId: input.sessionId,
|
|
1697
|
+
cwd: input.cwd
|
|
1698
|
+
}, result);
|
|
1699
|
+
}
|
|
1078
1700
|
function resolveWorktreeSessionAction(input) {
|
|
1079
1701
|
if (input.target.status !== "active" || input.target.health === "repair") return {
|
|
1080
1702
|
kind: "reject",
|
|
@@ -1138,6 +1760,16 @@ window.__ModuleLoader__.load({
|
|
|
1138
1760
|
} catch (error) {
|
|
1139
1761
|
throw new WorktreeSessionBindingError(input.pending.sessionId, error);
|
|
1140
1762
|
}
|
|
1763
|
+
await ensureWorktreeSessionPermission({
|
|
1764
|
+
permission: input.permission,
|
|
1765
|
+
confirmFullAccess: input.confirmFullAccess,
|
|
1766
|
+
onPermissionResult: input.onPermissionResult,
|
|
1767
|
+
sessionId: input.pending.sessionId,
|
|
1768
|
+
workspaceId: input.pending.workspaceId,
|
|
1769
|
+
worktreeId: input.pending.worktreeId,
|
|
1770
|
+
cwd: input.pending.cwd,
|
|
1771
|
+
createdSession: true
|
|
1772
|
+
});
|
|
1141
1773
|
input.ensureSessionWorkspace(input.pending.workspaceId, input.pending.sessionId);
|
|
1142
1774
|
input.openSession(input.pending.sessionId);
|
|
1143
1775
|
return input.pending.sessionId;
|
|
@@ -1161,6 +1793,16 @@ window.__ModuleLoader__.load({
|
|
|
1161
1793
|
bindings
|
|
1162
1794
|
});
|
|
1163
1795
|
if (action.kind === "open-bound") {
|
|
1796
|
+
await ensureWorktreeSessionPermission({
|
|
1797
|
+
permission: options.permission,
|
|
1798
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1799
|
+
onPermissionResult: options.onPermissionResult,
|
|
1800
|
+
sessionId: action.sessionId,
|
|
1801
|
+
workspaceId: input.workspaceId,
|
|
1802
|
+
worktreeId: input.worktreeId,
|
|
1803
|
+
cwd: input.cwd,
|
|
1804
|
+
createdSession: false
|
|
1805
|
+
});
|
|
1164
1806
|
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1165
1807
|
if (!disposed) options.openSession(action.sessionId);
|
|
1166
1808
|
return action.sessionId;
|
|
@@ -1175,6 +1817,16 @@ window.__ModuleLoader__.load({
|
|
|
1175
1817
|
} catch (error) {
|
|
1176
1818
|
throw new WorktreeSessionBindingError(action.sessionId, error);
|
|
1177
1819
|
}
|
|
1820
|
+
await ensureWorktreeSessionPermission({
|
|
1821
|
+
permission: options.permission,
|
|
1822
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1823
|
+
onPermissionResult: options.onPermissionResult,
|
|
1824
|
+
sessionId: action.sessionId,
|
|
1825
|
+
workspaceId: input.workspaceId,
|
|
1826
|
+
worktreeId: input.worktreeId,
|
|
1827
|
+
cwd: input.cwd,
|
|
1828
|
+
createdSession: false
|
|
1829
|
+
});
|
|
1178
1830
|
if (!disposed) {
|
|
1179
1831
|
options.ensureSessionWorkspace(input.workspaceId, action.sessionId);
|
|
1180
1832
|
if (!disposed) options.openSession(action.sessionId);
|
|
@@ -1187,9 +1839,18 @@ window.__ModuleLoader__.load({
|
|
|
1187
1839
|
...input,
|
|
1188
1840
|
createSession: options.createSession,
|
|
1189
1841
|
manager: options.manager,
|
|
1190
|
-
beforeOpen: (sessionId) => {
|
|
1842
|
+
beforeOpen: async (sessionId) => {
|
|
1191
1843
|
if (disposed) throw new WorktreeSessionActionError("CLIENT_DISPOSED", "", false);
|
|
1192
|
-
|
|
1844
|
+
await ensureWorktreeSessionPermission({
|
|
1845
|
+
permission: options.permission,
|
|
1846
|
+
confirmFullAccess: options.confirmFullAccess,
|
|
1847
|
+
onPermissionResult: options.onPermissionResult,
|
|
1848
|
+
sessionId,
|
|
1849
|
+
workspaceId: input.workspaceId,
|
|
1850
|
+
worktreeId: input.worktreeId,
|
|
1851
|
+
cwd: input.cwd,
|
|
1852
|
+
createdSession: true
|
|
1853
|
+
});
|
|
1193
1854
|
},
|
|
1194
1855
|
openSession: (sessionId) => {
|
|
1195
1856
|
if (!disposed) options.openSession(sessionId);
|
|
@@ -1348,10 +2009,12 @@ window.__ModuleLoader__.load({
|
|
|
1348
2009
|
})
|
|
1349
2010
|
});
|
|
1350
2011
|
}
|
|
1351
|
-
function WorktreeCreateDialog({ t, workspace, view, setupStatus, canCreate, selectedBranch, newBranch, actionPending, onClose, onSelectedBranchChange, onNewBranchChange, onSubmit }) {
|
|
2012
|
+
function WorktreeCreateDialog({ t, workspace, view, readError, setupStatus, canCreate, mode, importCandidates, selectedImportPath, selectedBranch, newBranch, actionPending, onClose, onRetry, onModeChange, onRetryImportCandidates, onSelectedImportPathChange, onSelectedBranchChange, onNewBranchChange, onSubmit }) {
|
|
1352
2013
|
if (workspace === void 0) return null;
|
|
1353
2014
|
const setupCommands = setupStatus === void 0 ? [] : worktreeSetupCommands(setupStatus);
|
|
1354
|
-
|
|
2015
|
+
const importing = mode === "import";
|
|
2016
|
+
const importBlocked = actionPending || importCandidates.status === "loading" || selectedImportPath === void 0;
|
|
2017
|
+
return (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1355
2018
|
open: true,
|
|
1356
2019
|
onClose: () => {
|
|
1357
2020
|
if (actionPending) return;
|
|
@@ -1359,7 +2022,7 @@ window.__ModuleLoader__.load({
|
|
|
1359
2022
|
},
|
|
1360
2023
|
closeLabel: t("dialog.closeWorktreeCreate"),
|
|
1361
2024
|
title: t("worktree.createTitle"),
|
|
1362
|
-
description: t("worktree.createDescription", { name: workspace.title }),
|
|
2025
|
+
description: importing ? t("worktree.importDescription", { name: workspace.title }) : t("worktree.createDescription", { name: workspace.title }),
|
|
1363
2026
|
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1364
2027
|
variant: "outline",
|
|
1365
2028
|
disabled: actionPending,
|
|
@@ -1367,13 +2030,104 @@ window.__ModuleLoader__.load({
|
|
|
1367
2030
|
children: t("dialog.cancel")
|
|
1368
2031
|
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1369
2032
|
variant: "primary",
|
|
1370
|
-
disabled: actionPending || selectedBranch.length === 0 || newBranch.trim().length === 0,
|
|
2033
|
+
disabled: importing ? importBlocked : actionPending || !canCreate || selectedBranch.length === 0 || newBranch.trim().length === 0,
|
|
1371
2034
|
onClick: () => {
|
|
1372
2035
|
onSubmit();
|
|
1373
2036
|
},
|
|
1374
|
-
children: t("worktree.create")
|
|
2037
|
+
children: importing ? t("worktree.import") : t("worktree.create")
|
|
1375
2038
|
})] }),
|
|
1376
|
-
children:
|
|
2039
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
2040
|
+
className: worktree_css_default.worktreeModalTabs,
|
|
2041
|
+
role: "tablist",
|
|
2042
|
+
"aria-label": t("worktree.title"),
|
|
2043
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
2044
|
+
className: worktree_css_default.worktreeModalTab,
|
|
2045
|
+
type: "button",
|
|
2046
|
+
role: "tab",
|
|
2047
|
+
"aria-selected": mode === "create",
|
|
2048
|
+
disabled: actionPending,
|
|
2049
|
+
onClick: () => {
|
|
2050
|
+
onModeChange("create");
|
|
2051
|
+
},
|
|
2052
|
+
children: t("worktree.tabCreate")
|
|
2053
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
2054
|
+
className: worktree_css_default.worktreeModalTab,
|
|
2055
|
+
type: "button",
|
|
2056
|
+
role: "tab",
|
|
2057
|
+
"aria-selected": mode === "import",
|
|
2058
|
+
disabled: actionPending,
|
|
2059
|
+
onClick: () => {
|
|
2060
|
+
onModeChange("import");
|
|
2061
|
+
},
|
|
2062
|
+
children: t("worktree.tabImport")
|
|
2063
|
+
})]
|
|
2064
|
+
}), importing ? (0, react_jsx_runtime.jsxs)("div", {
|
|
2065
|
+
className: worktree_css_default.worktreeImportCandidates,
|
|
2066
|
+
role: "tabpanel",
|
|
2067
|
+
children: [
|
|
2068
|
+
importCandidates.status === "loading" && importCandidates.candidates.length === 0 && (0, react_jsx_runtime.jsx)("p", {
|
|
2069
|
+
className: worktree_css_default.message,
|
|
2070
|
+
children: t("worktree.importLoading")
|
|
2071
|
+
}),
|
|
2072
|
+
importCandidates.status === "error" && (0, react_jsx_runtime.jsxs)("div", {
|
|
2073
|
+
className: worktree_css_default.worktreeImportError,
|
|
2074
|
+
role: "alert",
|
|
2075
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
2076
|
+
className: worktree_css_default.message,
|
|
2077
|
+
children: formatWorktreeViewError(importCandidates.error, t)
|
|
2078
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2079
|
+
variant: "outline",
|
|
2080
|
+
disabled: actionPending,
|
|
2081
|
+
onClick: onRetryImportCandidates,
|
|
2082
|
+
children: t("action.retry")
|
|
2083
|
+
})]
|
|
2084
|
+
}),
|
|
2085
|
+
importCandidates.candidates.length === 0 && importCandidates.status === "ready" && (0, react_jsx_runtime.jsx)("p", {
|
|
2086
|
+
className: worktree_css_default.message,
|
|
2087
|
+
children: t("worktree.importEmpty")
|
|
2088
|
+
}),
|
|
2089
|
+
importCandidates.candidates.length > 0 && (0, react_jsx_runtime.jsxs)("label", {
|
|
2090
|
+
className: worktree_css_default.modalField,
|
|
2091
|
+
children: [t("worktree.tabImport"), (0, react_jsx_runtime.jsxs)("select", {
|
|
2092
|
+
className: worktree_css_default.worktreeImportSelect,
|
|
2093
|
+
"data-worktree-import-select": true,
|
|
2094
|
+
"aria-label": t("worktree.tabImport"),
|
|
2095
|
+
value: selectedImportPath ?? "",
|
|
2096
|
+
disabled: actionPending,
|
|
2097
|
+
onChange: (event) => {
|
|
2098
|
+
onSelectedImportPathChange(event.currentTarget.value);
|
|
2099
|
+
},
|
|
2100
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
2101
|
+
value: "",
|
|
2102
|
+
disabled: true,
|
|
2103
|
+
children: t("worktree.importPlaceholder")
|
|
2104
|
+
}), importCandidates.candidates.map((candidate) => (0, react_jsx_runtime.jsxs)("option", {
|
|
2105
|
+
value: candidate.absolutePath,
|
|
2106
|
+
children: [
|
|
2107
|
+
candidate.branch,
|
|
2108
|
+
" — ",
|
|
2109
|
+
candidate.absolutePath
|
|
2110
|
+
]
|
|
2111
|
+
}, candidate.absolutePath))]
|
|
2112
|
+
})]
|
|
2113
|
+
})
|
|
2114
|
+
]
|
|
2115
|
+
}) : readError !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
2116
|
+
className: worktree_css_default.gitReadiness,
|
|
2117
|
+
"data-worktree-readiness": "error",
|
|
2118
|
+
role: "alert",
|
|
2119
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
2120
|
+
className: worktree_css_default.message,
|
|
2121
|
+
"data-error": "true",
|
|
2122
|
+
children: formatWorktreeViewError(readError, t)
|
|
2123
|
+
}), readError.retryable && onRetry !== void 0 && (0, react_jsx_runtime.jsx)("button", {
|
|
2124
|
+
type: "button",
|
|
2125
|
+
className: worktree_css_default.retryButton,
|
|
2126
|
+
disabled: actionPending,
|
|
2127
|
+
onClick: onRetry,
|
|
2128
|
+
children: t("action.retry")
|
|
2129
|
+
})]
|
|
2130
|
+
}) : canCreate ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("label", {
|
|
1377
2131
|
className: worktree_css_default.modalField,
|
|
1378
2132
|
children: [t("worktree.baseBranch"), (0, react_jsx_runtime.jsx)("select", {
|
|
1379
2133
|
className: worktree_css_default.actionSelect,
|
|
@@ -1416,7 +2170,7 @@ window.__ModuleLoader__.load({
|
|
|
1416
2170
|
"aria-label": t("worktree.setup.commands"),
|
|
1417
2171
|
children: setupCommands.join("\n")
|
|
1418
2172
|
})]
|
|
1419
|
-
})
|
|
2173
|
+
})]
|
|
1420
2174
|
});
|
|
1421
2175
|
}
|
|
1422
2176
|
function WorktreeRemovalDialog({ t, worktree, actionPending, onClose, onSubmit }) {
|
|
@@ -1429,7 +2183,7 @@ window.__ModuleLoader__.load({
|
|
|
1429
2183
|
},
|
|
1430
2184
|
closeLabel: t("dialog.closeWorktreeRemove"),
|
|
1431
2185
|
title: t("worktree.remove"),
|
|
1432
|
-
description: t("worktree.removeDescription", { name: worktree.branch }),
|
|
2186
|
+
description: worktree.source === "external" ? t("worktree.removeExternalDescription", { name: worktree.branch }) : t("worktree.removeDescription", { name: worktree.branch }),
|
|
1433
2187
|
footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1434
2188
|
variant: "outline",
|
|
1435
2189
|
disabled: actionPending,
|
|
@@ -1453,6 +2207,17 @@ window.__ModuleLoader__.load({
|
|
|
1453
2207
|
function bindingIdsFor(bindings, worktreeId) {
|
|
1454
2208
|
return bindings.filter((binding) => binding.worktreeId === worktreeId).map((binding) => binding.sessionId);
|
|
1455
2209
|
}
|
|
2210
|
+
function clearSessionGroupExpansion(current, groupKeys) {
|
|
2211
|
+
const next = { ...current };
|
|
2212
|
+
for (const key of groupKeys) delete next[key];
|
|
2213
|
+
return next;
|
|
2214
|
+
}
|
|
2215
|
+
function isCompleteWorktreeWorkspaceSnapshot(workspaceIds, views) {
|
|
2216
|
+
if (views.length !== workspaceIds.length) return false;
|
|
2217
|
+
const expected = new Set(workspaceIds);
|
|
2218
|
+
const actual = new Set(views.map((view) => view.workspaceId));
|
|
2219
|
+
return actual.size === expected.size && [...expected].every((id) => actual.has(id));
|
|
2220
|
+
}
|
|
1456
2221
|
function includesText(value, query) {
|
|
1457
2222
|
return value.toLocaleLowerCase().includes(query);
|
|
1458
2223
|
}
|
|
@@ -1464,14 +2229,118 @@ window.__ModuleLoader__.load({
|
|
|
1464
2229
|
if (view.worktrees.some((record) => includesText(record.branch, query) || includesText(record.absolutePath, query))) return true;
|
|
1465
2230
|
return view.bindings.some((binding) => sessionMatchesQuery(binding.sessionId, sessions, query));
|
|
1466
2231
|
}
|
|
2232
|
+
function resolveCurrentSessionLocation(currentSessionId, workspaces, views) {
|
|
2233
|
+
if (currentSessionId === void 0) return void 0;
|
|
2234
|
+
const workspace = workspaces.find((candidate) => candidate.sessionIds.includes(currentSessionId));
|
|
2235
|
+
if (workspace === void 0) return void 0;
|
|
2236
|
+
const view = views.find((candidate) => candidate.workspaceId === workspace.workspaceId);
|
|
2237
|
+
if (view === void 0) return void 0;
|
|
2238
|
+
const binding = view.bindings.find((candidate) => candidate.sessionId === currentSessionId);
|
|
2239
|
+
if (binding === void 0) return {
|
|
2240
|
+
sessionId: currentSessionId,
|
|
2241
|
+
workspaceId: workspace.workspaceId,
|
|
2242
|
+
groupKey: "main:" + workspace.workspaceId,
|
|
2243
|
+
kind: "main"
|
|
2244
|
+
};
|
|
2245
|
+
const worktree = view.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId && candidate.workspaceId === workspace.workspaceId);
|
|
2246
|
+
if (worktree === void 0) return void 0;
|
|
2247
|
+
return {
|
|
2248
|
+
sessionId: currentSessionId,
|
|
2249
|
+
workspaceId: workspace.workspaceId,
|
|
2250
|
+
groupKey: "worktree:" + worktree.worktreeId,
|
|
2251
|
+
kind: "worktree",
|
|
2252
|
+
worktreeId: worktree.worktreeId
|
|
2253
|
+
};
|
|
2254
|
+
}
|
|
2255
|
+
function currentSessionRevealKeys(location) {
|
|
2256
|
+
if (location === void 0) return [];
|
|
2257
|
+
return [
|
|
2258
|
+
"workspace:" + location.workspaceId,
|
|
2259
|
+
location.kind === "main" ? "main:" + location.workspaceId : "worktree:" + location.worktreeId,
|
|
2260
|
+
"session-group:" + location.groupKey
|
|
2261
|
+
];
|
|
2262
|
+
}
|
|
2263
|
+
function shouldRevealCurrentSessionGroup(sessionIds, currentSessionId) {
|
|
2264
|
+
if (currentSessionId === void 0 || sessionIds.length <= 5) return false;
|
|
2265
|
+
return sessionIds.indexOf(currentSessionId) >= 5;
|
|
2266
|
+
}
|
|
2267
|
+
function isSessionGroupAutoExpanded(sessionIds, currentSessionId, currentSessionRevealActive) {
|
|
2268
|
+
return currentSessionRevealActive && shouldRevealCurrentSessionGroup(sessionIds, currentSessionId);
|
|
2269
|
+
}
|
|
2270
|
+
//#endregion
|
|
2271
|
+
//#region lib/client/worktree-session-position.js
|
|
2272
|
+
function scrollCurrentSessionIntoView(root, sessionId) {
|
|
2273
|
+
if (root === null) return false;
|
|
2274
|
+
const row = Array.from(root.querySelectorAll("[data-session-id]")).find((candidate) => candidate.dataset.sessionId === sessionId);
|
|
2275
|
+
if (row === void 0) return false;
|
|
2276
|
+
row.scrollIntoView({ block: "nearest" });
|
|
2277
|
+
return true;
|
|
2278
|
+
}
|
|
1467
2279
|
//#endregion
|
|
1468
2280
|
//#region lib/client/worktree-surface-rows.js
|
|
1469
2281
|
function rowHalf(event) {
|
|
1470
2282
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
1471
2283
|
return event.clientY < rect.top + rect.height / 2 ? "before" : "after";
|
|
1472
2284
|
}
|
|
2285
|
+
function sessionStatusLabel(t, status) {
|
|
2286
|
+
switch (status.labelKey) {
|
|
2287
|
+
case "running": return t("session.status.running");
|
|
2288
|
+
case "subagentsRunning": return t(status.runningSubagentCount === 1 ? "session.status.subagentsRunning.one" : "session.status.subagentsRunning.other", { n: status.runningSubagentCount });
|
|
2289
|
+
case "idle": return t("session.status.idle");
|
|
2290
|
+
case "waitingApproval": return t("session.status.waitingApproval");
|
|
2291
|
+
case "planReview": return t("session.status.planReview");
|
|
2292
|
+
case "waitingAnswer": return t("session.status.waitingAnswer");
|
|
2293
|
+
case "completed": return t("session.status.completed");
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
function sessionTimeLabel(t, value) {
|
|
2297
|
+
switch (value.unit) {
|
|
2298
|
+
case "now": return t("session.time.now");
|
|
2299
|
+
case "minutes": return t("session.time.minutes", { n: value.n });
|
|
2300
|
+
case "hours": return t("session.time.hours", { n: value.n });
|
|
2301
|
+
case "days": return t("session.time.days", { n: value.n });
|
|
2302
|
+
case "months": return t("session.time.months", { n: value.n });
|
|
2303
|
+
case "years": return t("session.time.years", { n: value.n });
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
/** Native Workspace hover-card time copy, including the trailing "ago" marker. */
|
|
2307
|
+
function sessionHoverTimeLabel(t, value) {
|
|
2308
|
+
const label = sessionTimeLabel(t, value);
|
|
2309
|
+
return value.unit === "now" ? label : t("session.time.ago", { t: label });
|
|
2310
|
+
}
|
|
2311
|
+
/** Native Workspace hover-card status list, including a secondary subagent status when relevant. */
|
|
2312
|
+
function sessionHoverStatuses(presentation) {
|
|
2313
|
+
if (presentation.runningSubagentCount === 0 || presentation.status.labelKey === "subagentsRunning") return [presentation.status];
|
|
2314
|
+
return [presentation.status, {
|
|
2315
|
+
state: "ongoing",
|
|
2316
|
+
labelKey: "subagentsRunning",
|
|
2317
|
+
runningSubagentCount: presentation.runningSubagentCount
|
|
2318
|
+
}];
|
|
2319
|
+
}
|
|
2320
|
+
/** Native Workspace Session hover-card details, adapted to the Worktree row projection. */
|
|
2321
|
+
function WorktreeSessionHoverContent({ label, blank, presentation, t }) {
|
|
2322
|
+
const statuses = presentation === void 0 ? [] : sessionHoverStatuses(presentation);
|
|
2323
|
+
const timeValue = !blank && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
|
|
2324
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2325
|
+
className: worktree_css_default.sessionHoverContent,
|
|
2326
|
+
children: [
|
|
2327
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
2328
|
+
className: worktree_css_default.sessionHoverTitle,
|
|
2329
|
+
children: label
|
|
2330
|
+
}),
|
|
2331
|
+
!blank && timeValue !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
2332
|
+
className: worktree_css_default.sessionHoverTime,
|
|
2333
|
+
children: sessionHoverTimeLabel(t, timeValue)
|
|
2334
|
+
}),
|
|
2335
|
+
statuses.map((status) => (0, react_jsx_runtime.jsxs)("div", {
|
|
2336
|
+
className: worktree_css_default.sessionHoverStatus,
|
|
2337
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: status.state }), (0, react_jsx_runtime.jsx)("span", { children: sessionStatusLabel(t, status) })]
|
|
2338
|
+
}, `${status.labelKey}-${status.runningSubagentCount}`))
|
|
2339
|
+
]
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
1473
2342
|
/** Workspace row using the native DSH menu, fixed action column, and drag contract. */
|
|
1474
|
-
function WorktreeWorkspaceRow({ t, workspace, expanded, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
|
|
2343
|
+
function WorktreeWorkspaceRow({ t, workspace, expanded, hasOngoingSession, actionPending, menuOpen, drag, onToggle, onCreateWorktree, onRename, onDelete, onMenuOpenChange }) {
|
|
1475
2344
|
const workspaceMenuItems = [{
|
|
1476
2345
|
id: "rename",
|
|
1477
2346
|
label: t("workspace.rename"),
|
|
@@ -1488,6 +2357,7 @@ window.__ModuleLoader__.load({
|
|
|
1488
2357
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
1489
2358
|
className: `${worktree_css_default.workspaceRow} ${markerClass}`,
|
|
1490
2359
|
"data-workspace-drag": drag.active ? "active" : void 0,
|
|
2360
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
1491
2361
|
"data-menu-open": menuOpen || void 0,
|
|
1492
2362
|
draggable: true,
|
|
1493
2363
|
onClick: () => {
|
|
@@ -1533,50 +2403,61 @@ window.__ModuleLoader__.load({
|
|
|
1533
2403
|
}),
|
|
1534
2404
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
1535
2405
|
className: `${worktree_css_default.treeActionSlot} ${worktree_css_default.workspaceActions}`,
|
|
1536
|
-
children: [
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
1552
|
-
type: "button",
|
|
1553
|
-
className: worktree_css_default.iconButton,
|
|
1554
|
-
"data-workspace-menu": true,
|
|
1555
|
-
"aria-label": t("workspace.options", { name: workspace.title }),
|
|
1556
|
-
onClick: (event) => {
|
|
1557
|
-
event.stopPropagation();
|
|
1558
|
-
onMenuOpenChange(!menuOpen);
|
|
2406
|
+
children: [
|
|
2407
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2408
|
+
className: worktree_css_default.groupActivity,
|
|
2409
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
2410
|
+
role: hasOngoingSession && !expanded ? "img" : void 0,
|
|
2411
|
+
"aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2412
|
+
title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2413
|
+
children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
|
|
2414
|
+
}),
|
|
2415
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2416
|
+
className: worktree_css_default.menuAction,
|
|
2417
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2418
|
+
open: menuOpen,
|
|
2419
|
+
onClose: () => {
|
|
2420
|
+
onMenuOpenChange(false);
|
|
1559
2421
|
},
|
|
1560
|
-
|
|
2422
|
+
items: workspaceMenuItems,
|
|
2423
|
+
onSelect: (id) => {
|
|
2424
|
+
onMenuOpenChange(false);
|
|
2425
|
+
if (id === "rename") onRename();
|
|
2426
|
+
if (id === "delete") onDelete();
|
|
2427
|
+
},
|
|
2428
|
+
portal: true,
|
|
2429
|
+
closeOnPointerLeave: true,
|
|
2430
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2431
|
+
type: "button",
|
|
2432
|
+
className: worktree_css_default.iconButton,
|
|
2433
|
+
"data-workspace-menu": true,
|
|
2434
|
+
"aria-label": t("workspace.options", { name: workspace.title }),
|
|
2435
|
+
onClick: (event) => {
|
|
2436
|
+
event.stopPropagation();
|
|
2437
|
+
onMenuOpenChange(!menuOpen);
|
|
2438
|
+
},
|
|
2439
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2440
|
+
})
|
|
1561
2441
|
})
|
|
2442
|
+
}),
|
|
2443
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
2444
|
+
type: "button",
|
|
2445
|
+
className: worktree_css_default.iconButton,
|
|
2446
|
+
"data-add-worktree": true,
|
|
2447
|
+
"aria-label": t("workspace.addWorktree", { name: workspace.title }),
|
|
2448
|
+
onClick: (event) => {
|
|
2449
|
+
event.stopPropagation();
|
|
2450
|
+
onCreateWorktree();
|
|
2451
|
+
},
|
|
2452
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1562
2453
|
})
|
|
1563
|
-
|
|
1564
|
-
type: "button",
|
|
1565
|
-
className: worktree_css_default.iconButton,
|
|
1566
|
-
"data-add-worktree": true,
|
|
1567
|
-
"aria-label": t("workspace.addWorktree", { name: workspace.title }),
|
|
1568
|
-
onClick: (event) => {
|
|
1569
|
-
event.stopPropagation();
|
|
1570
|
-
onCreateWorktree();
|
|
1571
|
-
},
|
|
1572
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1573
|
-
})]
|
|
2454
|
+
]
|
|
1574
2455
|
})
|
|
1575
2456
|
]
|
|
1576
2457
|
});
|
|
1577
2458
|
}
|
|
1578
2459
|
/** Shared Main/Worktree group row with parameterized icon, state, and actions. */
|
|
1579
|
-
function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
|
|
2460
|
+
function WorktreeGroupRow({ t, kind, label, worktreeId, expanded, hasOngoingSession, icon, workspaceTitle, state, stateLabel, onToggle, onCreateSession, menu, drag }) {
|
|
1580
2461
|
const main = kind === "main";
|
|
1581
2462
|
const markerClass = drag?.marker === "before" ? worktree_css_default.dropBefore : drag?.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
1582
2463
|
const dragProps = drag === void 0 ? {} : {
|
|
@@ -1603,6 +2484,7 @@ window.__ModuleLoader__.load({
|
|
|
1603
2484
|
className: `${worktree_css_default.worktreeRow} ${markerClass}`,
|
|
1604
2485
|
"data-main-group": main ? "true" : void 0,
|
|
1605
2486
|
"data-main-expanded": main ? String(expanded) : void 0,
|
|
2487
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
1606
2488
|
"data-menu-open": menu?.open ? "true" : void 0,
|
|
1607
2489
|
"data-worktree-drag": drag?.active ? "active" : void 0,
|
|
1608
2490
|
...dragProps,
|
|
@@ -1637,50 +2519,77 @@ window.__ModuleLoader__.load({
|
|
|
1637
2519
|
}),
|
|
1638
2520
|
(0, react_jsx_runtime.jsxs)("span", {
|
|
1639
2521
|
className: worktree_css_default.treeActionSlot,
|
|
1640
|
-
children: [
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
menu.onOpenChange(false);
|
|
1656
|
-
if (id === "remove") menu.onRemove();
|
|
1657
|
-
},
|
|
1658
|
-
portal: true,
|
|
1659
|
-
closeOnPointerLeave: true,
|
|
1660
|
-
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
1661
|
-
type: "button",
|
|
1662
|
-
className: worktree_css_default.iconButton,
|
|
1663
|
-
"data-worktree-menu": true,
|
|
1664
|
-
"aria-label": t("worktree.options", { name: menu.label }),
|
|
1665
|
-
onClick: (event) => {
|
|
1666
|
-
event.stopPropagation();
|
|
1667
|
-
menu.onOpenChange(!menu.open);
|
|
2522
|
+
children: [
|
|
2523
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
2524
|
+
className: worktree_css_default.groupActivity,
|
|
2525
|
+
"data-group-activity": hasOngoingSession && !expanded ? "true" : void 0,
|
|
2526
|
+
role: hasOngoingSession && !expanded ? "img" : void 0,
|
|
2527
|
+
"aria-label": hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2528
|
+
title: hasOngoingSession && !expanded ? t("session.status.running") : void 0,
|
|
2529
|
+
children: hasOngoingSession && !expanded && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
|
|
2530
|
+
}),
|
|
2531
|
+
menu !== void 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
2532
|
+
className: worktree_css_default.menuAction,
|
|
2533
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2534
|
+
open: menu.open,
|
|
2535
|
+
onClose: () => {
|
|
2536
|
+
menu.onOpenChange(false);
|
|
1668
2537
|
},
|
|
1669
|
-
|
|
2538
|
+
items: [
|
|
2539
|
+
...menu.showCreate ? [{
|
|
2540
|
+
id: "create",
|
|
2541
|
+
label: t("worktree.createNew"),
|
|
2542
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {}),
|
|
2543
|
+
disabled: menu.disabled || menu.onCreateWorktree === void 0
|
|
2544
|
+
}] : [],
|
|
2545
|
+
{
|
|
2546
|
+
id: "copy-path",
|
|
2547
|
+
label: t("worktree.copyPath"),
|
|
2548
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}),
|
|
2549
|
+
disabled: menu.disabled
|
|
2550
|
+
},
|
|
2551
|
+
...menu.showRemove ? [{
|
|
2552
|
+
id: "remove",
|
|
2553
|
+
label: t("worktree.remove"),
|
|
2554
|
+
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {}),
|
|
2555
|
+
danger: true,
|
|
2556
|
+
disabled: menu.disabled || menu.onRemove === void 0
|
|
2557
|
+
}] : []
|
|
2558
|
+
],
|
|
2559
|
+
onSelect: (id) => {
|
|
2560
|
+
menu.onOpenChange(false);
|
|
2561
|
+
if (id === "create" && menu.showCreate) menu.onCreateWorktree?.();
|
|
2562
|
+
if (id === "copy-path") (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(menu.copyPath);
|
|
2563
|
+
if (id === "remove" && menu.showRemove) menu.onRemove?.();
|
|
2564
|
+
},
|
|
2565
|
+
portal: true,
|
|
2566
|
+
closeOnPointerLeave: true,
|
|
2567
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2568
|
+
type: "button",
|
|
2569
|
+
className: worktree_css_default.iconButton,
|
|
2570
|
+
"data-worktree-menu": true,
|
|
2571
|
+
"aria-label": t("worktree.options", { name: menu.label }),
|
|
2572
|
+
onClick: (event) => {
|
|
2573
|
+
event.stopPropagation();
|
|
2574
|
+
menu.onOpenChange(!menu.open);
|
|
2575
|
+
},
|
|
2576
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2577
|
+
})
|
|
1670
2578
|
})
|
|
2579
|
+
}),
|
|
2580
|
+
onCreateSession !== void 0 && (0, react_jsx_runtime.jsx)("button", {
|
|
2581
|
+
type: "button",
|
|
2582
|
+
className: worktree_css_default.iconButton,
|
|
2583
|
+
"data-add-main-session": main ? "true" : void 0,
|
|
2584
|
+
"data-add-session": main ? void 0 : "true",
|
|
2585
|
+
"aria-label": t("worktree.addSession", { name: workspaceTitle }),
|
|
2586
|
+
onClick: (event) => {
|
|
2587
|
+
event.stopPropagation();
|
|
2588
|
+
onCreateSession();
|
|
2589
|
+
},
|
|
2590
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1671
2591
|
})
|
|
1672
|
-
|
|
1673
|
-
type: "button",
|
|
1674
|
-
className: worktree_css_default.iconButton,
|
|
1675
|
-
"data-add-main-session": main ? "true" : void 0,
|
|
1676
|
-
"data-add-session": main ? void 0 : "true",
|
|
1677
|
-
"aria-label": t("worktree.addSession", { name: workspaceTitle }),
|
|
1678
|
-
onClick: (event) => {
|
|
1679
|
-
event.stopPropagation();
|
|
1680
|
-
onCreateSession();
|
|
1681
|
-
},
|
|
1682
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {})
|
|
1683
|
-
})]
|
|
2592
|
+
]
|
|
1684
2593
|
})
|
|
1685
2594
|
]
|
|
1686
2595
|
});
|
|
@@ -1696,7 +2605,7 @@ window.__ModuleLoader__.load({
|
|
|
1696
2605
|
});
|
|
1697
2606
|
}
|
|
1698
2607
|
/** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
|
|
1699
|
-
function WorktreeSessionRow({ t, sessionId, blank, label, drag, actionPending, onOpen, onRename, onFork, onArchive }) {
|
|
2608
|
+
function WorktreeSessionRow({ t, sessionId, blank, current, label, drag, actionPending, onOpen, onRename, onFork, onArchive, presentation }) {
|
|
1700
2609
|
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
1701
2610
|
const markerClass = drag.marker === "before" ? worktree_css_default.dropBefore : drag.marker === "after" ? worktree_css_default.dropAfter : "";
|
|
1702
2611
|
const sessionMenuItems = [
|
|
@@ -1719,82 +2628,116 @@ window.__ModuleLoader__.load({
|
|
|
1719
2628
|
disabled: onArchive === void 0 || actionPending
|
|
1720
2629
|
}
|
|
1721
2630
|
];
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
className: worktree_css_default.
|
|
1757
|
-
|
|
2631
|
+
const statusLabel = presentation === void 0 ? void 0 : sessionStatusLabel(t, presentation.status);
|
|
2632
|
+
const showTrailingStatus = !blank && presentation !== void 0 && (presentation.status.state !== "done" || presentation.completed);
|
|
2633
|
+
const timeValue = !blank && !showTrailingStatus && presentation?.updatedAt !== void 0 ? relativeTime(presentation.updatedAt, Date.now()) : void 0;
|
|
2634
|
+
const timeLabel = timeValue === void 0 ? void 0 : sessionTimeLabel(t, timeValue);
|
|
2635
|
+
return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
2636
|
+
anchor: (0, react_jsx_runtime.jsxs)("div", {
|
|
2637
|
+
className: `${worktree_css_default.treeSessionRow} ${markerClass}`,
|
|
2638
|
+
"data-session-id": sessionId,
|
|
2639
|
+
"data-session-blank": blank ? "true" : void 0,
|
|
2640
|
+
"data-session-current": current ? "true" : void 0,
|
|
2641
|
+
"data-session-drag": drag.active ? "active" : void 0,
|
|
2642
|
+
"data-menu-open": menuOpen || void 0,
|
|
2643
|
+
role: "treeitem",
|
|
2644
|
+
"aria-current": current ? "true" : void 0,
|
|
2645
|
+
draggable: true,
|
|
2646
|
+
onDragStart: (event) => {
|
|
2647
|
+
event.dataTransfer.effectAllowed = "move";
|
|
2648
|
+
event.dataTransfer.setData("text/plain", sessionId);
|
|
2649
|
+
drag.start();
|
|
2650
|
+
},
|
|
2651
|
+
onDragEnd: drag.end,
|
|
2652
|
+
onDragOver: (event) => {
|
|
2653
|
+
if (!drag.active) return;
|
|
2654
|
+
event.preventDefault();
|
|
2655
|
+
event.dataTransfer.dropEffect = "move";
|
|
2656
|
+
drag.hover(rowHalf(event));
|
|
2657
|
+
},
|
|
2658
|
+
onDrop: (event) => {
|
|
2659
|
+
if (!drag.active) return;
|
|
2660
|
+
event.preventDefault();
|
|
2661
|
+
drag.drop(rowHalf(event));
|
|
2662
|
+
},
|
|
2663
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
2664
|
+
type: "button",
|
|
2665
|
+
className: worktree_css_default.treeSessionContent,
|
|
2666
|
+
onClick: onOpen,
|
|
2667
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
2668
|
+
className: worktree_css_default.sessionLabel,
|
|
2669
|
+
children: label
|
|
2670
|
+
})
|
|
2671
|
+
}), !blank && (0, react_jsx_runtime.jsxs)("span", {
|
|
2672
|
+
className: worktree_css_default.sessionTrailing,
|
|
2673
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
2674
|
+
className: worktree_css_default.sessionMeta,
|
|
2675
|
+
children: showTrailingStatus && presentation !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
2676
|
+
className: worktree_css_default.sessionStatus,
|
|
2677
|
+
"data-session-status": statusLabel,
|
|
2678
|
+
role: "img",
|
|
2679
|
+
"aria-label": statusLabel,
|
|
2680
|
+
title: statusLabel,
|
|
2681
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: presentation.status.state })
|
|
2682
|
+
}) : timeLabel !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
2683
|
+
className: worktree_css_default.sessionTime,
|
|
2684
|
+
"data-session-time": true,
|
|
2685
|
+
children: timeLabel
|
|
2686
|
+
}) : null
|
|
2687
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
2688
|
+
className: worktree_css_default.rowActions,
|
|
2689
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2690
|
+
open: menuOpen,
|
|
2691
|
+
onClose: () => {
|
|
2692
|
+
setMenuOpen(false);
|
|
2693
|
+
},
|
|
2694
|
+
items: sessionMenuItems,
|
|
2695
|
+
onSelect: (id) => {
|
|
2696
|
+
setMenuOpen(false);
|
|
2697
|
+
if (id === "rename") onRename?.(sessionId, label);
|
|
2698
|
+
if (id === "fork") onFork?.(sessionId);
|
|
2699
|
+
if (id === "archive") onArchive?.(sessionId);
|
|
2700
|
+
},
|
|
2701
|
+
portal: true,
|
|
2702
|
+
closeOnPointerLeave: true,
|
|
2703
|
+
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
2704
|
+
type: "button",
|
|
2705
|
+
className: worktree_css_default.iconButton,
|
|
2706
|
+
"data-session-menu": true,
|
|
2707
|
+
"aria-label": t("session.options", { name: label }),
|
|
2708
|
+
onClick: (event) => {
|
|
2709
|
+
event.stopPropagation();
|
|
2710
|
+
setMenuOpen((current) => !current);
|
|
2711
|
+
},
|
|
2712
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
2713
|
+
})
|
|
2714
|
+
})
|
|
2715
|
+
})]
|
|
1758
2716
|
})]
|
|
1759
|
-
}),
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
if (id === "archive") onArchive?.(sessionId);
|
|
1772
|
-
},
|
|
1773
|
-
portal: true,
|
|
1774
|
-
closeOnPointerLeave: true,
|
|
1775
|
-
anchor: (0, react_jsx_runtime.jsx)("button", {
|
|
1776
|
-
type: "button",
|
|
1777
|
-
className: worktree_css_default.iconButton,
|
|
1778
|
-
"data-session-menu": true,
|
|
1779
|
-
"aria-label": t("session.options", { name: label }),
|
|
1780
|
-
onClick: (event) => {
|
|
1781
|
-
event.stopPropagation();
|
|
1782
|
-
setMenuOpen((current) => !current);
|
|
1783
|
-
},
|
|
1784
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {})
|
|
1785
|
-
})
|
|
1786
|
-
})
|
|
1787
|
-
})]
|
|
2717
|
+
}),
|
|
2718
|
+
content: (0, react_jsx_runtime.jsx)(WorktreeSessionHoverContent, {
|
|
2719
|
+
label,
|
|
2720
|
+
blank,
|
|
2721
|
+
presentation,
|
|
2722
|
+
t
|
|
2723
|
+
}),
|
|
2724
|
+
openDelayMs: 500,
|
|
2725
|
+
disabled: menuOpen || drag.active,
|
|
2726
|
+
copyText: blank ? void 0 : label,
|
|
2727
|
+
copyLabel: t("copy"),
|
|
2728
|
+
copiedLabel: t("hover.copied")
|
|
1788
2729
|
});
|
|
1789
2730
|
}
|
|
1790
|
-
function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, expanded, actionPending, sessions, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
|
|
2731
|
+
function WorktreeSessionGroup({ t, groupKey, sessionIds, workspaceId, currentSessionId, expanded, actionPending, sessions, sessionPresentations, dragState, onToggleExpanded, onStartDrag, onHoverDrag, onClearDrag, onFinishDrag, onCommitDrag, onOpen, onRename, onFork, onArchive }) {
|
|
1791
2732
|
const visibleSessionIds = expanded ? sessionIds : sessionIds.slice(0, 5);
|
|
1792
2733
|
const sameGroupDrag = dragState?.groupKey === groupKey;
|
|
1793
2734
|
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [visibleSessionIds.map((sessionId) => (0, react_jsx_runtime.jsx)(WorktreeSessionRow, {
|
|
1794
2735
|
t,
|
|
1795
2736
|
sessionId,
|
|
1796
2737
|
blank: isBlankSession(sessionId, sessions),
|
|
2738
|
+
current: sessionId === currentSessionId,
|
|
1797
2739
|
label: sessionLabel(sessionId, sessions, t),
|
|
2740
|
+
presentation: sessionPresentations[sessionId],
|
|
1798
2741
|
drag: {
|
|
1799
2742
|
active: sameGroupDrag,
|
|
1800
2743
|
marker: sameGroupDrag && dragState.over?.sessionId === sessionId ? dragState.over.half : null,
|
|
@@ -1846,6 +2789,33 @@ window.__ModuleLoader__.load({
|
|
|
1846
2789
|
status: "idle",
|
|
1847
2790
|
views: []
|
|
1848
2791
|
};
|
|
2792
|
+
const EMPTY_PERMISSION_NOTICE = void 0;
|
|
2793
|
+
const EMPTY_PERMISSION_NOTICE_SUBSCRIBE = () => () => {};
|
|
2794
|
+
const EMPTY_PERMISSION_NOTICE_SNAPSHOT = () => EMPTY_PERMISSION_NOTICE;
|
|
2795
|
+
const EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE = () => () => {};
|
|
2796
|
+
const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => void 0;
|
|
2797
|
+
const EMPTY_FORK_RECOVERY_SNAPSHOT = {
|
|
2798
|
+
revision: 0,
|
|
2799
|
+
pending: []
|
|
2800
|
+
};
|
|
2801
|
+
const EMPTY_FORK_RECOVERY_STORE = {
|
|
2802
|
+
getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
|
|
2803
|
+
subscribe: () => () => {}
|
|
2804
|
+
};
|
|
2805
|
+
function updatedAtById(sessionIds, sessions) {
|
|
2806
|
+
return Object.fromEntries(sessionIds.map((sessionId) => [sessionId, sessions.byId[sessionId]?.updatedAt]));
|
|
2807
|
+
}
|
|
2808
|
+
function forkRecoveryError(recovery) {
|
|
2809
|
+
const error = toNativeWorktreeViewError(recovery.error);
|
|
2810
|
+
return {
|
|
2811
|
+
...error,
|
|
2812
|
+
code: error.code === "WORKTREE_VIEW_FAILED" ? "SESSION_BINDING_FAILED" : error.code,
|
|
2813
|
+
details: {
|
|
2814
|
+
...error.details ?? {},
|
|
2815
|
+
sessionId: recovery.childSessionId
|
|
2816
|
+
}
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
1849
2819
|
function useStableWorkspaceIds(workspaces) {
|
|
1850
2820
|
const next = workspaces.map((workspace) => workspace.workspaceId);
|
|
1851
2821
|
const previousRef = (0, react.useRef)([]);
|
|
@@ -1857,20 +2827,49 @@ window.__ModuleLoader__.load({
|
|
|
1857
2827
|
* Peer Worktree navigation surface. It keeps the original DSH Workspace mode
|
|
1858
2828
|
* intact and renders a browser-local Workspace → Worktree → Session projection.
|
|
1859
2829
|
*/
|
|
1860
|
-
function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, manager, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
|
|
2830
|
+
function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, sessionOrder, manager, permission, confirmFullAccess, fullAccessConfirmation, onPermissionResult, onPermissionNotice, permissionNotice, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, forkRecovery, retryForkSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
|
|
1861
2831
|
const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
|
|
1862
2832
|
const sessions = useSessions((state) => state);
|
|
1863
2833
|
const workspaces = useWorkspaces((state) => state);
|
|
2834
|
+
const forkRecoveryStore = forkRecovery ?? EMPTY_FORK_RECOVERY_STORE;
|
|
2835
|
+
const forkRecoverySnapshot = (0, react.useSyncExternalStore)(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
|
|
2836
|
+
const currentSessionId = sessions.current;
|
|
1864
2837
|
const workspaceIds = useStableWorkspaceIds(workspaces.items);
|
|
1865
2838
|
const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
|
|
2839
|
+
const expandSnapshot = (0, react.useSyncExternalStore)(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
|
|
2840
|
+
const permissionNoticeSnapshot = (0, react.useSyncExternalStore)(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
|
|
2841
|
+
const fullAccessConfirmationSnapshot = (0, react.useSyncExternalStore)(fullAccessConfirmation?.subscribe ?? EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT);
|
|
2842
|
+
const fullAccessConfirmationKey = fullAccessConfirmationSnapshot === void 0 ? "" : [
|
|
2843
|
+
fullAccessConfirmationSnapshot.workspaceId,
|
|
2844
|
+
fullAccessConfirmationSnapshot.worktreeId,
|
|
2845
|
+
fullAccessConfirmationSnapshot.sessionId,
|
|
2846
|
+
fullAccessConfirmationSnapshot.cwd
|
|
2847
|
+
].join("\0");
|
|
2848
|
+
const [fullAccessAcknowledged, setFullAccessAcknowledged] = (0, react.useState)(false);
|
|
2849
|
+
(0, react.useEffect)(() => {
|
|
2850
|
+
setFullAccessAcknowledged(false);
|
|
2851
|
+
}, [fullAccessConfirmationKey]);
|
|
2852
|
+
const sessionOrderSnapshot = (0, react.useSyncExternalStore)(sessionOrder.subscribe, sessionOrder.getSnapshot, sessionOrder.getSnapshot);
|
|
2853
|
+
const sessionPresentations = (0, react.useMemo)(() => deriveSessionPresentationIndex(sessions), [sessions.byId]);
|
|
1866
2854
|
const readStateRef = (0, react.useRef)(readState);
|
|
1867
2855
|
readStateRef.current = readState;
|
|
1868
2856
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
1869
|
-
const [
|
|
1870
|
-
const
|
|
1871
|
-
|
|
2857
|
+
const [currentSessionReveal, setCurrentSessionReveal] = (0, react.useState)();
|
|
2858
|
+
const searchQueryRef = (0, react.useRef)(searchQuery);
|
|
2859
|
+
searchQueryRef.current = searchQuery;
|
|
2860
|
+
const locateGenerationRef = (0, react.useRef)(0);
|
|
2861
|
+
const positionedLocateGenerationRef = (0, react.useRef)();
|
|
1872
2862
|
const [worktreeModalWorkspaceId, setWorktreeModalWorkspaceId] = (0, react.useState)();
|
|
2863
|
+
const [modalReadError, setModalReadError] = (0, react.useState)();
|
|
2864
|
+
const [modalReadLoading, setModalReadLoading] = (0, react.useState)(false);
|
|
2865
|
+
const [worktreeModalMode, setWorktreeModalMode] = (0, react.useState)("create");
|
|
2866
|
+
const [importCandidates, setImportCandidates] = (0, react.useState)({
|
|
2867
|
+
status: "idle",
|
|
2868
|
+
candidates: []
|
|
2869
|
+
});
|
|
2870
|
+
const [selectedImportPath, setSelectedImportPath] = (0, react.useState)();
|
|
1873
2871
|
const [openWorkspaceMenuId, setOpenWorkspaceMenuId] = (0, react.useState)();
|
|
2872
|
+
const [openMainMenuId, setOpenMainMenuId] = (0, react.useState)();
|
|
1874
2873
|
const [openWorktreeMenuId, setOpenWorktreeMenuId] = (0, react.useState)();
|
|
1875
2874
|
const [worktreeRemoval, setWorktreeRemoval] = (0, react.useState)();
|
|
1876
2875
|
const [selectedBranch, setSelectedBranch] = (0, react.useState)("");
|
|
@@ -1878,6 +2877,7 @@ window.__ModuleLoader__.load({
|
|
|
1878
2877
|
const [pendingSessionBinding, setPendingSessionBinding] = (0, react.useState)();
|
|
1879
2878
|
const [actionError, setActionError] = (0, react.useState)();
|
|
1880
2879
|
const [actionPending, setActionPending] = (0, react.useState)(false);
|
|
2880
|
+
const [forkRetryKey, setForkRetryKey] = (0, react.useState)();
|
|
1881
2881
|
const [sessionRenameTarget, setSessionRenameTarget] = (0, react.useState)();
|
|
1882
2882
|
const [sessionRenameDraft, setSessionRenameDraft] = (0, react.useState)("");
|
|
1883
2883
|
const [sessionRenamePending, setSessionRenamePending] = (0, react.useState)(false);
|
|
@@ -1897,6 +2897,12 @@ window.__ModuleLoader__.load({
|
|
|
1897
2897
|
const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
|
|
1898
2898
|
const worktreeDropCommitted = (0, react.useRef)(false);
|
|
1899
2899
|
const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
|
|
2900
|
+
const forkRecoveryRevisionRef = (0, react.useRef)(forkRecoverySnapshot.revision);
|
|
2901
|
+
const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader());
|
|
2902
|
+
const modalReadViewRef = (0, react.useRef)();
|
|
2903
|
+
const importCandidatesGuard = (0, react.useRef)(createWorktreeRefreshGuard());
|
|
2904
|
+
const modalWorkspaceIdRef = (0, react.useRef)(worktreeModalWorkspaceId);
|
|
2905
|
+
modalWorkspaceIdRef.current = worktreeModalWorkspaceId;
|
|
1900
2906
|
const { ref, width, bounds } = useSidebarOverlayGeometry(mode === "worktree");
|
|
1901
2907
|
const collapsed = width <= 64;
|
|
1902
2908
|
const query = searchQuery.trim().toLocaleLowerCase();
|
|
@@ -1919,13 +2925,13 @@ window.__ModuleLoader__.load({
|
|
|
1919
2925
|
}), (views) => {
|
|
1920
2926
|
setReadState({
|
|
1921
2927
|
status: "ready",
|
|
1922
|
-
views
|
|
2928
|
+
views: modalReadViewRef.current === void 0 ? views : mergeWorktreeView(views, modalReadViewRef.current)
|
|
1923
2929
|
});
|
|
1924
2930
|
}, (error) => {
|
|
1925
2931
|
if (preserveCurrent) throw error;
|
|
1926
2932
|
setReadState({
|
|
1927
2933
|
status: "error",
|
|
1928
|
-
views: [],
|
|
2934
|
+
views: modalReadViewRef.current === void 0 ? [] : [modalReadViewRef.current],
|
|
1929
2935
|
error: toWorktreeViewError(error)
|
|
1930
2936
|
});
|
|
1931
2937
|
});
|
|
@@ -1934,13 +2940,56 @@ window.__ModuleLoader__.load({
|
|
|
1934
2940
|
manager,
|
|
1935
2941
|
workspaceIds
|
|
1936
2942
|
]);
|
|
2943
|
+
const loadModalWorktreeView = (0, react.useCallback)((workspaceId) => {
|
|
2944
|
+
setModalReadError(void 0);
|
|
2945
|
+
setModalReadLoading(true);
|
|
2946
|
+
if (manager === void 0) {
|
|
2947
|
+
setModalReadLoading(false);
|
|
2948
|
+
setModalReadError({
|
|
2949
|
+
code: "WORKTREE_VIEW_UNAVAILABLE",
|
|
2950
|
+
message: "",
|
|
2951
|
+
retryable: true
|
|
2952
|
+
});
|
|
2953
|
+
return;
|
|
2954
|
+
}
|
|
2955
|
+
modalReadLoader.current.load(manager, workspaceId, (view) => {
|
|
2956
|
+
modalReadViewRef.current = view;
|
|
2957
|
+
setModalReadLoading(false);
|
|
2958
|
+
setReadState((current) => ({
|
|
2959
|
+
...current,
|
|
2960
|
+
views: mergeWorktreeView(current.views, view)
|
|
2961
|
+
}));
|
|
2962
|
+
}, (error) => {
|
|
2963
|
+
setModalReadLoading(false);
|
|
2964
|
+
setModalReadError(toWorktreeViewError(error));
|
|
2965
|
+
});
|
|
2966
|
+
}, [manager]);
|
|
1937
2967
|
(0, react.useEffect)(() => {
|
|
1938
2968
|
if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
|
|
1939
2969
|
else {
|
|
1940
2970
|
refreshGuard.current.invalidate();
|
|
2971
|
+
modalReadLoader.current.invalidate();
|
|
2972
|
+
modalReadViewRef.current = void 0;
|
|
2973
|
+
setWorktreeModalWorkspaceId(void 0);
|
|
2974
|
+
setModalReadError(void 0);
|
|
2975
|
+
setModalReadLoading(false);
|
|
1941
2976
|
setReadState(EMPTY_READ_STATE);
|
|
1942
2977
|
}
|
|
1943
2978
|
}, [mode, refresh]);
|
|
2979
|
+
(0, react.useEffect)(() => {
|
|
2980
|
+
if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision) return;
|
|
2981
|
+
forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
|
|
2982
|
+
if (mode !== "worktree" || manager === void 0) return;
|
|
2983
|
+
refresh({
|
|
2984
|
+
preserveCurrent: readStateRef.current.status === "ready",
|
|
2985
|
+
invalidateContext: false
|
|
2986
|
+
}).catch(() => {});
|
|
2987
|
+
}, [
|
|
2988
|
+
forkRecoverySnapshot.revision,
|
|
2989
|
+
manager,
|
|
2990
|
+
mode,
|
|
2991
|
+
refresh
|
|
2992
|
+
]);
|
|
1944
2993
|
(0, react.useEffect)(() => {
|
|
1945
2994
|
if (readState.status !== "ready" || syncSessionWorkspaces === void 0) return;
|
|
1946
2995
|
syncSessionWorkspaces(readState.views.flatMap((view) => view.bindings.map((binding) => ({
|
|
@@ -1953,18 +3002,130 @@ window.__ModuleLoader__.load({
|
|
|
1953
3002
|
syncSessionWorkspaces
|
|
1954
3003
|
]);
|
|
1955
3004
|
const viewByWorkspace = (0, react.useMemo)(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
|
|
3005
|
+
const sessionOrderInputs = (0, react.useMemo)(() => {
|
|
3006
|
+
if (readState.status !== "ready") return [];
|
|
3007
|
+
const inputs = [];
|
|
3008
|
+
for (const workspace of workspaces.items) {
|
|
3009
|
+
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
3010
|
+
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
3011
|
+
const bindings = view?.bindings ?? [];
|
|
3012
|
+
const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
|
|
3013
|
+
inputs.push({
|
|
3014
|
+
accountKey: `main:${workspace.workspaceId}`,
|
|
3015
|
+
sessionIds: mainSessionIds,
|
|
3016
|
+
updatedAtById: updatedAtById(mainSessionIds, sessions)
|
|
3017
|
+
});
|
|
3018
|
+
for (const record of view?.worktrees ?? []) {
|
|
3019
|
+
const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
|
|
3020
|
+
inputs.push({
|
|
3021
|
+
accountKey: `worktree:${record.worktreeId}`,
|
|
3022
|
+
sessionIds: worktreeSessionIds,
|
|
3023
|
+
updatedAtById: updatedAtById(worktreeSessionIds, sessions)
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
return inputs;
|
|
3028
|
+
}, [
|
|
3029
|
+
archivedSessionIds,
|
|
3030
|
+
readState.status,
|
|
3031
|
+
sessions.byId,
|
|
3032
|
+
sessions.ids,
|
|
3033
|
+
viewByWorkspace,
|
|
3034
|
+
workspaces,
|
|
3035
|
+
workspaces.items
|
|
3036
|
+
]);
|
|
3037
|
+
const orderedSessionIdsByAccount = (0, react.useMemo)(() => {
|
|
3038
|
+
const ordered = /* @__PURE__ */ new Map();
|
|
3039
|
+
for (const input of sessionOrderInputs) {
|
|
3040
|
+
const previous = sessionOrderSnapshot.accounts[input.accountKey];
|
|
3041
|
+
ordered.set(input.accountKey, nextSessionOrderAccount({
|
|
3042
|
+
baseIds: input.sessionIds,
|
|
3043
|
+
updatedAtById: input.updatedAtById,
|
|
3044
|
+
previous
|
|
3045
|
+
}).order);
|
|
3046
|
+
}
|
|
3047
|
+
return ordered;
|
|
3048
|
+
}, [sessionOrderInputs, sessionOrderSnapshot]);
|
|
3049
|
+
(0, react.useEffect)(() => {
|
|
3050
|
+
if (mode !== "worktree" || readState.status !== "ready") return;
|
|
3051
|
+
for (const input of sessionOrderInputs) sessionOrder.actions.reconcile(input.accountKey, input.sessionIds, input.updatedAtById);
|
|
3052
|
+
sessionOrder.actions.retain(sessionOrderInputs.map((input) => input.accountKey));
|
|
3053
|
+
}, [
|
|
3054
|
+
mode,
|
|
3055
|
+
readState.status,
|
|
3056
|
+
sessionOrder,
|
|
3057
|
+
sessionOrderInputs
|
|
3058
|
+
]);
|
|
3059
|
+
const currentSessionLocation = (0, react.useMemo)(() => readState.status === "ready" ? resolveCurrentSessionLocation(currentSessionId, workspaces.items, readState.views) : void 0, [
|
|
3060
|
+
currentSessionId,
|
|
3061
|
+
readState.status,
|
|
3062
|
+
readState.views,
|
|
3063
|
+
workspaces.items
|
|
3064
|
+
]);
|
|
3065
|
+
const currentRevealKeys = (0, react.useMemo)(() => new Set(currentSessionRevealKeys(currentSessionLocation)), [currentSessionLocation]);
|
|
3066
|
+
const isCurrentSessionReveal = (key) => currentSessionReveal !== void 0 && currentSessionReveal.sessionId === currentSessionId && currentRevealKeys.has(key) && currentSessionReveal.suppressedKeys[key] !== true;
|
|
3067
|
+
(0, react.useLayoutEffect)(() => {
|
|
3068
|
+
locateGenerationRef.current += 1;
|
|
3069
|
+
positionedLocateGenerationRef.current = void 0;
|
|
3070
|
+
if (mode !== "worktree") {
|
|
3071
|
+
setCurrentSessionReveal(void 0);
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
if (searchQueryRef.current.trim().length > 0) setSearchQuery("");
|
|
3075
|
+
setCurrentSessionReveal(currentSessionId === void 0 ? void 0 : {
|
|
3076
|
+
sessionId: currentSessionId,
|
|
3077
|
+
suppressedKeys: {}
|
|
3078
|
+
});
|
|
3079
|
+
}, [currentSessionId, mode]);
|
|
3080
|
+
(0, react.useLayoutEffect)(() => {
|
|
3081
|
+
if (mode !== "worktree" || currentSessionId === void 0 || currentSessionLocation === void 0) return;
|
|
3082
|
+
const generation = locateGenerationRef.current;
|
|
3083
|
+
if (positionedLocateGenerationRef.current === generation) return;
|
|
3084
|
+
let cancelled = false;
|
|
3085
|
+
const frame = requestAnimationFrame(() => {
|
|
3086
|
+
if (cancelled || generation !== locateGenerationRef.current) return;
|
|
3087
|
+
if (!scrollCurrentSessionIntoView(ref.current, currentSessionId)) return;
|
|
3088
|
+
positionedLocateGenerationRef.current = generation;
|
|
3089
|
+
});
|
|
3090
|
+
return () => {
|
|
3091
|
+
cancelled = true;
|
|
3092
|
+
cancelAnimationFrame(frame);
|
|
3093
|
+
};
|
|
3094
|
+
}, [
|
|
3095
|
+
currentSessionId,
|
|
3096
|
+
currentSessionLocation,
|
|
3097
|
+
currentSessionReveal,
|
|
3098
|
+
expandSnapshot,
|
|
3099
|
+
mode,
|
|
3100
|
+
query,
|
|
3101
|
+
readState.status
|
|
3102
|
+
]);
|
|
3103
|
+
(0, react.useEffect)(() => {
|
|
3104
|
+
if (readState.status !== "ready" || !isCompleteWorktreeWorkspaceSnapshot(workspaceIds, readState.views)) return;
|
|
3105
|
+
expandState.actions.retain(workspaceIds, readState.views.flatMap((view) => view.worktrees.map((record) => record.worktreeId)));
|
|
3106
|
+
}, [
|
|
3107
|
+
expandState,
|
|
3108
|
+
readState.status,
|
|
3109
|
+
readState.views,
|
|
3110
|
+
workspaceIds
|
|
3111
|
+
]);
|
|
1956
3112
|
const modalWorkspace = workspaces.items.find((workspace) => workspace.workspaceId === worktreeModalWorkspaceId);
|
|
1957
3113
|
const modalView = worktreeModalWorkspaceId === void 0 ? void 0 : viewByWorkspace.get(worktreeModalWorkspaceId);
|
|
1958
3114
|
const modalReadiness = modalView?.readiness;
|
|
1959
3115
|
const modalSetupStatus = modalView === void 0 ? void 0 : modalReadiness?.status === "ready" ? modalView.branches.length === 0 ? "noLocalBranch" : void 0 : modalReadiness?.status;
|
|
1960
|
-
const modalCanCreate = modalSetupStatus === void 0 && modalReadiness?.status === "ready";
|
|
3116
|
+
const modalCanCreate = !modalReadLoading && modalSetupStatus === void 0 && modalReadiness?.status === "ready";
|
|
1961
3117
|
(0, react.useEffect)(() => {
|
|
1962
3118
|
if (worktreeModalWorkspaceId === void 0 || modalView === void 0) return;
|
|
1963
3119
|
if (modalView.readiness.status !== "ready") {
|
|
1964
3120
|
setSelectedBranch("");
|
|
3121
|
+
setNewBranch("");
|
|
1965
3122
|
return;
|
|
1966
3123
|
}
|
|
1967
3124
|
setSelectedBranch((current) => reconcileBaseBranchSelection(current, modalView.branches));
|
|
3125
|
+
setNewBranch((current) => {
|
|
3126
|
+
if (current.length > 0) return current;
|
|
3127
|
+
return createDefaultWorktreeName([...modalView.branches.map((branch) => branch.name), ...modalView.worktrees.map((worktree) => worktree.branch)]);
|
|
3128
|
+
});
|
|
1968
3129
|
}, [modalView, worktreeModalWorkspaceId]);
|
|
1969
3130
|
const runMutation = async (operation) => {
|
|
1970
3131
|
setActionPending(true);
|
|
@@ -1978,6 +3139,27 @@ window.__ModuleLoader__.load({
|
|
|
1978
3139
|
setActionPending(false);
|
|
1979
3140
|
}
|
|
1980
3141
|
};
|
|
3142
|
+
const loadImportCandidates = (0, react.useCallback)(async (workspaceId) => {
|
|
3143
|
+
if (manager === void 0) return;
|
|
3144
|
+
setImportCandidates((current) => ({
|
|
3145
|
+
status: "loading",
|
|
3146
|
+
candidates: current.candidates
|
|
3147
|
+
}));
|
|
3148
|
+
await importCandidatesGuard.current.run(() => manager.listImportCandidates({ workspaceId }), (candidates) => {
|
|
3149
|
+
if (modalWorkspaceIdRef.current !== workspaceId) return;
|
|
3150
|
+
setImportCandidates({
|
|
3151
|
+
status: "ready",
|
|
3152
|
+
candidates
|
|
3153
|
+
});
|
|
3154
|
+
}, (error) => {
|
|
3155
|
+
if (modalWorkspaceIdRef.current !== workspaceId) return;
|
|
3156
|
+
setImportCandidates((current) => ({
|
|
3157
|
+
status: "error",
|
|
3158
|
+
candidates: current.candidates,
|
|
3159
|
+
error: toWorktreeViewError(error)
|
|
3160
|
+
}));
|
|
3161
|
+
});
|
|
3162
|
+
}, [manager]);
|
|
1981
3163
|
const workspaceRenameTrimmed = workspaceRenameDraft.trim();
|
|
1982
3164
|
const workspaceRenameDuplicate = workspaceRenameTarget !== void 0 && workspaceRenameTrimmed.length > 0 && workspaces.items.some((workspace) => workspace.workspaceId !== workspaceRenameTarget.workspaceId && workspace.title === workspaceRenameTrimmed);
|
|
1983
3165
|
const workspaceRenameBlocked = workspaceRenamePending || workspaceRenameTarget === void 0 || workspaceRenameTrimmed.length === 0 || workspaceRenameTrimmed === workspaceRenameTarget?.currentTitle || workspaceRenameDuplicate;
|
|
@@ -2093,7 +3275,10 @@ window.__ModuleLoader__.load({
|
|
|
2093
3275
|
return;
|
|
2094
3276
|
}
|
|
2095
3277
|
setActionError(void 0);
|
|
2096
|
-
|
|
3278
|
+
const currentOrder = sessionOrderSnapshot.accounts[activeDrag.groupKey]?.order ?? sessionIds;
|
|
3279
|
+
insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId).then(() => {
|
|
3280
|
+
sessionOrder.actions.setOrder(activeDrag.groupKey, reorderSessionIds(currentOrder, activeDrag.sessionId, over.sessionId, over.half));
|
|
3281
|
+
}).catch((error) => {
|
|
2097
3282
|
setActionError(toWorktreeViewError(error));
|
|
2098
3283
|
});
|
|
2099
3284
|
};
|
|
@@ -2160,80 +3345,176 @@ window.__ModuleLoader__.load({
|
|
|
2160
3345
|
if (archiveSession === void 0) return;
|
|
2161
3346
|
await runMutation(() => archiveSession(sessionId));
|
|
2162
3347
|
};
|
|
3348
|
+
const clearSessionGroups = (groupKeys) => {
|
|
3349
|
+
if (groupKeys.length === 0) return;
|
|
3350
|
+
setExpandedSessionGroups((current) => clearSessionGroupExpansion(current, groupKeys));
|
|
3351
|
+
};
|
|
3352
|
+
const suppressCurrentSessionReveal = (key) => {
|
|
3353
|
+
if (!isCurrentSessionReveal(key)) return false;
|
|
3354
|
+
setCurrentSessionReveal((current) => {
|
|
3355
|
+
if (current === void 0 || current.sessionId !== currentSessionId) return current;
|
|
3356
|
+
return {
|
|
3357
|
+
...current,
|
|
3358
|
+
suppressedKeys: {
|
|
3359
|
+
...current.suppressedKeys,
|
|
3360
|
+
[key]: true
|
|
3361
|
+
}
|
|
3362
|
+
};
|
|
3363
|
+
});
|
|
3364
|
+
return true;
|
|
3365
|
+
};
|
|
2163
3366
|
const toggleWorkspace = (workspaceId) => {
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
3367
|
+
const persistedExpanded = isWorkspaceExpanded(expandSnapshot, workspaceId);
|
|
3368
|
+
const autoExpanded = isCurrentSessionReveal("workspace:" + workspaceId);
|
|
3369
|
+
const visuallyExpanded = persistedExpanded || autoExpanded;
|
|
3370
|
+
if (visuallyExpanded && autoExpanded) suppressCurrentSessionReveal("workspace:" + workspaceId);
|
|
3371
|
+
if (visuallyExpanded && !persistedExpanded) {
|
|
3372
|
+
clearSessionGroups(["main:" + workspaceId, ...(viewByWorkspace.get(workspaceId)?.worktrees.map((record) => record.worktreeId) ?? []).map((worktreeId) => "worktree:" + worktreeId)]);
|
|
3373
|
+
return;
|
|
3374
|
+
}
|
|
3375
|
+
expandState.actions.toggleWorkspace(workspaceId);
|
|
3376
|
+
if (visuallyExpanded) clearSessionGroups(["main:" + workspaceId, ...(viewByWorkspace.get(workspaceId)?.worktrees.map((record) => record.worktreeId) ?? []).map((worktreeId) => "worktree:" + worktreeId)]);
|
|
2168
3377
|
};
|
|
2169
3378
|
const toggleMain = (workspaceId) => {
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
3379
|
+
const persistedExpanded = isMainExpanded(expandSnapshot, workspaceId);
|
|
3380
|
+
const autoExpanded = isCurrentSessionReveal("main:" + workspaceId);
|
|
3381
|
+
const visuallyExpanded = persistedExpanded || autoExpanded;
|
|
3382
|
+
if (visuallyExpanded && autoExpanded) suppressCurrentSessionReveal("main:" + workspaceId);
|
|
3383
|
+
if (visuallyExpanded && !persistedExpanded) {
|
|
3384
|
+
clearSessionGroups(["main:" + workspaceId]);
|
|
3385
|
+
return;
|
|
3386
|
+
}
|
|
3387
|
+
expandState.actions.toggleMain(workspaceId);
|
|
3388
|
+
if (visuallyExpanded) clearSessionGroups(["main:" + workspaceId]);
|
|
2174
3389
|
};
|
|
2175
3390
|
const toggleWorktree = (worktreeId) => {
|
|
2176
|
-
|
|
3391
|
+
const persistedExpanded = isWorktreeExpanded(expandSnapshot, worktreeId);
|
|
3392
|
+
const autoExpanded = isCurrentSessionReveal("worktree:" + worktreeId);
|
|
3393
|
+
const visuallyExpanded = persistedExpanded || autoExpanded;
|
|
3394
|
+
if (visuallyExpanded && autoExpanded) suppressCurrentSessionReveal("worktree:" + worktreeId);
|
|
3395
|
+
if (visuallyExpanded && !persistedExpanded) {
|
|
3396
|
+
clearSessionGroups(["worktree:" + worktreeId]);
|
|
3397
|
+
return;
|
|
3398
|
+
}
|
|
3399
|
+
expandState.actions.toggleWorktree(worktreeId);
|
|
3400
|
+
if (visuallyExpanded) clearSessionGroups(["worktree:" + worktreeId]);
|
|
3401
|
+
};
|
|
3402
|
+
const toggleSessionGroup = (groupKey, autoExpanded) => {
|
|
3403
|
+
const transientExpanded = expandedSessionGroups[groupKey] === true;
|
|
3404
|
+
if (autoExpanded) {
|
|
3405
|
+
suppressCurrentSessionReveal("session-group:" + groupKey);
|
|
3406
|
+
setExpandedSessionGroups((current) => {
|
|
3407
|
+
const next = { ...current };
|
|
3408
|
+
delete next[groupKey];
|
|
3409
|
+
return next;
|
|
3410
|
+
});
|
|
3411
|
+
return;
|
|
3412
|
+
}
|
|
3413
|
+
setExpandedSessionGroups((current) => ({
|
|
2177
3414
|
...current,
|
|
2178
|
-
[
|
|
3415
|
+
[groupKey]: !transientExpanded
|
|
2179
3416
|
}));
|
|
2180
3417
|
};
|
|
2181
|
-
const
|
|
3418
|
+
const closeWorktreeCreator = (force = false) => {
|
|
3419
|
+
if (actionPending && !force) return;
|
|
3420
|
+
modalReadLoader.current.invalidate();
|
|
3421
|
+
modalReadViewRef.current = void 0;
|
|
3422
|
+
importCandidatesGuard.current.invalidate();
|
|
3423
|
+
setWorktreeModalWorkspaceId(void 0);
|
|
3424
|
+
setModalReadError(void 0);
|
|
3425
|
+
setModalReadLoading(false);
|
|
3426
|
+
};
|
|
3427
|
+
const openWorktreeCreator = (workspace, defaults = {}) => {
|
|
2182
3428
|
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
2183
|
-
|
|
2184
|
-
|
|
3429
|
+
modalReadLoader.current.invalidate();
|
|
3430
|
+
modalReadViewRef.current = void 0;
|
|
3431
|
+
importCandidatesGuard.current.invalidate();
|
|
2185
3432
|
setWorktreeModalWorkspaceId(workspace.workspaceId);
|
|
2186
|
-
|
|
2187
|
-
|
|
3433
|
+
setWorktreeModalMode("create");
|
|
3434
|
+
setImportCandidates({
|
|
3435
|
+
status: "idle",
|
|
3436
|
+
candidates: []
|
|
3437
|
+
});
|
|
3438
|
+
setSelectedImportPath(void 0);
|
|
2188
3439
|
setActionError(void 0);
|
|
3440
|
+
setModalReadError(void 0);
|
|
3441
|
+
setModalReadLoading(false);
|
|
3442
|
+
if (view === void 0) {
|
|
3443
|
+
setSelectedBranch(defaults.baseBranch ?? "");
|
|
3444
|
+
setNewBranch(defaults.newBranch ?? "");
|
|
3445
|
+
loadModalWorktreeView(workspace.workspaceId);
|
|
3446
|
+
return;
|
|
3447
|
+
}
|
|
3448
|
+
setSelectedBranch(defaults.baseBranch ?? selectDefaultBaseBranch(view.branches));
|
|
3449
|
+
setNewBranch(defaults.newBranch ?? createDefaultWorktreeName([...view.branches.map((branch) => branch.name), ...view.worktrees.map((worktree) => worktree.branch)]));
|
|
3450
|
+
};
|
|
3451
|
+
const changeWorktreeModalMode = (mode) => {
|
|
3452
|
+
setWorktreeModalMode(mode);
|
|
3453
|
+
if (mode === "import" && worktreeModalWorkspaceId !== void 0 && importCandidates.status === "idle") loadImportCandidates(worktreeModalWorkspaceId);
|
|
3454
|
+
};
|
|
3455
|
+
const continueWorktreeRegistration = async (registeredWorktree) => {
|
|
3456
|
+
closeWorktreeCreator(true);
|
|
3457
|
+
if (createSessionCallback === void 0) {
|
|
3458
|
+
await refresh({ preserveCurrent: true });
|
|
3459
|
+
setActionError({
|
|
3460
|
+
code: "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE",
|
|
3461
|
+
message: "",
|
|
3462
|
+
retryable: true
|
|
3463
|
+
});
|
|
3464
|
+
return;
|
|
3465
|
+
}
|
|
3466
|
+
const sessionInput = {
|
|
3467
|
+
workspaceId: registeredWorktree.workspaceId,
|
|
3468
|
+
worktreeId: registeredWorktree.worktreeId,
|
|
3469
|
+
cwd: registeredWorktree.absolutePath
|
|
3470
|
+
};
|
|
3471
|
+
try {
|
|
3472
|
+
await createSessionCallback(sessionInput);
|
|
3473
|
+
await invalidateWorktreeContext?.(registeredWorktree.workspaceId);
|
|
3474
|
+
} catch (error) {
|
|
3475
|
+
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
3476
|
+
...sessionInput,
|
|
3477
|
+
sessionId: error.sessionId
|
|
3478
|
+
});
|
|
3479
|
+
if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
|
|
3480
|
+
...sessionInput,
|
|
3481
|
+
sessionId: error.sessionId,
|
|
3482
|
+
permissionRequired: true
|
|
3483
|
+
});
|
|
3484
|
+
throw error;
|
|
3485
|
+
}
|
|
3486
|
+
await refresh({ preserveCurrent: true });
|
|
2189
3487
|
};
|
|
2190
3488
|
const submitWorktree = async () => {
|
|
2191
3489
|
const worktreeName = newBranch.trim();
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
newBranch: worktreeName
|
|
2197
|
-
};
|
|
3490
|
+
const selectedImportCandidate = importCandidates.candidates.find((candidate) => candidate.absolutePath === selectedImportPath);
|
|
3491
|
+
if (manager === void 0 || modalWorkspace === void 0) return;
|
|
3492
|
+
if (worktreeModalMode === "create" && (!modalCanCreate || selectedBranch.length === 0 || worktreeName.length === 0)) return;
|
|
3493
|
+
if (worktreeModalMode === "import" && selectedImportCandidate === void 0) return;
|
|
2198
3494
|
setActionPending(true);
|
|
2199
3495
|
setActionError(void 0);
|
|
2200
3496
|
setPendingSessionBinding(void 0);
|
|
2201
3497
|
try {
|
|
2202
|
-
const
|
|
3498
|
+
const registeredWorktree = worktreeModalMode === "create" ? await executeWorktreeAction(manager, {
|
|
2203
3499
|
type: "createWorktree",
|
|
2204
|
-
input
|
|
3500
|
+
input: {
|
|
3501
|
+
workspaceId: modalWorkspace.workspaceId,
|
|
3502
|
+
branch: selectedBranch,
|
|
3503
|
+
newBranch: worktreeName
|
|
3504
|
+
}
|
|
3505
|
+
}) : await executeWorktreeAction(manager, {
|
|
3506
|
+
type: "importWorktree",
|
|
3507
|
+
input: {
|
|
3508
|
+
workspaceId: modalWorkspace.workspaceId,
|
|
3509
|
+
absolutePath: selectedImportCandidate.absolutePath
|
|
3510
|
+
}
|
|
2205
3511
|
});
|
|
2206
|
-
if (
|
|
3512
|
+
if (registeredWorktree === void 0) throw {
|
|
2207
3513
|
code: "WORKTREE_RECORD_MISSING",
|
|
2208
3514
|
message: "",
|
|
2209
3515
|
retryable: true
|
|
2210
3516
|
};
|
|
2211
|
-
|
|
2212
|
-
if (createSessionCallback === void 0) {
|
|
2213
|
-
await refresh({ preserveCurrent: true });
|
|
2214
|
-
setActionError({
|
|
2215
|
-
code: "WORKTREE_CREATED_SESSION_UNAVAILABLE",
|
|
2216
|
-
message: "",
|
|
2217
|
-
retryable: true
|
|
2218
|
-
});
|
|
2219
|
-
return;
|
|
2220
|
-
}
|
|
2221
|
-
const sessionInput = {
|
|
2222
|
-
workspaceId: createdWorktree.workspaceId,
|
|
2223
|
-
worktreeId: createdWorktree.worktreeId,
|
|
2224
|
-
cwd: createdWorktree.absolutePath
|
|
2225
|
-
};
|
|
2226
|
-
try {
|
|
2227
|
-
await createSessionCallback(sessionInput);
|
|
2228
|
-
await invalidateWorktreeContext?.(createdWorktree.workspaceId);
|
|
2229
|
-
} catch (error) {
|
|
2230
|
-
if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
|
|
2231
|
-
...sessionInput,
|
|
2232
|
-
sessionId: error.sessionId
|
|
2233
|
-
});
|
|
2234
|
-
throw error;
|
|
2235
|
-
}
|
|
2236
|
-
await refresh({ preserveCurrent: true });
|
|
3517
|
+
await continueWorktreeRegistration(registeredWorktree);
|
|
2237
3518
|
} catch (error) {
|
|
2238
3519
|
setActionError(toWorktreeViewError(error));
|
|
2239
3520
|
} finally {
|
|
@@ -2261,6 +3542,11 @@ window.__ModuleLoader__.load({
|
|
|
2261
3542
|
...input,
|
|
2262
3543
|
sessionId: error.sessionId
|
|
2263
3544
|
});
|
|
3545
|
+
if (error instanceof WorktreeSessionPermissionError && error.retryable) setPendingSessionBinding({
|
|
3546
|
+
...input,
|
|
3547
|
+
sessionId: error.sessionId,
|
|
3548
|
+
permissionRequired: true
|
|
3549
|
+
});
|
|
2264
3550
|
setActionError(toWorktreeViewError(error));
|
|
2265
3551
|
} finally {
|
|
2266
3552
|
setActionPending(false);
|
|
@@ -2279,6 +3565,9 @@ window.__ModuleLoader__.load({
|
|
|
2279
3565
|
ensureSessionWorkspace: (workspaceId, sessionId) => {
|
|
2280
3566
|
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2281
3567
|
},
|
|
3568
|
+
permission,
|
|
3569
|
+
confirmFullAccess,
|
|
3570
|
+
onPermissionResult,
|
|
2282
3571
|
openSession
|
|
2283
3572
|
});
|
|
2284
3573
|
setPendingSessionBinding(void 0);
|
|
@@ -2291,6 +3580,17 @@ window.__ModuleLoader__.load({
|
|
|
2291
3580
|
setActionPending(false);
|
|
2292
3581
|
}
|
|
2293
3582
|
};
|
|
3583
|
+
const retryForkBinding = async (key) => {
|
|
3584
|
+
if (retryForkSession === void 0 || forkRetryKey !== void 0) return;
|
|
3585
|
+
setForkRetryKey(key);
|
|
3586
|
+
try {
|
|
3587
|
+
await retryForkSession(key);
|
|
3588
|
+
} catch (error) {
|
|
3589
|
+
setActionError(toNativeWorktreeViewError(error));
|
|
3590
|
+
} finally {
|
|
3591
|
+
setForkRetryKey(void 0);
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
2294
3594
|
const openWorkspaceSession = (workspaceId, sessionId) => {
|
|
2295
3595
|
ensureSessionWorkspace?.(workspaceId, sessionId);
|
|
2296
3596
|
openWorktreeSession({ open: openSession }, sessionId);
|
|
@@ -2356,7 +3656,7 @@ window.__ModuleLoader__.load({
|
|
|
2356
3656
|
onClick: () => {
|
|
2357
3657
|
if (createWorkspace !== void 0) runMutation(createWorkspace);
|
|
2358
3658
|
},
|
|
2359
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
3659
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconProjectAddOutline16, {})
|
|
2360
3660
|
})
|
|
2361
3661
|
]
|
|
2362
3662
|
}),
|
|
@@ -2364,6 +3664,47 @@ window.__ModuleLoader__.load({
|
|
|
2364
3664
|
className: worktree_css_default.content,
|
|
2365
3665
|
tabIndex: 0,
|
|
2366
3666
|
children: [
|
|
3667
|
+
permissionNoticeSnapshot !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
3668
|
+
className: worktree_css_default.notice,
|
|
3669
|
+
role: "status",
|
|
3670
|
+
"data-worktree-permission-notice": true,
|
|
3671
|
+
children: (0, react_jsx_runtime.jsx)("p", {
|
|
3672
|
+
className: worktree_css_default.message,
|
|
3673
|
+
children: formatWorktreePermissionNotice(permissionNoticeSnapshot.result, t)
|
|
3674
|
+
})
|
|
3675
|
+
}),
|
|
3676
|
+
forkRecoverySnapshot.pending.map((recovery) => {
|
|
3677
|
+
const recoveryViewError = forkRecoveryError(recovery);
|
|
3678
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
3679
|
+
className: worktree_css_default.error,
|
|
3680
|
+
role: "alert",
|
|
3681
|
+
"data-fork-recovery": recovery.key,
|
|
3682
|
+
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
3683
|
+
className: worktree_css_default.message,
|
|
3684
|
+
"data-error": "true",
|
|
3685
|
+
children: formatWorktreeViewError(recoveryViewError, t)
|
|
3686
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
3687
|
+
className: worktree_css_default.recoveryActions,
|
|
3688
|
+
children: [retryForkSession !== void 0 && recoveryViewError.retryable && (0, react_jsx_runtime.jsx)("button", {
|
|
3689
|
+
type: "button",
|
|
3690
|
+
className: worktree_css_default.actionButton,
|
|
3691
|
+
disabled: forkRetryKey !== void 0,
|
|
3692
|
+
onClick: () => {
|
|
3693
|
+
retryForkBinding(recovery.key);
|
|
3694
|
+
},
|
|
3695
|
+
children: t("action.retryBinding")
|
|
3696
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
3697
|
+
type: "button",
|
|
3698
|
+
className: worktree_css_default.actionButton,
|
|
3699
|
+
disabled: forkRetryKey !== void 0,
|
|
3700
|
+
onClick: () => {
|
|
3701
|
+
openSession(recovery.childSessionId);
|
|
3702
|
+
},
|
|
3703
|
+
children: t("action.openCreatedSession")
|
|
3704
|
+
})]
|
|
3705
|
+
})]
|
|
3706
|
+
}, recovery.key);
|
|
3707
|
+
}),
|
|
2367
3708
|
actionError !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
2368
3709
|
className: worktree_css_default.error,
|
|
2369
3710
|
role: "alert",
|
|
@@ -2384,7 +3725,7 @@ window.__ModuleLoader__.load({
|
|
|
2384
3725
|
retrySessionBinding();
|
|
2385
3726
|
},
|
|
2386
3727
|
children: t("action.retryBinding")
|
|
2387
|
-
}), (0, react_jsx_runtime.jsx)("button", {
|
|
3728
|
+
}), !pendingSessionBinding.permissionRequired && (0, react_jsx_runtime.jsx)("button", {
|
|
2388
3729
|
type: "button",
|
|
2389
3730
|
className: worktree_css_default.actionButton,
|
|
2390
3731
|
disabled: actionPending,
|
|
@@ -2437,14 +3778,22 @@ window.__ModuleLoader__.load({
|
|
|
2437
3778
|
const view = viewByWorkspace.get(workspace.workspaceId);
|
|
2438
3779
|
const currentBranch = view?.branches.find((branch) => branch.isCurrent)?.name;
|
|
2439
3780
|
const mainLabel = currentBranch === void 0 ? t("worktree.main") : t("worktree.mainWithBranch", { branch: currentBranch });
|
|
2440
|
-
const expanded =
|
|
3781
|
+
const expanded = isWorkspaceExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("workspace:" + workspace.workspaceId);
|
|
2441
3782
|
const workspaceMatchesQuery = includesText(workspace.title, query);
|
|
2442
3783
|
const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
|
|
3784
|
+
const workspaceHasOngoingSession = hasOngoingSession(filterVisibleSessionIds(allWorkspaceSessionIds, sessions), sessionPresentations);
|
|
2443
3785
|
const bindings = view?.bindings ?? [];
|
|
2444
|
-
const
|
|
2445
|
-
const mainExpanded = expandedMains[workspace.workspaceId] !== false;
|
|
3786
|
+
const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...new Set(bindings.map((binding) => binding.sessionId))]), sessions);
|
|
2446
3787
|
const mainGroupKey = `main:${workspace.workspaceId}`;
|
|
3788
|
+
const orderedMainSessionIds = orderedSessionIdsByAccount.get(mainGroupKey) ?? mainSessionIds;
|
|
3789
|
+
const visibleMainSessionIds = mainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3790
|
+
const orderedVisibleMainSessionIds = orderedMainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3791
|
+
const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) || isCurrentSessionReveal("main:" + workspace.workspaceId);
|
|
3792
|
+
const sessionIds = orderedVisibleMainSessionIds.length === visibleMainSessionIds.length ? orderedVisibleMainSessionIds : visibleMainSessionIds;
|
|
3793
|
+
const mainSessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + mainGroupKey));
|
|
3794
|
+
const mainSessionGroupExpanded = expandedSessionGroups[mainGroupKey] === true || mainSessionGroupAutoExpanded;
|
|
2447
3795
|
const worktrees = view?.worktrees ?? [];
|
|
3796
|
+
const workspaceWorktreeNames = [...view?.branches.map((branch) => branch.name) ?? [], ...view?.worktrees.map((worktree) => worktree.branch) ?? []];
|
|
2448
3797
|
const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
|
|
2449
3798
|
return (0, react_jsx_runtime.jsxs)("section", {
|
|
2450
3799
|
className: worktree_css_default.workspaceGroup,
|
|
@@ -2453,6 +3802,7 @@ window.__ModuleLoader__.load({
|
|
|
2453
3802
|
t,
|
|
2454
3803
|
workspace,
|
|
2455
3804
|
expanded,
|
|
3805
|
+
hasOngoingSession: workspaceHasOngoingSession,
|
|
2456
3806
|
actionPending,
|
|
2457
3807
|
menuOpen: openWorkspaceMenuId === workspace.workspaceId,
|
|
2458
3808
|
drag: {
|
|
@@ -2510,11 +3860,29 @@ window.__ModuleLoader__.load({
|
|
|
2510
3860
|
kind: "main",
|
|
2511
3861
|
label: mainLabel,
|
|
2512
3862
|
expanded: mainExpanded,
|
|
3863
|
+
hasOngoingSession: hasOngoingSession(mainSessionIds, sessionPresentations),
|
|
2513
3864
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
2514
3865
|
workspaceTitle: workspace.title,
|
|
2515
3866
|
onToggle: () => {
|
|
2516
3867
|
toggleMain(workspace.workspaceId);
|
|
2517
3868
|
},
|
|
3869
|
+
menu: {
|
|
3870
|
+
open: openMainMenuId === workspace.workspaceId,
|
|
3871
|
+
label: mainLabel,
|
|
3872
|
+
copyPath: workspace.path,
|
|
3873
|
+
showCreate: currentBranch !== void 0,
|
|
3874
|
+
showRemove: false,
|
|
3875
|
+
disabled: actionPending,
|
|
3876
|
+
onOpenChange: (open) => {
|
|
3877
|
+
setOpenMainMenuId(open ? workspace.workspaceId : void 0);
|
|
3878
|
+
},
|
|
3879
|
+
onCreateWorktree: currentBranch === void 0 ? void 0 : () => {
|
|
3880
|
+
openWorktreeCreator(workspace, {
|
|
3881
|
+
baseBranch: currentBranch,
|
|
3882
|
+
newBranch: createNumberedWorktreeName(currentBranch, workspaceWorktreeNames)
|
|
3883
|
+
});
|
|
3884
|
+
}
|
|
3885
|
+
},
|
|
2518
3886
|
onCreateSession: createMainSession === void 0 ? void 0 : () => {
|
|
2519
3887
|
createMainSession(workspace.workspaceId);
|
|
2520
3888
|
}
|
|
@@ -2522,17 +3890,16 @@ window.__ModuleLoader__.load({
|
|
|
2522
3890
|
mainExpanded && (0, react_jsx_runtime.jsx)(WorktreeSessionGroup, {
|
|
2523
3891
|
t,
|
|
2524
3892
|
groupKey: mainGroupKey,
|
|
2525
|
-
sessionIds
|
|
3893
|
+
sessionIds,
|
|
2526
3894
|
workspaceId: workspace.workspaceId,
|
|
2527
|
-
|
|
3895
|
+
currentSessionId,
|
|
3896
|
+
expanded: mainSessionGroupExpanded,
|
|
2528
3897
|
actionPending,
|
|
2529
3898
|
sessions,
|
|
3899
|
+
sessionPresentations,
|
|
2530
3900
|
dragState: sessionDrag,
|
|
2531
3901
|
onToggleExpanded: () => {
|
|
2532
|
-
|
|
2533
|
-
...current,
|
|
2534
|
-
[mainGroupKey]: current[mainGroupKey] !== true
|
|
2535
|
-
}));
|
|
3902
|
+
toggleSessionGroup(mainGroupKey, mainSessionGroupAutoExpanded);
|
|
2536
3903
|
},
|
|
2537
3904
|
onStartDrag: (groupKey, sessionId) => {
|
|
2538
3905
|
sessionDropCommitted.current = false;
|
|
@@ -2575,9 +3942,13 @@ window.__ModuleLoader__.load({
|
|
|
2575
3942
|
if (query.length > 0 && !worktreeMatchesQuery && !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) return null;
|
|
2576
3943
|
const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
2577
3944
|
const worktreeGroupKey = `worktree:${record.worktreeId}`;
|
|
3945
|
+
const orderedVisibleWorktreeSessionIds = (orderedSessionIdsByAccount.get(worktreeGroupKey) ?? worktreeSessionIds).filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
|
|
3946
|
+
const sessionIds = orderedVisibleWorktreeSessionIds.length === visibleWorktreeSessionIds.length ? orderedVisibleWorktreeSessionIds : visibleWorktreeSessionIds;
|
|
3947
|
+
const sessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + worktreeGroupKey));
|
|
3948
|
+
const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true || sessionGroupAutoExpanded;
|
|
2578
3949
|
const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
|
|
2579
3950
|
const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
|
|
2580
|
-
const worktreeExpanded =
|
|
3951
|
+
const worktreeExpanded = isWorktreeExpanded(expandSnapshot, record.worktreeId) || isCurrentSessionReveal("worktree:" + record.worktreeId);
|
|
2581
3952
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
2582
3953
|
className: worktree_css_default.worktreeGroup,
|
|
2583
3954
|
"data-worktree-id": record.worktreeId,
|
|
@@ -2587,6 +3958,7 @@ window.__ModuleLoader__.load({
|
|
|
2587
3958
|
label: record.branch,
|
|
2588
3959
|
worktreeId: record.worktreeId,
|
|
2589
3960
|
expanded: worktreeExpanded,
|
|
3961
|
+
hasOngoingSession: hasOngoingSession(worktreeSessionIds, sessionPresentations),
|
|
2590
3962
|
icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutline16, {}),
|
|
2591
3963
|
workspaceTitle: workspace.title,
|
|
2592
3964
|
state,
|
|
@@ -2601,18 +3973,27 @@ window.__ModuleLoader__.load({
|
|
|
2601
3973
|
cwd: record.absolutePath
|
|
2602
3974
|
});
|
|
2603
3975
|
} : void 0,
|
|
2604
|
-
menu:
|
|
3976
|
+
menu: {
|
|
2605
3977
|
open: openWorktreeMenuId === record.worktreeId,
|
|
2606
3978
|
label: record.branch,
|
|
3979
|
+
copyPath: record.absolutePath,
|
|
3980
|
+
showCreate: record.status === "active",
|
|
3981
|
+
showRemove: record.status === "active",
|
|
2607
3982
|
disabled: actionPending,
|
|
2608
3983
|
onOpenChange: (open) => {
|
|
2609
3984
|
setOpenWorktreeMenuId(open ? record.worktreeId : void 0);
|
|
2610
3985
|
},
|
|
2611
|
-
|
|
3986
|
+
onCreateWorktree: record.status === "active" ? () => {
|
|
3987
|
+
openWorktreeCreator(workspace, {
|
|
3988
|
+
baseBranch: record.branch,
|
|
3989
|
+
newBranch: createNumberedWorktreeName(record.branch, workspaceWorktreeNames)
|
|
3990
|
+
});
|
|
3991
|
+
} : void 0,
|
|
3992
|
+
onRemove: record.status === "active" ? () => {
|
|
2612
3993
|
setWorktreeRemoval(record);
|
|
2613
3994
|
setActionError(void 0);
|
|
2614
|
-
}
|
|
2615
|
-
}
|
|
3995
|
+
} : void 0
|
|
3996
|
+
},
|
|
2616
3997
|
drag: {
|
|
2617
3998
|
active: sameWorkspaceWorktreeDrag,
|
|
2618
3999
|
marker: worktreeDrag?.over?.worktreeId === record.worktreeId ? worktreeDrag.over.half : null,
|
|
@@ -2648,17 +4029,16 @@ window.__ModuleLoader__.load({
|
|
|
2648
4029
|
}), worktreeExpanded && (0, react_jsx_runtime.jsx)(WorktreeSessionGroup, {
|
|
2649
4030
|
t,
|
|
2650
4031
|
groupKey: worktreeGroupKey,
|
|
2651
|
-
sessionIds
|
|
4032
|
+
sessionIds,
|
|
2652
4033
|
workspaceId: workspace.workspaceId,
|
|
2653
|
-
|
|
4034
|
+
currentSessionId,
|
|
4035
|
+
expanded: sessionGroupExpanded,
|
|
2654
4036
|
actionPending,
|
|
2655
4037
|
sessions,
|
|
4038
|
+
sessionPresentations,
|
|
2656
4039
|
dragState: sessionDrag,
|
|
2657
4040
|
onToggleExpanded: () => {
|
|
2658
|
-
|
|
2659
|
-
...current,
|
|
2660
|
-
[worktreeGroupKey]: current[worktreeGroupKey] !== true
|
|
2661
|
-
}));
|
|
4041
|
+
toggleSessionGroup(worktreeGroupKey, sessionGroupAutoExpanded);
|
|
2662
4042
|
},
|
|
2663
4043
|
onStartDrag: (groupKey, sessionId) => {
|
|
2664
4044
|
sessionDropCommitted.current = false;
|
|
@@ -2741,14 +4121,28 @@ window.__ModuleLoader__.load({
|
|
|
2741
4121
|
t,
|
|
2742
4122
|
workspace: modalWorkspace,
|
|
2743
4123
|
view: modalView,
|
|
4124
|
+
readError: modalReadError,
|
|
2744
4125
|
setupStatus: modalSetupStatus,
|
|
2745
4126
|
canCreate: modalCanCreate,
|
|
4127
|
+
mode: worktreeModalMode,
|
|
4128
|
+
importCandidates,
|
|
4129
|
+
selectedImportPath,
|
|
2746
4130
|
selectedBranch,
|
|
2747
4131
|
newBranch,
|
|
2748
4132
|
actionPending,
|
|
2749
|
-
onClose:
|
|
2750
|
-
|
|
4133
|
+
onClose: closeWorktreeCreator,
|
|
4134
|
+
onRetry: () => {
|
|
4135
|
+
if (worktreeModalWorkspaceId === void 0) return;
|
|
4136
|
+
modalReadViewRef.current = void 0;
|
|
4137
|
+
setSelectedBranch("");
|
|
4138
|
+
setNewBranch("");
|
|
4139
|
+
loadModalWorktreeView(worktreeModalWorkspaceId);
|
|
2751
4140
|
},
|
|
4141
|
+
onModeChange: changeWorktreeModalMode,
|
|
4142
|
+
onRetryImportCandidates: () => {
|
|
4143
|
+
if (worktreeModalWorkspaceId !== void 0) loadImportCandidates(worktreeModalWorkspaceId);
|
|
4144
|
+
},
|
|
4145
|
+
onSelectedImportPathChange: setSelectedImportPath,
|
|
2752
4146
|
onSelectedBranchChange: setSelectedBranch,
|
|
2753
4147
|
onNewBranchChange: setNewBranch,
|
|
2754
4148
|
onSubmit: submitWorktree
|
|
@@ -2770,11 +4164,29 @@ window.__ModuleLoader__.load({
|
|
|
2770
4164
|
workspaceId: target.workspaceId,
|
|
2771
4165
|
worktreeId: target.worktreeId
|
|
2772
4166
|
}
|
|
2773
|
-
});
|
|
4167
|
+
}, permission, onPermissionNotice);
|
|
2774
4168
|
await invalidateWorktreeContext?.(target.workspaceId);
|
|
2775
4169
|
setWorktreeRemoval(void 0);
|
|
2776
4170
|
});
|
|
2777
4171
|
}
|
|
4172
|
+
}),
|
|
4173
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.RiskConfirmation, {
|
|
4174
|
+
open: fullAccessConfirmationSnapshot !== void 0,
|
|
4175
|
+
title: t("permission.fullAccessTitle"),
|
|
4176
|
+
description: fullAccessConfirmationSnapshot === void 0 ? "" : t("permission.fullAccessDescription", { cwd: fullAccessConfirmationSnapshot.cwd }),
|
|
4177
|
+
acknowledgeLabel: t("permission.fullAccessAcknowledge"),
|
|
4178
|
+
cancelLabel: t("dialog.cancel"),
|
|
4179
|
+
confirmLabel: t("permission.fullAccessEnable"),
|
|
4180
|
+
acknowledged: fullAccessAcknowledged,
|
|
4181
|
+
onAcknowledgedChange: setFullAccessAcknowledged,
|
|
4182
|
+
onCancel: () => {
|
|
4183
|
+
setFullAccessAcknowledged(false);
|
|
4184
|
+
fullAccessConfirmation?.resolve(false);
|
|
4185
|
+
},
|
|
4186
|
+
onConfirm: () => {
|
|
4187
|
+
setFullAccessAcknowledged(false);
|
|
4188
|
+
fullAccessConfirmation?.resolve(true);
|
|
4189
|
+
}
|
|
2778
4190
|
})
|
|
2779
4191
|
]
|
|
2780
4192
|
});
|
|
@@ -3140,6 +4552,313 @@ window.__ModuleLoader__.load({
|
|
|
3140
4552
|
};
|
|
3141
4553
|
}
|
|
3142
4554
|
//#endregion
|
|
4555
|
+
//#region lib/client/worktree-permission.js
|
|
4556
|
+
/**
|
|
4557
|
+
* Coordinate async permission requests with the one in-page confirmation
|
|
4558
|
+
* rendered by the Worktree surface. Requests are serialized so concurrent
|
|
4559
|
+
* Worktree Session creations cannot replace one another's dialog.
|
|
4560
|
+
*/
|
|
4561
|
+
function createWorktreeFullAccessConfirmationController() {
|
|
4562
|
+
let active;
|
|
4563
|
+
const queue = [];
|
|
4564
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
4565
|
+
let disposed = false;
|
|
4566
|
+
const notify = () => {
|
|
4567
|
+
for (const listener of listeners) listener();
|
|
4568
|
+
};
|
|
4569
|
+
const showNext = () => {
|
|
4570
|
+
if (active !== void 0) return;
|
|
4571
|
+
active = queue.shift();
|
|
4572
|
+
notify();
|
|
4573
|
+
};
|
|
4574
|
+
return {
|
|
4575
|
+
getSnapshot: () => active?.input,
|
|
4576
|
+
subscribe: (listener) => {
|
|
4577
|
+
listeners.add(listener);
|
|
4578
|
+
return () => {
|
|
4579
|
+
listeners.delete(listener);
|
|
4580
|
+
};
|
|
4581
|
+
},
|
|
4582
|
+
request: (input) => {
|
|
4583
|
+
if (disposed) return Promise.resolve(false);
|
|
4584
|
+
return new Promise((resolve) => {
|
|
4585
|
+
queue.push({
|
|
4586
|
+
input,
|
|
4587
|
+
resolve
|
|
4588
|
+
});
|
|
4589
|
+
showNext();
|
|
4590
|
+
});
|
|
4591
|
+
},
|
|
4592
|
+
resolve: (confirmed) => {
|
|
4593
|
+
if (active === void 0) return;
|
|
4594
|
+
const current = active;
|
|
4595
|
+
active = void 0;
|
|
4596
|
+
current.resolve(confirmed);
|
|
4597
|
+
showNext();
|
|
4598
|
+
},
|
|
4599
|
+
dispose: () => {
|
|
4600
|
+
if (disposed) return;
|
|
4601
|
+
disposed = true;
|
|
4602
|
+
active?.resolve(false);
|
|
4603
|
+
active = void 0;
|
|
4604
|
+
for (const pending of queue.splice(0)) pending.resolve(false);
|
|
4605
|
+
notify();
|
|
4606
|
+
}
|
|
4607
|
+
};
|
|
4608
|
+
}
|
|
4609
|
+
//#endregion
|
|
4610
|
+
//#region lib/client/worktree-permission-icon.js
|
|
4611
|
+
const PLUGIN_ID = "@cerbur/clutch-dsh-worktree";
|
|
4612
|
+
const STYLE_ID = `${PLUGIN_ID}/permission-icon`;
|
|
4613
|
+
const WORKTREE_PERMISSION_LABEL = "Worktree Full Access";
|
|
4614
|
+
/** DOM marker owned only by this plugin's permission icon decorator. */
|
|
4615
|
+
const WORKTREE_PERMISSION_ICON_ATTRIBUTE = "data-clutch-dsh-worktree-permission-icon";
|
|
4616
|
+
const ICON_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\"><path d=\"M13.0762 1.37207C14.0846 1.37228 14.9021 2.19077 14.9023 3.19922C14.9022 4.20772 14.0847 5.02518 13.0762 5.02539C12.2967 5.02539 11.6325 4.53691 11.3701 3.84961H4.35547C4.79397 4.26458 5.15861 4.7644 5.41699 5.33496L7.10645 9.06738C7.88526 10.7875 9.55104 11.9228 11.4189 12.0371C11.7085 11.4109 12.3411 10.9756 13.0762 10.9756C14.0843 10.9759 14.9023 11.7936 14.9023 12.8018C14.9023 13.81 14.0843 14.6277 13.0762 14.6279C12.2534 14.6279 11.5574 14.0832 11.3291 13.335C8.9868 13.1879 6.89981 11.7612 5.92285 9.60352L4.23242 5.87109C3.67503 4.64033 2.44878 3.84961 1.09766 3.84961V2.54883C1.10665 2.54883 1.11601 2.54975 1.125 2.5498L11.3701 2.54883C11.6326 1.86151 12.2969 1.37207 13.0762 1.37207ZM13.0762 12.2764C12.7858 12.2764 12.5508 12.5114 12.5508 12.8018C12.5508 13.0921 12.7858 13.3281 13.0762 13.3281C13.3664 13.3279 13.6025 13.092 13.6025 12.8018C13.6025 12.5115 13.3664 12.2766 13.0762 12.2764ZM13.0762 2.67285C12.7855 2.67285 12.55 2.90861 12.5498 3.19922C12.5499 3.48987 12.7855 3.72559 13.0762 3.72559C13.3667 3.72538 13.6024 3.48975 13.6025 3.19922C13.6023 2.90874 13.3666 2.67306 13.0762 2.67285Z\" fill=\"black\"/></svg>";
|
|
4617
|
+
function iconStyles() {
|
|
4618
|
+
const mask = `url("data:image/svg+xml,${encodeURIComponent(ICON_SVG)}")`;
|
|
4619
|
+
return `
|
|
4620
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]::before {
|
|
4621
|
+
content: "";
|
|
4622
|
+
display: inline-block;
|
|
4623
|
+
flex: 0 0 auto;
|
|
4624
|
+
width: 16px;
|
|
4625
|
+
height: 16px;
|
|
4626
|
+
background-color: var(--dsw-alias-label-tertiary, currentColor);
|
|
4627
|
+
-webkit-mask-image: ${mask};
|
|
4628
|
+
mask-image: ${mask};
|
|
4629
|
+
-webkit-mask-position: center;
|
|
4630
|
+
mask-position: center;
|
|
4631
|
+
-webkit-mask-repeat: no-repeat;
|
|
4632
|
+
mask-repeat: no-repeat;
|
|
4633
|
+
-webkit-mask-size: contain;
|
|
4634
|
+
mask-size: contain;
|
|
4635
|
+
}
|
|
4636
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"]::before {
|
|
4637
|
+
width: 14px;
|
|
4638
|
+
height: 14px;
|
|
4639
|
+
}
|
|
4640
|
+
@container (max-width: 460px) {
|
|
4641
|
+
[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}="trigger"] > span:first-of-type {
|
|
4642
|
+
display: none;
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
`;
|
|
4646
|
+
}
|
|
4647
|
+
function normalizedText(element) {
|
|
4648
|
+
return (element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
4649
|
+
}
|
|
4650
|
+
function isWorktreeMenuItem(element) {
|
|
4651
|
+
return element.matches("button[role=\"menuitem\"]") && normalizedText(element) === WORKTREE_PERMISSION_LABEL && element.closest("[role=\"menu\"]") !== null;
|
|
4652
|
+
}
|
|
4653
|
+
function isWorktreeTrigger(element) {
|
|
4654
|
+
if (!element.matches("button[aria-label]")) return false;
|
|
4655
|
+
const label = element.getAttribute("aria-label") ?? "";
|
|
4656
|
+
return /^(?:access mode,\s*current:\s*|访问模式,当前:\s*)worktree full access$/iu.test(label.trim());
|
|
4657
|
+
}
|
|
4658
|
+
/** Mark the native custom permission row and trigger for CSS decoration. */
|
|
4659
|
+
function decorateWorktreePermissionIcons(document) {
|
|
4660
|
+
for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) {
|
|
4661
|
+
const kind = marked.getAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4662
|
+
if (kind === "menu" && !isWorktreeMenuItem(marked) || kind === "trigger" && !isWorktreeTrigger(marked)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4663
|
+
}
|
|
4664
|
+
for (const item of document.querySelectorAll("button[role=\"menuitem\"]")) if (isWorktreeMenuItem(item)) item.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "menu");
|
|
4665
|
+
for (const button of document.querySelectorAll("button[aria-label]")) if (isWorktreeTrigger(button)) button.setAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE, "trigger");
|
|
4666
|
+
}
|
|
4667
|
+
/** Install the Worktree permission icon and return a plugin-local disposer. */
|
|
4668
|
+
function installWorktreePermissionIcon(document) {
|
|
4669
|
+
for (const existing of document.querySelectorAll("style[data-plugin-css]")) if (existing.getAttribute("data-plugin-css") === STYLE_ID) existing.remove();
|
|
4670
|
+
const style = document.createElement("style");
|
|
4671
|
+
style.setAttribute("data-plugin", PLUGIN_ID);
|
|
4672
|
+
style.setAttribute("data-plugin-css", STYLE_ID);
|
|
4673
|
+
style.textContent = iconStyles();
|
|
4674
|
+
document.head.appendChild(style);
|
|
4675
|
+
let active = true;
|
|
4676
|
+
let queued = false;
|
|
4677
|
+
const scan = () => {
|
|
4678
|
+
if (!active || queued) return;
|
|
4679
|
+
queued = true;
|
|
4680
|
+
queueMicrotask(() => {
|
|
4681
|
+
queued = false;
|
|
4682
|
+
if (active) decorateWorktreePermissionIcons(document);
|
|
4683
|
+
});
|
|
4684
|
+
};
|
|
4685
|
+
decorateWorktreePermissionIcons(document);
|
|
4686
|
+
const observer = typeof MutationObserver === "function" ? new MutationObserver(scan) : void 0;
|
|
4687
|
+
observer?.observe(document.documentElement, {
|
|
4688
|
+
attributes: true,
|
|
4689
|
+
attributeFilter: ["aria-label"],
|
|
4690
|
+
characterData: true,
|
|
4691
|
+
childList: true,
|
|
4692
|
+
subtree: true
|
|
4693
|
+
});
|
|
4694
|
+
return () => {
|
|
4695
|
+
if (!active) return;
|
|
4696
|
+
active = false;
|
|
4697
|
+
observer?.disconnect();
|
|
4698
|
+
style.remove();
|
|
4699
|
+
for (const marked of document.querySelectorAll(`[${WORKTREE_PERMISSION_ICON_ATTRIBUTE}]`)) marked.removeAttribute(WORKTREE_PERMISSION_ICON_ATTRIBUTE);
|
|
4700
|
+
};
|
|
4701
|
+
}
|
|
4702
|
+
//#endregion
|
|
4703
|
+
//#region lib/client/worktree-session-fork.js
|
|
4704
|
+
function recoveryKey(sourceSessionId, childSessionId) {
|
|
4705
|
+
return `${sourceSessionId}\u0000${childSessionId}`;
|
|
4706
|
+
}
|
|
4707
|
+
/**
|
|
4708
|
+
* Coordinate native Session fork with the plugin-owned Worktree relation.
|
|
4709
|
+
* Native Session creation always wins: plugin lookup/bind failures are kept as
|
|
4710
|
+
* recovery state and never turn an already-created child into a failed fork.
|
|
4711
|
+
*/
|
|
4712
|
+
function createWorktreeSessionForkCoordinator(options) {
|
|
4713
|
+
let disposed = false;
|
|
4714
|
+
let revision = 0;
|
|
4715
|
+
let pending = /* @__PURE__ */ new Map();
|
|
4716
|
+
let recoverySnapshot = {
|
|
4717
|
+
revision: 0,
|
|
4718
|
+
pending: []
|
|
4719
|
+
};
|
|
4720
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
4721
|
+
const boundChildren = /* @__PURE__ */ new Set();
|
|
4722
|
+
const bindingInFlight = /* @__PURE__ */ new Map();
|
|
4723
|
+
let reconciliationInFlight;
|
|
4724
|
+
let reconciliationAgain = false;
|
|
4725
|
+
const publish = () => {
|
|
4726
|
+
revision += 1;
|
|
4727
|
+
recoverySnapshot = {
|
|
4728
|
+
revision,
|
|
4729
|
+
pending: [...pending.values()]
|
|
4730
|
+
};
|
|
4731
|
+
for (const subscriber of subscribers) subscriber();
|
|
4732
|
+
};
|
|
4733
|
+
const setRecovery = (sourceSessionId, childSessionId, error, target) => {
|
|
4734
|
+
if (disposed) return;
|
|
4735
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4736
|
+
pending = new Map(pending).set(key, {
|
|
4737
|
+
key,
|
|
4738
|
+
sourceSessionId,
|
|
4739
|
+
childSessionId,
|
|
4740
|
+
...target === void 0 ? {} : { binding: target },
|
|
4741
|
+
error
|
|
4742
|
+
});
|
|
4743
|
+
publish();
|
|
4744
|
+
};
|
|
4745
|
+
const clearRecovery = (sourceSessionId, childSessionId) => {
|
|
4746
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4747
|
+
if (!pending.has(key)) return;
|
|
4748
|
+
const next = new Map(pending);
|
|
4749
|
+
next.delete(key);
|
|
4750
|
+
pending = next;
|
|
4751
|
+
publish();
|
|
4752
|
+
};
|
|
4753
|
+
const attemptBinding = async (sourceSessionId, childSessionId) => {
|
|
4754
|
+
if (disposed || boundChildren.has(childSessionId)) return { bound: false };
|
|
4755
|
+
let target;
|
|
4756
|
+
try {
|
|
4757
|
+
target = await options.findBinding(sourceSessionId);
|
|
4758
|
+
} catch (error) {
|
|
4759
|
+
setRecovery(sourceSessionId, childSessionId, error);
|
|
4760
|
+
return { bound: false };
|
|
4761
|
+
}
|
|
4762
|
+
if (disposed) return { bound: false };
|
|
4763
|
+
if (target === void 0 || target.status !== "active") {
|
|
4764
|
+
clearRecovery(sourceSessionId, childSessionId);
|
|
4765
|
+
return { bound: false };
|
|
4766
|
+
}
|
|
4767
|
+
try {
|
|
4768
|
+
await options.bindSession({
|
|
4769
|
+
workspaceId: target.workspaceId,
|
|
4770
|
+
worktreeId: target.worktreeId,
|
|
4771
|
+
sessionId: childSessionId
|
|
4772
|
+
});
|
|
4773
|
+
if (disposed) return { bound: false };
|
|
4774
|
+
const childBinding = {
|
|
4775
|
+
workspaceId: target.workspaceId,
|
|
4776
|
+
worktreeId: target.worktreeId,
|
|
4777
|
+
sessionId: childSessionId,
|
|
4778
|
+
status: "active"
|
|
4779
|
+
};
|
|
4780
|
+
boundChildren.add(childSessionId);
|
|
4781
|
+
clearRecovery(sourceSessionId, childSessionId);
|
|
4782
|
+
options.onBound?.(childBinding);
|
|
4783
|
+
publish();
|
|
4784
|
+
return { bound: true };
|
|
4785
|
+
} catch (error) {
|
|
4786
|
+
setRecovery(sourceSessionId, childSessionId, error, target);
|
|
4787
|
+
return { bound: false };
|
|
4788
|
+
}
|
|
4789
|
+
};
|
|
4790
|
+
const bindChild = (sourceSessionId, childSessionId) => {
|
|
4791
|
+
if (disposed || boundChildren.has(childSessionId)) return Promise.resolve({ bound: false });
|
|
4792
|
+
const key = recoveryKey(sourceSessionId, childSessionId);
|
|
4793
|
+
const current = bindingInFlight.get(key);
|
|
4794
|
+
if (current !== void 0) return current;
|
|
4795
|
+
const promise = attemptBinding(sourceSessionId, childSessionId).finally(() => {
|
|
4796
|
+
if (bindingInFlight.get(key) === promise) bindingInFlight.delete(key);
|
|
4797
|
+
});
|
|
4798
|
+
bindingInFlight.set(key, promise);
|
|
4799
|
+
return promise;
|
|
4800
|
+
};
|
|
4801
|
+
const reconcileNow = async () => {
|
|
4802
|
+
if (disposed || options.sessions === void 0) return;
|
|
4803
|
+
const snapshot = options.sessions.getSnapshot();
|
|
4804
|
+
if (snapshot.phase === "pending") return;
|
|
4805
|
+
if (!Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null) return;
|
|
4806
|
+
const candidates = snapshot.ids.flatMap((childSessionId) => {
|
|
4807
|
+
const summary = snapshot.byId[childSessionId];
|
|
4808
|
+
if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
|
|
4809
|
+
return [{
|
|
4810
|
+
childSessionId,
|
|
4811
|
+
sourceSessionId: summary.parentId
|
|
4812
|
+
}];
|
|
4813
|
+
});
|
|
4814
|
+
await Promise.all(candidates.map(({ childSessionId, sourceSessionId }) => bindChild(sourceSessionId, childSessionId).then(() => void 0)));
|
|
4815
|
+
};
|
|
4816
|
+
const reconcile = () => {
|
|
4817
|
+
if (reconciliationInFlight !== void 0) {
|
|
4818
|
+
reconciliationAgain = true;
|
|
4819
|
+
return reconciliationInFlight;
|
|
4820
|
+
}
|
|
4821
|
+
const run = async () => {
|
|
4822
|
+
do {
|
|
4823
|
+
reconciliationAgain = false;
|
|
4824
|
+
await reconcileNow();
|
|
4825
|
+
} while (!disposed && reconciliationAgain);
|
|
4826
|
+
};
|
|
4827
|
+
const promise = run().finally(() => {
|
|
4828
|
+
if (reconciliationInFlight === promise) reconciliationInFlight = void 0;
|
|
4829
|
+
});
|
|
4830
|
+
reconciliationInFlight = promise;
|
|
4831
|
+
return promise;
|
|
4832
|
+
};
|
|
4833
|
+
return {
|
|
4834
|
+
recovery: {
|
|
4835
|
+
getSnapshot() {
|
|
4836
|
+
return recoverySnapshot;
|
|
4837
|
+
},
|
|
4838
|
+
subscribe(listener) {
|
|
4839
|
+
subscribers.add(listener);
|
|
4840
|
+
return () => subscribers.delete(listener);
|
|
4841
|
+
}
|
|
4842
|
+
},
|
|
4843
|
+
async fork(input) {
|
|
4844
|
+
const childSessionId = await options.fork(input);
|
|
4845
|
+
if (!disposed) await bindChild(input.sessionId, childSessionId);
|
|
4846
|
+
return childSessionId;
|
|
4847
|
+
},
|
|
4848
|
+
reconcile,
|
|
4849
|
+
async retry(key) {
|
|
4850
|
+
const item = pending.get(key);
|
|
4851
|
+
if (item === void 0 || disposed) return false;
|
|
4852
|
+
return (await bindChild(item.sourceSessionId, item.childSessionId)).bound;
|
|
4853
|
+
},
|
|
4854
|
+
dispose() {
|
|
4855
|
+
disposed = true;
|
|
4856
|
+
bindingInFlight.clear();
|
|
4857
|
+
subscribers.clear();
|
|
4858
|
+
}
|
|
4859
|
+
};
|
|
4860
|
+
}
|
|
4861
|
+
//#endregion
|
|
3143
4862
|
//#region lib/client/entry.js
|
|
3144
4863
|
/** Required DSH Client services; Connection is the sole Worktree wire dependency. */
|
|
3145
4864
|
const inject = [
|
|
@@ -3154,11 +4873,22 @@ window.__ModuleLoader__.load({
|
|
|
3154
4873
|
* with that fiber, so slot consumers share one manager and one request lifetime.
|
|
3155
4874
|
*/
|
|
3156
4875
|
function apply(ctx) {
|
|
4876
|
+
if (typeof document !== "undefined") ctx.effect(() => installWorktreePermissionIcon(document), "clutch-dsh-worktree: permission icon cleanup");
|
|
3157
4877
|
ctx.effect(() => ctx.locale.register(WORKTREE_NS, {
|
|
3158
4878
|
zh,
|
|
3159
4879
|
en
|
|
3160
4880
|
}), "clutch-dsh-worktree: locale dictionaries");
|
|
3161
4881
|
const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
|
|
4882
|
+
const fullAccessConfirmation = createWorktreeFullAccessConfirmationController();
|
|
4883
|
+
const permissionNotice = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(void 0);
|
|
4884
|
+
const permissionManager = typeof document !== "undefined" ? manager : void 0;
|
|
4885
|
+
const reportPermissionNotice = (input, result) => {
|
|
4886
|
+
const visible = result.status === "fallback-workspace-write" || result.status === "user-restricted" || result.status === "unverified";
|
|
4887
|
+
permissionNotice.set(visible ? {
|
|
4888
|
+
...input,
|
|
4889
|
+
result
|
|
4890
|
+
} : void 0);
|
|
4891
|
+
};
|
|
3162
4892
|
const sessions = ctx.sessions;
|
|
3163
4893
|
const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
|
|
3164
4894
|
const contextProjection = createWorktreeContextProjection({
|
|
@@ -3168,10 +4898,14 @@ window.__ModuleLoader__.load({
|
|
|
3168
4898
|
storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
|
|
3169
4899
|
});
|
|
3170
4900
|
ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
|
|
4901
|
+
ctx.effect(() => () => fullAccessConfirmation.dispose(), "clutch-dsh-worktree: Full Access confirmation cleanup");
|
|
3171
4902
|
ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
|
|
3172
4903
|
ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
|
|
3173
4904
|
contextProjection.refresh();
|
|
3174
4905
|
const viewStore = createWorktreeViewStore();
|
|
4906
|
+
const expandState = createWorktreeExpandStateStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
|
|
4907
|
+
const sessionOrder = createWorktreeSessionOrderStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
|
|
4908
|
+
ctx.effect(() => () => sessionOrder.dispose(), "clutch-dsh-worktree: Session order cleanup");
|
|
3175
4909
|
const ensureSessionWorkspace = (workspaceId, sessionId) => {
|
|
3176
4910
|
virtualWorkspaceMembership.ensure({
|
|
3177
4911
|
workspaceId,
|
|
@@ -3181,12 +4915,48 @@ window.__ModuleLoader__.load({
|
|
|
3181
4915
|
const syncSessionWorkspaces = (bindings) => {
|
|
3182
4916
|
virtualWorkspaceMembership.sync(bindings);
|
|
3183
4917
|
};
|
|
4918
|
+
const forkableSessions = ctx.sessions;
|
|
4919
|
+
const nativeFork = forkableSessions.fork;
|
|
4920
|
+
const findWorktreeSessionBinding = async (sessionId) => {
|
|
4921
|
+
const workspaceIds = ctx.workspaces.list.getSnapshot().items.map((workspace) => workspace.workspaceId);
|
|
4922
|
+
const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
|
|
4923
|
+
return (await manager.listBindings({ workspaceId })).find((binding) => binding.sessionId === sessionId && binding.status === "active");
|
|
4924
|
+
}));
|
|
4925
|
+
const found = results.find((result) => result.status === "fulfilled" && result.value !== void 0);
|
|
4926
|
+
if (found !== void 0) return found.value;
|
|
4927
|
+
const failed = results.find((result) => result.status === "rejected");
|
|
4928
|
+
if (failed !== void 0) throw failed.reason;
|
|
4929
|
+
};
|
|
4930
|
+
const forkCoordinator = typeof nativeFork !== "function" ? void 0 : createWorktreeSessionForkCoordinator({
|
|
4931
|
+
fork: (input) => nativeFork.call(ctx.sessions, input),
|
|
4932
|
+
findBinding: findWorktreeSessionBinding,
|
|
4933
|
+
bindSession: (input) => manager.bindSession(input),
|
|
4934
|
+
sessions: ctx.sessions.list
|
|
4935
|
+
});
|
|
4936
|
+
if (forkCoordinator !== void 0) {
|
|
4937
|
+
forkableSessions.fork = (input) => forkCoordinator.fork(input);
|
|
4938
|
+
const reconcileForkChildren = () => {
|
|
4939
|
+
forkCoordinator.reconcile();
|
|
4940
|
+
};
|
|
4941
|
+
const unsubscribeSessionList = ctx.sessions.list.subscribe(reconcileForkChildren);
|
|
4942
|
+
const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildren);
|
|
4943
|
+
ctx.effect(() => () => {
|
|
4944
|
+
unsubscribeSessionList();
|
|
4945
|
+
unsubscribeWorkspaceList();
|
|
4946
|
+
forkCoordinator.dispose();
|
|
4947
|
+
forkableSessions.fork = nativeFork;
|
|
4948
|
+
}, "clutch-dsh-worktree: Session fork cleanup");
|
|
4949
|
+
forkCoordinator.reconcile();
|
|
4950
|
+
}
|
|
3184
4951
|
const worktreeSessionConnector = createWorktreeSessionConnector({
|
|
3185
4952
|
manager,
|
|
3186
4953
|
sessions: ctx.sessions.list,
|
|
3187
4954
|
archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
|
|
3188
4955
|
createSession: async (input) => String(await sessions.create(input)),
|
|
3189
4956
|
ensureSessionWorkspace,
|
|
4957
|
+
permission: permissionManager,
|
|
4958
|
+
confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
|
|
4959
|
+
onPermissionResult: reportPermissionNotice,
|
|
3190
4960
|
openSession: (sessionId) => {
|
|
3191
4961
|
ctx.sessions.open(sessionId);
|
|
3192
4962
|
}
|
|
@@ -3213,8 +4983,16 @@ window.__ModuleLoader__.load({
|
|
|
3213
4983
|
locale: WORKTREE_NS,
|
|
3214
4984
|
inject: () => ({
|
|
3215
4985
|
available: true,
|
|
4986
|
+
expandState,
|
|
4987
|
+
sessionOrder,
|
|
3216
4988
|
hooks: { worktreeContext: contextProjection.store },
|
|
3217
4989
|
manager,
|
|
4990
|
+
permission: permissionManager,
|
|
4991
|
+
confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
|
|
4992
|
+
fullAccessConfirmation: typeof document === "undefined" ? void 0 : fullAccessConfirmation,
|
|
4993
|
+
onPermissionResult: reportPermissionNotice,
|
|
4994
|
+
onPermissionNotice: reportPermissionNotice,
|
|
4995
|
+
permissionNotice,
|
|
3218
4996
|
createWorkspace: async () => {
|
|
3219
4997
|
const workspacePath = await ctx.workspaces.pickDirectory();
|
|
3220
4998
|
if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
|
|
@@ -3248,6 +5026,7 @@ window.__ModuleLoader__.load({
|
|
|
3248
5026
|
if (!result.ok) throw new Error(result.error.message);
|
|
3249
5027
|
},
|
|
3250
5028
|
forkSession: (sessionId) => {
|
|
5029
|
+
if (forkableSessions.fork === void 0) return;
|
|
3251
5030
|
ctx.sessions.fork({
|
|
3252
5031
|
sessionId,
|
|
3253
5032
|
increaseTitle: true
|
|
@@ -3258,6 +5037,10 @@ window.__ModuleLoader__.load({
|
|
|
3258
5037
|
archiveSession: (sessionId) => ctx.workspaces.archiveSession(sessionId),
|
|
3259
5038
|
ensureSessionWorkspace,
|
|
3260
5039
|
syncSessionWorkspaces,
|
|
5040
|
+
forkRecovery: forkCoordinator?.recovery,
|
|
5041
|
+
retryForkSession: forkCoordinator === void 0 ? void 0 : async (key) => {
|
|
5042
|
+
await forkCoordinator.retry(key);
|
|
5043
|
+
},
|
|
3261
5044
|
openSession: (sessionId) => {
|
|
3262
5045
|
ctx.sessions.open(sessionId);
|
|
3263
5046
|
}
|