@cerbur/clutch-dsh-worktree 0.1.0
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 +136 -0
- package/cordis.patch.yml +5 -0
- package/lib/client/WorktreeModeAction.d.ts +11 -0
- package/lib/client/WorktreeModeAction.d.ts.map +1 -0
- package/lib/client/WorktreeModeAction.js +14 -0
- package/lib/client/WorktreeModeAction.js.map +1 -0
- package/lib/client/WorktreeSurface.d.ts +33 -0
- package/lib/client/WorktreeSurface.d.ts.map +1 -0
- package/lib/client/WorktreeSurface.js +834 -0
- package/lib/client/WorktreeSurface.js.map +1 -0
- package/lib/client/entry.d.ts +18 -0
- package/lib/client/entry.d.ts.map +1 -0
- package/lib/client/entry.js +100 -0
- package/lib/client/entry.js.map +1 -0
- package/lib/client/index.d.ts +7 -0
- package/lib/client/index.d.ts.map +1 -0
- package/lib/client/index.js +6 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/navigation.d.ts +7 -0
- package/lib/client/navigation.d.ts.map +1 -0
- package/lib/client/navigation.js +5 -0
- package/lib/client/navigation.js.map +1 -0
- package/lib/client/overlay-bounds.d.ts +11 -0
- package/lib/client/overlay-bounds.d.ts.map +1 -0
- package/lib/client/overlay-bounds.js +9 -0
- package/lib/client/overlay-bounds.js.map +1 -0
- package/lib/client/sidebar-overlay-geometry.d.ts +10 -0
- package/lib/client/sidebar-overlay-geometry.d.ts.map +1 -0
- package/lib/client/sidebar-overlay-geometry.js +96 -0
- package/lib/client/sidebar-overlay-geometry.js.map +1 -0
- package/lib/client/view-mode-store.d.ts +5 -0
- package/lib/client/view-mode-store.d.ts.map +1 -0
- package/lib/client/view-mode-store.js +15 -0
- package/lib/client/view-mode-store.js.map +1 -0
- package/lib/client/view-mode.d.ts +52 -0
- package/lib/client/view-mode.d.ts.map +1 -0
- package/lib/client/view-mode.js +76 -0
- package/lib/client/view-mode.js.map +1 -0
- package/lib/client/virtual-workspace-membership.d.ts +27 -0
- package/lib/client/virtual-workspace-membership.d.ts.map +1 -0
- package/lib/client/virtual-workspace-membership.js +95 -0
- package/lib/client/virtual-workspace-membership.js.map +1 -0
- package/lib/client/worktree-connection.d.ts +42 -0
- package/lib/client/worktree-connection.d.ts.map +1 -0
- package/lib/client/worktree-connection.js +139 -0
- package/lib/client/worktree-connection.js.map +1 -0
- package/lib/client/worktree-view.d.ts +63 -0
- package/lib/client/worktree-view.d.ts.map +1 -0
- package/lib/client/worktree-view.js +116 -0
- package/lib/client/worktree-view.js.map +1 -0
- package/lib/client.js +1952 -0
- package/lib/client.js.map +1 -0
- package/lib/contract/index.contract.d.ts +2 -0
- package/lib/contract/index.contract.d.ts.map +1 -0
- package/lib/contract/index.contract.js +51 -0
- package/lib/contract/index.contract.js.map +1 -0
- package/lib/contract/index.d.ts +181 -0
- package/lib/contract/index.d.ts.map +1 -0
- package/lib/contract/index.js +45 -0
- package/lib/contract/index.js.map +1 -0
- package/lib/host/dsh-read-adapter.d.ts +58 -0
- package/lib/host/dsh-read-adapter.d.ts.map +1 -0
- package/lib/host/dsh-read-adapter.js +59 -0
- package/lib/host/dsh-read-adapter.js.map +1 -0
- package/lib/host/index.d.ts +16 -0
- package/lib/host/index.d.ts.map +1 -0
- package/lib/host/index.js +14 -0
- package/lib/host/index.js.map +1 -0
- package/lib/host/remote.d.ts +16 -0
- package/lib/host/remote.d.ts.map +1 -0
- package/lib/host/remote.js +61 -0
- package/lib/host/remote.js.map +1 -0
- package/lib/host/service.d.ts +58 -0
- package/lib/host/service.d.ts.map +1 -0
- package/lib/host/service.js +121 -0
- package/lib/host/service.js.map +1 -0
- package/lib/index.d.ts +23 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +22 -0
- package/lib/index.js.map +1 -0
- package/lib/manage/index.d.ts +9 -0
- package/lib/manage/index.d.ts.map +1 -0
- package/lib/manage/index.js +8 -0
- package/lib/manage/index.js.map +1 -0
- package/lib/manage/manager.d.ts +86 -0
- package/lib/manage/manager.d.ts.map +1 -0
- package/lib/manage/manager.js +584 -0
- package/lib/manage/manager.js.map +1 -0
- package/lib/manage/types.d.ts +41 -0
- package/lib/manage/types.d.ts.map +1 -0
- package/lib/manage/types.js +2 -0
- package/lib/manage/types.js.map +1 -0
- package/lib/provider/git.d.ts +42 -0
- package/lib/provider/git.d.ts.map +1 -0
- package/lib/provider/git.js +222 -0
- package/lib/provider/git.js.map +1 -0
- package/lib/provider/index.d.ts +13 -0
- package/lib/provider/index.d.ts.map +1 -0
- package/lib/provider/index.js +12 -0
- package/lib/provider/index.js.map +1 -0
- package/lib/provider/sidecar.d.ts +85 -0
- package/lib/provider/sidecar.d.ts.map +1 -0
- package/lib/provider/sidecar.js +410 -0
- package/lib/provider/sidecar.js.map +1 -0
- package/lib/provider/types.d.ts +126 -0
- package/lib/provider/types.d.ts.map +1 -0
- package/lib/provider/types.js +46 -0
- package/lib/provider/types.js.map +1 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +290 -0
- package/lib/typert.remote-client.d.ts +32 -0
- package/lib/typert.remote-client.d.ts.map +1 -0
- package/lib/typert.remote-client.js +284 -0
- package/package.json +118 -0
|
@@ -0,0 +1,584 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { lstat, realpath, stat } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { LocalGitAdapter } from '../provider/git.js';
|
|
5
|
+
import { WorkspaceShardedSidecarRepository } from '../provider/sidecar.js';
|
|
6
|
+
import { isWorktreeProviderError, providerError, } from '../provider/types.js';
|
|
7
|
+
// 这是词法边界检查,既接受 parent 本身也接受其后代;物理路径边界会在后续单独校验。
|
|
8
|
+
// This is a lexical boundary check that accepts parent itself and descendants; physical boundaries are validated separately later.
|
|
9
|
+
function isSameOrInside(parent, candidate) {
|
|
10
|
+
const relative = path.relative(parent, candidate);
|
|
11
|
+
return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));
|
|
12
|
+
}
|
|
13
|
+
async function isDirectory(filePath) {
|
|
14
|
+
try {
|
|
15
|
+
return (await stat(filePath)).isDirectory();
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
if (error.code === 'ENOENT')
|
|
19
|
+
return false;
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function pathExists(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
await stat(filePath);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error.code === 'ENOENT')
|
|
30
|
+
return false;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// 优先比较 canonical path 以覆盖符号链接/路径别名;无法 canonicalize 时退回绝对词法比较。
|
|
35
|
+
// Prefer canonical paths to cover symlinks and aliases; fall back to absolute lexical comparison when canonicalization is unavailable.
|
|
36
|
+
async function samePhysicalPath(left, right) {
|
|
37
|
+
try {
|
|
38
|
+
return (await realpath(left)) === (await realpath(right));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return path.resolve(left) === path.resolve(right);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// 已存在的受信边界不允许是 symlink,避免后续创建绕过 DSH Home 的物理目录约束。
|
|
45
|
+
// Existing trusted boundaries may not be symlinks, preventing later creation from escaping the physical DSH Home boundary.
|
|
46
|
+
async function rejectSymlink(filePath, label) {
|
|
47
|
+
try {
|
|
48
|
+
if ((await lstat(filePath)).isSymbolicLink()) {
|
|
49
|
+
throw providerError('GIT_OPERATION_FAILED', `${label} must not be a symlink: ${filePath}`, {
|
|
50
|
+
path: filePath,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error.code === 'ENOENT')
|
|
56
|
+
return;
|
|
57
|
+
if (isWorktreeProviderError(error))
|
|
58
|
+
throw error;
|
|
59
|
+
throw providerError('GIT_OPERATION_FAILED', `Unable to inspect ${label}: ${filePath}`, {
|
|
60
|
+
path: filePath,
|
|
61
|
+
cause: String(error),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function asGitError(operation, workspaceRoot, targetPath, error) {
|
|
66
|
+
if (isWorktreeProviderError(error))
|
|
67
|
+
return error;
|
|
68
|
+
return providerError('GIT_OPERATION_FAILED', `Git ${operation} failed: ${String(error)}`, {
|
|
69
|
+
workspaceRoot,
|
|
70
|
+
...(targetPath ? { targetPath } : {}),
|
|
71
|
+
operation,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
function asSidecarError(error, workspaceId) {
|
|
75
|
+
if (isWorktreeProviderError(error))
|
|
76
|
+
return error;
|
|
77
|
+
return providerError('SIDECAR_UNAVAILABLE', `Sidecar operation failed for Workspace ${workspaceId}`, {
|
|
78
|
+
workspaceId,
|
|
79
|
+
cause: String(error),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function describeError(error) {
|
|
83
|
+
return error instanceof Error ? error.message : String(error);
|
|
84
|
+
}
|
|
85
|
+
function generatedId(idFactory) {
|
|
86
|
+
const worktreeId = idFactory();
|
|
87
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(worktreeId)) {
|
|
88
|
+
throw providerError('GIT_OPERATION_FAILED', 'Provider generated an invalid Worktree ID', { worktreeId });
|
|
89
|
+
}
|
|
90
|
+
return worktreeId;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Worktree/Session 用例编排器:DSH 只提供权威只读事实,Git 承担 worktree 副作用,sidecar 只保存外部关系。
|
|
94
|
+
* Worktree/Session use-case orchestrator: DSH supplies authoritative read-only facts, Git owns worktree side effects, and the sidecar stores only external relations.
|
|
95
|
+
*/
|
|
96
|
+
export class WorktreeManagerImpl {
|
|
97
|
+
dsh;
|
|
98
|
+
dshHome;
|
|
99
|
+
git;
|
|
100
|
+
sidecar;
|
|
101
|
+
idFactory;
|
|
102
|
+
/**
|
|
103
|
+
* 使用可注入端口组合 Manager;未注入的 Git 与 sidecar 端口会绑定到本地 Provider 实现。
|
|
104
|
+
* Composes the Manager from injectable ports; omitted Git and sidecar ports bind to local Provider implementations.
|
|
105
|
+
*/
|
|
106
|
+
constructor(options) {
|
|
107
|
+
if (!path.isAbsolute(options.dshHome)) {
|
|
108
|
+
throw providerError('SIDECAR_UNAVAILABLE', 'DSH Home must be an absolute path', {
|
|
109
|
+
dshHome: options.dshHome,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
this.dsh = options.dsh;
|
|
113
|
+
this.dshHome = path.resolve(options.dshHome);
|
|
114
|
+
this.git = options.git ?? new LocalGitAdapter();
|
|
115
|
+
this.sidecar = options.sidecar ?? new WorkspaceShardedSidecarRepository({ dshHome: this.dshHome });
|
|
116
|
+
this.idFactory = options.idFactory ?? (() => `wt_${randomUUID()}`);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 返回含 active/removed 状态的 sidecar Worktree 投影。
|
|
120
|
+
* Returns the sidecar Worktree projection, including active/removed state.
|
|
121
|
+
*/
|
|
122
|
+
async listWorktrees(input) {
|
|
123
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
124
|
+
const records = (await this.sidecar.read(input.workspaceId)).worktrees;
|
|
125
|
+
let gitWorktrees;
|
|
126
|
+
try {
|
|
127
|
+
gitWorktrees = await this.git.listWorktrees(workspace.rootPath);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return records.map((record) => {
|
|
131
|
+
const { health: _health, ...durableRecord } = record;
|
|
132
|
+
void _health;
|
|
133
|
+
return record.status === 'active'
|
|
134
|
+
? { ...durableRecord, health: 'repair' }
|
|
135
|
+
: durableRecord;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const nextRecords = [];
|
|
139
|
+
for (const record of records) {
|
|
140
|
+
const { health: _health, ...durableRecord } = record;
|
|
141
|
+
void _health;
|
|
142
|
+
if (record.status !== 'active') {
|
|
143
|
+
nextRecords.push(durableRecord);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
let ready = false;
|
|
147
|
+
for (const gitWorktree of gitWorktrees) {
|
|
148
|
+
if (path.resolve(gitWorktree.absolutePath) === path.resolve(record.absolutePath) ||
|
|
149
|
+
(await samePhysicalPath(gitWorktree.absolutePath, record.absolutePath))) {
|
|
150
|
+
ready = true;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
nextRecords.push({ ...durableRecord, health: ready ? 'ready' : 'repair' });
|
|
155
|
+
}
|
|
156
|
+
return nextRecords;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 将本地分支与所有 Git worktree 联合投影,以便调用方禁用已 checkout 的分支。
|
|
160
|
+
* Projects local branches against every Git worktree so callers can disable branches that are already checked out.
|
|
161
|
+
*/
|
|
162
|
+
async listBranches(input) {
|
|
163
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
164
|
+
await this.git.validateRepository(workspace.rootPath);
|
|
165
|
+
const [branches, worktrees] = await Promise.all([
|
|
166
|
+
this.git.listBranches(workspace.rootPath),
|
|
167
|
+
this.git.listWorktrees(workspace.rootPath),
|
|
168
|
+
]);
|
|
169
|
+
// `checkedOut` 覆盖主 Workspace 和所有 linked worktree;`isCurrent` 只标识与 Workspace root 同一物理路径的条目。
|
|
170
|
+
// `checkedOut` covers the main Workspace and all linked worktrees; `isCurrent` only identifies the entry at the Workspace root's physical path.
|
|
171
|
+
const checkedOut = new Set(worktrees.flatMap((worktree) => (worktree.branch ? [worktree.branch] : [])));
|
|
172
|
+
let currentBranch;
|
|
173
|
+
for (const worktree of worktrees) {
|
|
174
|
+
if (await samePhysicalPath(worktree.absolutePath, workspace.rootPath)) {
|
|
175
|
+
currentBranch = worktree.branch;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return branches.map((name) => ({
|
|
180
|
+
name,
|
|
181
|
+
isCurrent: currentBranch === name,
|
|
182
|
+
checkedOut: checkedOut.has(name),
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 创建受 DSH Home 边界管理的 Git Worktree,并仅在 sidecar 提交成功后返回;已 checkout 的
|
|
187
|
+
* base branch 可以通过 newBranch 创建新的本地 branch。持久化失败会补偿删除 Git Worktree。
|
|
188
|
+
* Creates a Git Worktree inside the managed DSH Home boundary and returns only after sidecar
|
|
189
|
+
* commit. An already checked-out base branch can create a new local branch through newBranch.
|
|
190
|
+
* Persistence failure compensates by removing the Git Worktree.
|
|
191
|
+
*/
|
|
192
|
+
async createWorktree(input) {
|
|
193
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
194
|
+
await this.git.validateRepository(workspace.rootPath);
|
|
195
|
+
if (typeof input.branch !== 'string' || input.branch.length === 0) {
|
|
196
|
+
throw providerError('GIT_OPERATION_FAILED', 'A local branch is required', {
|
|
197
|
+
workspaceRoot: workspace.rootPath,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const baseBranch = input.branch.trim();
|
|
201
|
+
if (input.newBranch !== undefined && typeof input.newBranch !== 'string') {
|
|
202
|
+
throw providerError('GIT_OPERATION_FAILED', 'A new branch name must be a string', {
|
|
203
|
+
workspaceRoot: workspace.rootPath,
|
|
204
|
+
baseBranch,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const newBranch = input.newBranch?.trim();
|
|
208
|
+
if (baseBranch.length === 0) {
|
|
209
|
+
throw providerError('GIT_OPERATION_FAILED', 'A local base branch is required', {
|
|
210
|
+
workspaceRoot: workspace.rootPath,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (input.newBranch !== undefined && (!newBranch || newBranch === baseBranch)) {
|
|
214
|
+
throw providerError('GIT_OPERATION_FAILED', 'A distinct new branch name is required', {
|
|
215
|
+
workspaceRoot: workspace.rootPath,
|
|
216
|
+
baseBranch,
|
|
217
|
+
newBranch: input.newBranch,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
const branches = await this.git.listBranches(workspace.rootPath);
|
|
221
|
+
if (!branches.includes(baseBranch)) {
|
|
222
|
+
throw providerError('GIT_OPERATION_FAILED', `Local branch does not exist: ${baseBranch}`, {
|
|
223
|
+
workspaceRoot: workspace.rootPath,
|
|
224
|
+
branch: baseBranch,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const targetBranch = newBranch ?? baseBranch;
|
|
228
|
+
if (newBranch !== undefined && branches.includes(newBranch)) {
|
|
229
|
+
throw providerError('WORKTREE_BRANCH_CONFLICT', `New branch already exists: ${newBranch}`, {
|
|
230
|
+
workspaceRoot: workspace.rootPath,
|
|
231
|
+
branch: newBranch,
|
|
232
|
+
baseBranch,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const existingGitWorktrees = await this.git.listWorktrees(workspace.rootPath);
|
|
236
|
+
if (existingGitWorktrees.some((worktree) => worktree.branch === targetBranch)) {
|
|
237
|
+
throw providerError('WORKTREE_BRANCH_CONFLICT', `Branch is already checked out: ${targetBranch}`, {
|
|
238
|
+
workspaceRoot: workspace.rootPath,
|
|
239
|
+
branch: targetBranch,
|
|
240
|
+
baseBranch,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
const worktreeId = generatedId(this.idFactory);
|
|
244
|
+
const targetPath = path.resolve(this.dshHome, 'clutch-dsh-worktree', 'worktree', worktreeId);
|
|
245
|
+
// 创建前同时检查词法和物理目录边界,阻止配置、ID 或 symlink 将目标引回 Workspace 或带出插件根目录。
|
|
246
|
+
// Check lexical and physical directory boundaries before creation so configuration, IDs, or symlinks cannot redirect the target into the Workspace or outside the plugin root.
|
|
247
|
+
this.validateGeneratedPath(workspace.rootPath, targetPath, worktreeId);
|
|
248
|
+
await this.validatePhysicalGeneratedPath(workspace.rootPath, targetPath);
|
|
249
|
+
if (await pathExists(targetPath)) {
|
|
250
|
+
throw providerError('GIT_OPERATION_FAILED', `Generated Worktree path already exists: ${targetPath}`, {
|
|
251
|
+
workspaceRoot: workspace.rootPath,
|
|
252
|
+
targetPath,
|
|
253
|
+
worktreeId,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
// Git 是第一个外部副作用;下方 sidecar mutation 是关系提交点,失败时必须反向清理这一步。
|
|
257
|
+
// Git is the first external side effect; the sidecar mutation below is the relation commit point and must compensate this step on failure.
|
|
258
|
+
try {
|
|
259
|
+
await this.git.createWorktree(workspace.rootPath, targetPath, baseBranch, newBranch);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
throw asGitError('create worktree', workspace.rootPath, targetPath, error);
|
|
263
|
+
}
|
|
264
|
+
const record = {
|
|
265
|
+
worktreeId,
|
|
266
|
+
workspaceId: input.workspaceId,
|
|
267
|
+
absolutePath: targetPath,
|
|
268
|
+
branch: targetBranch,
|
|
269
|
+
status: 'active',
|
|
270
|
+
};
|
|
271
|
+
try {
|
|
272
|
+
return await this.sidecar.mutate(input.workspaceId, (snapshot) => {
|
|
273
|
+
// 在互斥 mutation 内重新检查 ID/branch,避免 Git 预检之后的并发 sidecar 写入造成重复 active 记录。
|
|
274
|
+
// Recheck ID and branch inside the serialized mutation so a concurrent sidecar write after the Git preflight cannot create duplicate active records.
|
|
275
|
+
const idConflict = snapshot.worktrees.find((worktree) => worktree.worktreeId === worktreeId);
|
|
276
|
+
if (idConflict) {
|
|
277
|
+
throw providerError('SIDECAR_CORRUPT', `Generated Worktree ID is already recorded: ${worktreeId}`, {
|
|
278
|
+
worktreeId,
|
|
279
|
+
existingStatus: idConflict.status,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
const branchConflict = snapshot.worktrees.find((worktree) => worktree.status === 'active' && worktree.branch === targetBranch);
|
|
283
|
+
if (branchConflict) {
|
|
284
|
+
throw providerError('WORKTREE_BRANCH_CONFLICT', `Branch is already recorded as active: ${targetBranch}`, {
|
|
285
|
+
branch: targetBranch,
|
|
286
|
+
worktreeId: branchConflict.worktreeId,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const next = {
|
|
290
|
+
...snapshot,
|
|
291
|
+
worktrees: [...snapshot.worktrees, record],
|
|
292
|
+
};
|
|
293
|
+
return { result: record, snapshot: next };
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
const sidecarError = asSidecarError(error, input.workspaceId);
|
|
298
|
+
// sidecar 未提交时删除新建 Worktree;若补偿也失败,显式要求同步修复而不是掩盖残留 Git 状态。
|
|
299
|
+
// Remove the new Worktree when sidecar commit fails; if compensation also fails, require explicit synchronization instead of hiding residual Git state.
|
|
300
|
+
try {
|
|
301
|
+
await this.git.removeWorktree(workspace.rootPath, targetPath);
|
|
302
|
+
}
|
|
303
|
+
catch (cleanupError) {
|
|
304
|
+
throw providerError('SIDECAR_SYNC_REQUIRED', `Sidecar write failed and the newly created Worktree could not be cleaned up: ${targetPath}`, {
|
|
305
|
+
workspaceId: input.workspaceId,
|
|
306
|
+
workspaceRoot: workspace.rootPath,
|
|
307
|
+
targetPath,
|
|
308
|
+
sidecarError: sidecarError.message,
|
|
309
|
+
cleanupError: describeError(cleanupError),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
throw sidecarError;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* 先删除 Git Worktree,再原子标记 record 为 removed 并保留 detached bindings;失败阶段决定该操作是否可直接重试或需要同步修复。
|
|
317
|
+
* Removes the Git Worktree first, then atomically marks its record removed and preserves detached bindings; the failure phase determines whether retry or synchronization repair is required.
|
|
318
|
+
*/
|
|
319
|
+
async removeWorktree(input) {
|
|
320
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
321
|
+
// 该标记区分“尚无 Git 副作用”的失败和“Git 已删除但 sidecar 未提交”的部分成功。
|
|
322
|
+
// This marker distinguishes failures before any Git side effect from partial success where Git removed the Worktree but sidecar commit failed.
|
|
323
|
+
let gitRemoved = false;
|
|
324
|
+
try {
|
|
325
|
+
await this.sidecar.mutate(input.workspaceId, async (snapshot) => {
|
|
326
|
+
const record = snapshot.worktrees.find((worktree) => worktree.worktreeId === input.worktreeId);
|
|
327
|
+
if (!record) {
|
|
328
|
+
throw providerError('WORKTREE_NOT_FOUND', `Worktree not found: ${input.worktreeId}`, {
|
|
329
|
+
worktreeId: input.worktreeId,
|
|
330
|
+
workspaceId: input.workspaceId,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
if (record.status === 'removed') {
|
|
334
|
+
throw providerError('WORKTREE_REMOVED', `Worktree has already been removed: ${input.worktreeId}`, {
|
|
335
|
+
worktreeId: input.worktreeId,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
await this.git.removeWorktree(workspace.rootPath, record.absolutePath);
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
let stillRegistered;
|
|
343
|
+
try {
|
|
344
|
+
stillRegistered = false;
|
|
345
|
+
for (const worktree of await this.git.listWorktrees(workspace.rootPath)) {
|
|
346
|
+
if (await samePhysicalPath(worktree.absolutePath, record.absolutePath)) {
|
|
347
|
+
stillRegistered = true;
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
throw asGitError('remove worktree', workspace.rootPath, record.absolutePath, error);
|
|
354
|
+
}
|
|
355
|
+
if (stillRegistered) {
|
|
356
|
+
throw asGitError('remove worktree', workspace.rootPath, record.absolutePath, error);
|
|
357
|
+
}
|
|
358
|
+
// Git 已不再报告这个物理 Worktree;这是上一次 sidecar 同步失败后的显式幂等修复路径。
|
|
359
|
+
// Git no longer reports this physical Worktree; this is the explicit idempotent repair path after an earlier sidecar sync failure.
|
|
360
|
+
}
|
|
361
|
+
gitRemoved = true;
|
|
362
|
+
// 保留 Worktree 与 binding 历史,只改变生命周期;DSH Session 从不在此流程中读取或删除。
|
|
363
|
+
// Preserve Worktree and binding history while changing lifecycle only; DSH Sessions are never read or deleted in this flow.
|
|
364
|
+
const next = {
|
|
365
|
+
...snapshot,
|
|
366
|
+
worktrees: snapshot.worktrees.map((candidate) => candidate.worktreeId === record.worktreeId ? { ...candidate, status: 'removed' } : candidate),
|
|
367
|
+
bindings: snapshot.bindings.map((binding) => binding.worktreeId === record.worktreeId && binding.status === 'active'
|
|
368
|
+
? { ...binding, status: 'detached' }
|
|
369
|
+
: binding),
|
|
370
|
+
};
|
|
371
|
+
return { result: undefined, snapshot: next };
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
if (gitRemoved) {
|
|
376
|
+
// 此时不能回滚 Git 删除,因此用专用错误暴露 Git/sidecar 不一致,供同一删除操作安全重试。
|
|
377
|
+
// Git removal cannot be rolled back here, so a dedicated error exposes the Git/sidecar divergence for a safe retry of the same removal.
|
|
378
|
+
const sidecarError = asSidecarError(error, input.workspaceId);
|
|
379
|
+
throw providerError('SIDECAR_SYNC_REQUIRED', `Git removed Worktree ${input.worktreeId}, but sidecar synchronization failed`, {
|
|
380
|
+
workspaceId: input.workspaceId,
|
|
381
|
+
worktreeId: input.worktreeId,
|
|
382
|
+
workspaceRoot: workspace.rootPath,
|
|
383
|
+
sidecarError: sidecarError.message,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* 返回 Workspace 的 active/detached Session 关系。
|
|
391
|
+
* Returns active/detached Session relations for the Workspace.
|
|
392
|
+
*/
|
|
393
|
+
async listBindings(input) {
|
|
394
|
+
await this.requireWorkspace(input.workspaceId);
|
|
395
|
+
return (await this.sidecar.read(input.workspaceId)).bindings;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* 将已由 DSH 创建且 cwd 指向目标 Worktree 的 Session 绑定到 sidecar;相同 active 请求幂等,其他既有关系一律冲突。
|
|
399
|
+
* Binds a DSH-created Session whose cwd already targets the Worktree; the same active request is idempotent and every other existing relation conflicts.
|
|
400
|
+
*/
|
|
401
|
+
async bindSession(input) {
|
|
402
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
403
|
+
// 查重、DSH 事实校验和追加发生在同一序列化 mutation 中,防止并发请求绕过单 Session 关系不变量。
|
|
404
|
+
// Duplicate checks, DSH fact validation, and append happen in one serialized mutation so concurrent requests cannot bypass the one-relation-per-Session invariant.
|
|
405
|
+
return this.sidecar.mutate(input.workspaceId, async (snapshot) => {
|
|
406
|
+
const worktree = snapshot.worktrees.find((candidate) => candidate.worktreeId === input.worktreeId);
|
|
407
|
+
if (!worktree) {
|
|
408
|
+
throw providerError('WORKTREE_NOT_FOUND', `Worktree not found: ${input.worktreeId}`, {
|
|
409
|
+
workspaceId: input.workspaceId,
|
|
410
|
+
worktreeId: input.worktreeId,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
if (worktree.status === 'removed') {
|
|
414
|
+
throw providerError('WORKTREE_REMOVED', `Worktree has been removed: ${input.worktreeId}`, {
|
|
415
|
+
workspaceId: input.workspaceId,
|
|
416
|
+
worktreeId: input.worktreeId,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
const existing = snapshot.bindings.find((binding) => binding.sessionId === input.sessionId);
|
|
420
|
+
if (existing) {
|
|
421
|
+
if (existing.worktreeId === input.worktreeId && existing.status === 'active') {
|
|
422
|
+
// 精确重试不触发磁盘写入;detached 历史不会被隐式重新激活。
|
|
423
|
+
// An exact retry performs no disk write; detached history is never reactivated implicitly.
|
|
424
|
+
return { result: existing, snapshot, changed: false };
|
|
425
|
+
}
|
|
426
|
+
throw providerError('SESSION_ALREADY_BOUND', `Session is already bound to Worktree ${existing.worktreeId}`, {
|
|
427
|
+
sessionId: input.sessionId,
|
|
428
|
+
worktreeId: existing.worktreeId,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
// Session identity、Workspace/Project 归属和持久化 cwd 都来自 DSH;插件只验证这些事实,不做修正写回。
|
|
432
|
+
// Session identity, Workspace/Project ownership, and persisted cwd come from DSH; the plugin validates these facts without writing corrections back.
|
|
433
|
+
const session = await this.dsh.getSession(input.sessionId);
|
|
434
|
+
if (!session) {
|
|
435
|
+
throw providerError('SESSION_NOT_FOUND', `Session not found: ${input.sessionId}`, {
|
|
436
|
+
sessionId: input.sessionId,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
this.assertSessionMatchesWorkspace(session, workspace, worktree);
|
|
440
|
+
const binding = {
|
|
441
|
+
workspaceId: input.workspaceId,
|
|
442
|
+
worktreeId: input.worktreeId,
|
|
443
|
+
sessionId: input.sessionId,
|
|
444
|
+
status: 'active',
|
|
445
|
+
};
|
|
446
|
+
return {
|
|
447
|
+
result: binding,
|
|
448
|
+
snapshot: { ...snapshot, bindings: [...snapshot.bindings, binding] },
|
|
449
|
+
};
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* 派生一次执行的 cwd:无 binding 或 detached 时使用 Workspace root,active 时要求对应 Worktree 记录和目录均有效。
|
|
454
|
+
* Derives cwd for one execution: no binding or detached uses the Workspace root, while active requires both a valid Worktree record and directory.
|
|
455
|
+
*/
|
|
456
|
+
async resolveRuntimeCwd(input) {
|
|
457
|
+
const workspace = await this.requireWorkspace(input.workspaceId);
|
|
458
|
+
const snapshot = await this.sidecar.read(input.workspaceId);
|
|
459
|
+
const binding = snapshot.bindings.find((candidate) => candidate.sessionId === input.sessionId);
|
|
460
|
+
// detached 是保留关系历史的安全 main fallback;active 关系损坏则在下方明确失败,绝不静默降级。
|
|
461
|
+
// Detached is a safe main fallback that preserves relation history; a broken active relation fails explicitly below and never degrades silently.
|
|
462
|
+
if (!binding || binding.status === 'detached')
|
|
463
|
+
return workspace.rootPath;
|
|
464
|
+
const worktree = snapshot.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId);
|
|
465
|
+
if (!worktree) {
|
|
466
|
+
throw providerError('WORKTREE_NOT_FOUND', `Active binding points to a missing Worktree: ${binding.worktreeId}`, {
|
|
467
|
+
workspaceId: input.workspaceId,
|
|
468
|
+
worktreeId: binding.worktreeId,
|
|
469
|
+
sessionId: input.sessionId,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
if (worktree.status !== 'active') {
|
|
473
|
+
throw providerError('WORKTREE_REMOVED', `Active binding points to a removed Worktree: ${worktree.worktreeId}`, {
|
|
474
|
+
workspaceId: input.workspaceId,
|
|
475
|
+
worktreeId: worktree.worktreeId,
|
|
476
|
+
sessionId: input.sessionId,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
if (!(await isDirectory(worktree.absolutePath))) {
|
|
480
|
+
throw providerError('WORKTREE_NOT_FOUND', `Active Worktree path does not exist: ${worktree.absolutePath}`, {
|
|
481
|
+
workspaceId: input.workspaceId,
|
|
482
|
+
worktreeId: worktree.worktreeId,
|
|
483
|
+
sessionId: input.sessionId,
|
|
484
|
+
absolutePath: worktree.absolutePath,
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
return worktree.absolutePath;
|
|
488
|
+
}
|
|
489
|
+
// Workspace root 始终从 DSH 只读 adapter 获取并在使用时验证,不复制到 sidecar。
|
|
490
|
+
// The Workspace root always comes from the read-only DSH adapter and is validated at use time rather than copied into the sidecar.
|
|
491
|
+
async requireWorkspace(workspaceId) {
|
|
492
|
+
const workspace = await this.dsh.getWorkspace(workspaceId);
|
|
493
|
+
if (!workspace || workspace.workspaceId !== workspaceId || !path.isAbsolute(workspace.rootPath)) {
|
|
494
|
+
throw providerError('WORKSPACE_NOT_FOUND', `Workspace is missing or has a non-absolute root: ${workspaceId}`, {
|
|
495
|
+
workspaceId,
|
|
496
|
+
rootPath: workspace?.rootPath ?? '',
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
const rootPath = path.resolve(workspace.rootPath);
|
|
500
|
+
if (!(await isDirectory(rootPath))) {
|
|
501
|
+
throw providerError('WORKSPACE_NOT_FOUND', `Workspace root does not exist: ${rootPath}`, {
|
|
502
|
+
workspaceId,
|
|
503
|
+
rootPath,
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
await realpath(rootPath);
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
throw providerError('WORKSPACE_NOT_FOUND', `Unable to resolve Workspace root: ${rootPath}`, {
|
|
511
|
+
workspaceId,
|
|
512
|
+
rootPath,
|
|
513
|
+
cause: String(error),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
return { ...workspace, rootPath };
|
|
517
|
+
}
|
|
518
|
+
// 第一层使用未解析路径验证目标属于插件根且不位于 Workspace 内。
|
|
519
|
+
// The first layer uses unresolved paths to ensure the target belongs to the plugin root and is not inside the Workspace.
|
|
520
|
+
validateGeneratedPath(workspaceRoot, targetPath, worktreeId) {
|
|
521
|
+
const pluginRoot = path.resolve(this.dshHome, 'clutch-dsh-worktree');
|
|
522
|
+
if (!isSameOrInside(pluginRoot, targetPath) || isSameOrInside(workspaceRoot, targetPath)) {
|
|
523
|
+
throw providerError('GIT_OPERATION_FAILED', 'Generated Worktree path is outside the allowed boundary', {
|
|
524
|
+
workspaceRoot,
|
|
525
|
+
targetPath,
|
|
526
|
+
worktreeId,
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
// 第二层拒绝受信祖先 symlink,并以 realpath 后的根重新计算目标,防止物理路径逃逸。
|
|
531
|
+
// The second layer rejects symlinked trusted ancestors and recomputes the target from the realpath root to prevent physical path escape.
|
|
532
|
+
async validatePhysicalGeneratedPath(workspaceRoot, targetPath) {
|
|
533
|
+
await rejectSymlink(this.dshHome, 'DSH Home');
|
|
534
|
+
await rejectSymlink(path.join(this.dshHome, 'clutch-dsh-worktree'), 'plugin sidecar root');
|
|
535
|
+
await rejectSymlink(path.join(this.dshHome, 'clutch-dsh-worktree', 'worktree'), 'Worktree root');
|
|
536
|
+
let canonicalDshHome;
|
|
537
|
+
try {
|
|
538
|
+
canonicalDshHome = await realpath(this.dshHome);
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
throw providerError('SIDECAR_UNAVAILABLE', `Unable to resolve DSH Home: ${this.dshHome}`, {
|
|
542
|
+
dshHome: this.dshHome,
|
|
543
|
+
cause: String(error),
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
const targetRelativeToDshHome = path.relative(this.dshHome, targetPath);
|
|
547
|
+
const canonicalTarget = path.resolve(canonicalDshHome, targetRelativeToDshHome);
|
|
548
|
+
const canonicalWorkspace = await realpath(workspaceRoot);
|
|
549
|
+
if (!isSameOrInside(canonicalDshHome, canonicalTarget) || isSameOrInside(canonicalWorkspace, canonicalTarget)) {
|
|
550
|
+
throw providerError('GIT_OPERATION_FAILED', 'Generated Worktree path crosses a physical boundary', {
|
|
551
|
+
workspaceRoot: canonicalWorkspace,
|
|
552
|
+
dshHome: canonicalDshHome,
|
|
553
|
+
targetPath: canonicalTarget,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// 绑定只接受 DSH 已按目标 Worktree cwd 创建的 Session;Manager 不替用户迁移或改写 Session。
|
|
558
|
+
// Binding accepts only Sessions already created by DSH with the target Worktree cwd; the Manager never migrates or rewrites a Session.
|
|
559
|
+
assertSessionMatchesWorkspace(session, workspace, worktree) {
|
|
560
|
+
if ((session.workspaceId !== undefined && session.workspaceId !== workspace.workspaceId) ||
|
|
561
|
+
(session.projectId !== undefined &&
|
|
562
|
+
workspace.projectId !== undefined &&
|
|
563
|
+
session.projectId !== workspace.projectId) ||
|
|
564
|
+
!path.isAbsolute(session.cwd) ||
|
|
565
|
+
path.resolve(session.cwd) !== path.resolve(worktree.absolutePath)) {
|
|
566
|
+
throw providerError('SESSION_CWD_MISMATCH', `Session cwd or Workspace association does not match Worktree`, {
|
|
567
|
+
sessionId: session.sessionId,
|
|
568
|
+
workspaceId: workspace.workspaceId,
|
|
569
|
+
expectedCwd: worktree.absolutePath,
|
|
570
|
+
actualCwd: session.cwd,
|
|
571
|
+
sessionWorkspaceId: session.workspaceId ?? '',
|
|
572
|
+
sessionProjectId: session.projectId ?? '',
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* 创建实现 `WorktreeManagerService` 的默认编排器,同时保留所有底层端口的注入能力。
|
|
579
|
+
* Creates the default `WorktreeManagerService` orchestrator while preserving injection for every low-level port.
|
|
580
|
+
*/
|
|
581
|
+
export function createWorktreeManager(options) {
|
|
582
|
+
return new WorktreeManagerImpl(options);
|
|
583
|
+
}
|
|
584
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/manage/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { WorktreeManager } from '../contract/index.js';
|
|
2
|
+
import type { DshReadAdapter, GitWorktreeAdapter, SidecarStore } from '../provider/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* 单次执行的 cwd 解析键;解析结果是临时 runtime context,不会写回 DSH Session 或 sidecar。
|
|
5
|
+
* Lookup key for one execution's cwd; the result is transient runtime context and is never written back to the DSH Session or sidecar.
|
|
6
|
+
*/
|
|
7
|
+
export interface RuntimeCwdInput {
|
|
8
|
+
readonly workspaceId: string;
|
|
9
|
+
readonly sessionId: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Manage composition 配置;DSH adapter 必须只读,`dshHome` 划定插件 sidecar/worktree 的绝对存储边界。
|
|
13
|
+
* Manage composition options; the DSH adapter must be read-only and `dshHome` defines the absolute storage boundary for plugin sidecars/worktrees.
|
|
14
|
+
*/
|
|
15
|
+
export interface WorktreeManagerOptions {
|
|
16
|
+
readonly dsh: DshReadAdapter;
|
|
17
|
+
readonly dshHome: string;
|
|
18
|
+
/**
|
|
19
|
+
* 可替换的底层端口主要用于 Host 组合与确定性测试;缺省时使用本地实现。
|
|
20
|
+
* Replaceable low-level ports for Host composition and deterministic tests; local implementations are used by default.
|
|
21
|
+
*/
|
|
22
|
+
readonly git?: GitWorktreeAdapter;
|
|
23
|
+
readonly sidecar?: SidecarStore;
|
|
24
|
+
/**
|
|
25
|
+
* 生成的 ID 会在任何文件系统副作用前校验为路径安全片段。
|
|
26
|
+
* Generated IDs are validated as path-safe segments before any filesystem side effect.
|
|
27
|
+
*/
|
|
28
|
+
readonly idFactory?: () => string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Host 侧的完整 Manage 服务;`resolveRuntimeCwd` 有意不属于 browser-safe `WorktreeManager` Remote 契约。
|
|
32
|
+
* Complete Host-side Manage service; `resolveRuntimeCwd` is intentionally absent from the browser-safe `WorktreeManager` Remote contract.
|
|
33
|
+
*/
|
|
34
|
+
export interface WorktreeManagerService extends WorktreeManager {
|
|
35
|
+
/**
|
|
36
|
+
* 每次调用都从 DSH Workspace 与 sidecar 重新派生 cwd;active 关系损坏时明确失败,不静默回退。
|
|
37
|
+
* Re-derives cwd from the DSH Workspace and sidecar on every call; a broken active relation fails explicitly instead of silently falling back.
|
|
38
|
+
*/
|
|
39
|
+
resolveRuntimeCwd(input: RuntimeCwdInput): Promise<string>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|