@made-by-moonlight/athene-plugin-workspace-worktree 0.9.1
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/LICENSE +22 -0
- package/dist/__tests__/activity-events.test.d.ts +8 -0
- package/dist/__tests__/activity-events.test.d.ts.map +1 -0
- package/dist/__tests__/activity-events.test.js +151 -0
- package/dist/__tests__/activity-events.test.js.map +1 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +1154 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +613 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import { existsSync, lstatSync, statSync, symlinkSync, linkSync, rmSync, mkdirSync, readdirSync, } from "node:fs";
|
|
5
|
+
import { join, resolve, basename, dirname, sep } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { getShell, isWindows, recordActivityEvent, } from "@made-by-moonlight/athene-core";
|
|
8
|
+
/** Timeout for git commands (30 seconds) */
|
|
9
|
+
const GIT_TIMEOUT = 30_000;
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
export const manifest = {
|
|
12
|
+
name: "worktree",
|
|
13
|
+
slot: "workspace",
|
|
14
|
+
description: "Workspace plugin: git worktrees",
|
|
15
|
+
version: "0.1.0",
|
|
16
|
+
};
|
|
17
|
+
/** Run a git command in a given directory */
|
|
18
|
+
async function git(cwd, ...args) {
|
|
19
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
20
|
+
cwd,
|
|
21
|
+
windowsHide: true,
|
|
22
|
+
timeout: GIT_TIMEOUT,
|
|
23
|
+
});
|
|
24
|
+
return stdout.trimEnd();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Normalize a path for cross-platform comparison. `git worktree list --porcelain`
|
|
28
|
+
* emits forward-slash paths on Windows even when callers constructed the
|
|
29
|
+
* directory with backslashes via `path.join`. Lowercase the drive letter so
|
|
30
|
+
* `C:` and `c:` match.
|
|
31
|
+
*/
|
|
32
|
+
function toComparablePath(p) {
|
|
33
|
+
const slash = p.replace(/\\/g, "/");
|
|
34
|
+
return slash.replace(/^([a-zA-Z]):/, (_, d) => d.toLowerCase() + ":");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Remove a directory, retrying on Windows when file handles haven't drained yet.
|
|
38
|
+
*
|
|
39
|
+
* On Windows, killing a pty-host with node-pty leaves a small window where
|
|
40
|
+
* child processes (conpty_console_list_agent.exe, the agent's spawned shell,
|
|
41
|
+
* .git/index.lock) still hold handles inside the worktree. rmSync(force: true)
|
|
42
|
+
* deletes individual files but the directory rmdir blocks with EBUSY/ENOTEMPTY/EPERM
|
|
43
|
+
* until the kernel drains those handles — typically 100 ms–2 min. Without retry,
|
|
44
|
+
* AO leaves an empty orphan directory that confuses the next git worktree
|
|
45
|
+
* operation and shows up as residue under the project's worktrees directory.
|
|
46
|
+
*/
|
|
47
|
+
async function removeDirWithRetry(target) {
|
|
48
|
+
if (!isWindows()) {
|
|
49
|
+
rmSync(target, { recursive: true, force: true });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const backoffsMs = [0, 100, 250, 500, 1000, 2000];
|
|
53
|
+
let lastErr;
|
|
54
|
+
for (const delay of backoffsMs) {
|
|
55
|
+
if (delay > 0)
|
|
56
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
57
|
+
try {
|
|
58
|
+
rmSync(target, { recursive: true, force: true });
|
|
59
|
+
if (!existsSync(target))
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
lastErr = err;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (existsSync(target)) {
|
|
67
|
+
throw new Error(`Failed to remove "${target}" after ${backoffsMs.length} attempts (Windows file-handle drain). ` +
|
|
68
|
+
`Last error: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function hasOriginRemote(cwd) {
|
|
72
|
+
try {
|
|
73
|
+
await git(cwd, "remote", "get-url", "origin");
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function refExists(cwd, ref) {
|
|
81
|
+
try {
|
|
82
|
+
await git(cwd, "rev-parse", "--verify", "--quiet", ref);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function resolveBaseRef(repoPath, defaultBranch, options) {
|
|
90
|
+
const hasOrigin = options?.hasOrigin ?? (await hasOriginRemote(repoPath));
|
|
91
|
+
if (hasOrigin) {
|
|
92
|
+
if (options?.branch) {
|
|
93
|
+
const remoteBranch = `origin/${options.branch}`;
|
|
94
|
+
if (await refExists(repoPath, remoteBranch))
|
|
95
|
+
return remoteBranch;
|
|
96
|
+
}
|
|
97
|
+
const remoteDefaultBranch = `origin/${defaultBranch}`;
|
|
98
|
+
if (await refExists(repoPath, remoteDefaultBranch))
|
|
99
|
+
return remoteDefaultBranch;
|
|
100
|
+
}
|
|
101
|
+
const localDefaultBranch = `refs/heads/${defaultBranch}`;
|
|
102
|
+
if (await refExists(repoPath, localDefaultBranch))
|
|
103
|
+
return localDefaultBranch;
|
|
104
|
+
throw new Error(`Unable to resolve base ref for default branch "${defaultBranch}"`);
|
|
105
|
+
}
|
|
106
|
+
async function isRegisteredWorktree(repoPath, worktreePath) {
|
|
107
|
+
try {
|
|
108
|
+
const output = await git(repoPath, "worktree", "list", "--porcelain");
|
|
109
|
+
// Normalize both sides so non-canonical inputs don't false-negative
|
|
110
|
+
// and let a subsequent rmSync delete a still-registered worktree
|
|
111
|
+
// (data loss). resolve() collapses trailing-slash / ".." segments;
|
|
112
|
+
// toComparablePath handles Windows backslashes and drive case.
|
|
113
|
+
const target = toComparablePath(resolve(worktreePath));
|
|
114
|
+
return output
|
|
115
|
+
.split("\n")
|
|
116
|
+
.some((line) => line.startsWith("worktree ") &&
|
|
117
|
+
toComparablePath(resolve(line.slice("worktree ".length))) === target);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function clearStaleWorktreePath(repoPath, worktreePath) {
|
|
124
|
+
if (!existsSync(worktreePath))
|
|
125
|
+
return;
|
|
126
|
+
try {
|
|
127
|
+
await git(repoPath, "worktree", "prune");
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Best-effort prune before checking whether the path is still registered.
|
|
131
|
+
}
|
|
132
|
+
if (await isRegisteredWorktree(repoPath, worktreePath)) {
|
|
133
|
+
throw new Error(`Worktree path "${worktreePath}" already exists and is still registered with git`);
|
|
134
|
+
}
|
|
135
|
+
rmSync(worktreePath, { recursive: true, force: true });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Restore recovery: clear any stale worktree registration and/or stale
|
|
139
|
+
* directory at `workspacePath` so a subsequent `git worktree add` can
|
|
140
|
+
* succeed. Both restore branches (re-attach existing branch, create from
|
|
141
|
+
* base) need this — without it, an `<path> already exists` failure repeats.
|
|
142
|
+
*
|
|
143
|
+
* Refuses to rmSync the path if it's still a registered worktree, which
|
|
144
|
+
* would silently destroy the user's work. The entry-point `worktree prune`
|
|
145
|
+
* in restore() already ran, so we don't prune again here.
|
|
146
|
+
*/
|
|
147
|
+
async function cleanupStaleWorkspacePath(repoPath, workspacePath) {
|
|
148
|
+
// Force-remove any registered worktree at this path. Best-effort — the
|
|
149
|
+
// path may not be registered, in which case git errors and we fall
|
|
150
|
+
// through to the dir cleanup.
|
|
151
|
+
try {
|
|
152
|
+
await git(repoPath, "worktree", "remove", "--force", workspacePath);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// Best-effort
|
|
156
|
+
}
|
|
157
|
+
if (existsSync(workspacePath)) {
|
|
158
|
+
if (await isRegisteredWorktree(repoPath, workspacePath)) {
|
|
159
|
+
throw new Error(`Worktree path "${workspacePath}" already exists and is still registered with git`);
|
|
160
|
+
}
|
|
161
|
+
// Use removeDirWithRetry for Windows file-handle drain races (matches
|
|
162
|
+
// destroy()'s fallback). On Unix this is just rmSync.
|
|
163
|
+
await removeDirWithRetry(workspacePath);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Restore recovery: re-attach an existing local branch to a worktree at
|
|
168
|
+
* `workspacePath`. Used when the branch is already present (destroy()
|
|
169
|
+
* preserves it) but the first `git worktree add <path> <branch>` failed
|
|
170
|
+
* — typically because `workspacePath` has a stale registry entry, a
|
|
171
|
+
* stale directory, or both.
|
|
172
|
+
*
|
|
173
|
+
* Never uses -b/-B: -b would fail with "branch already exists", and -B
|
|
174
|
+
* would force-reset the branch to a base ref and silently discard the
|
|
175
|
+
* session's commits, which is the opposite of restore's intent.
|
|
176
|
+
*/
|
|
177
|
+
async function reattachExistingBranch(repoPath, workspacePath, branch) {
|
|
178
|
+
await cleanupStaleWorkspacePath(repoPath, workspacePath);
|
|
179
|
+
await git(repoPath, "worktree", "add", workspacePath, branch);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Restore recovery: create a fresh branch at `workspacePath` from the
|
|
183
|
+
* appropriate base ref. Used when the local branch is missing — typically
|
|
184
|
+
* because only `origin/<branch>` exists and we need to materialize the
|
|
185
|
+
* local ref. Tries the remote ref first, then falls back to the local
|
|
186
|
+
* default branch.
|
|
187
|
+
*
|
|
188
|
+
* Runs the same stale-path cleanup as reattachExistingBranch so this path
|
|
189
|
+
* also recovers when `workspacePath` has a stale registry entry / dir.
|
|
190
|
+
*/
|
|
191
|
+
async function createBranchFromBase(repoPath, workspacePath, branch, defaultBranch, hasOrigin) {
|
|
192
|
+
await cleanupStaleWorkspacePath(repoPath, workspacePath);
|
|
193
|
+
const baseRef = await resolveBaseRef(repoPath, defaultBranch, { branch, hasOrigin });
|
|
194
|
+
if (!baseRef.startsWith("origin/")) {
|
|
195
|
+
// No remote available — create from the local default branch
|
|
196
|
+
await git(repoPath, "worktree", "add", "-b", branch, workspacePath, baseRef);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Branch might not exist locally — try the remote ref first, then fall
|
|
200
|
+
// back to the local default branch if the remote ref is unavailable.
|
|
201
|
+
try {
|
|
202
|
+
await git(repoPath, "worktree", "add", "-b", branch, workspacePath, baseRef);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
await git(repoPath, "worktree", "add", "-b", branch, workspacePath, `refs/heads/${defaultBranch}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function parseWorktreeList(output) {
|
|
209
|
+
const normalized = output.replace(/\r\n/g, "\n").trim();
|
|
210
|
+
if (!normalized)
|
|
211
|
+
return [];
|
|
212
|
+
return normalized
|
|
213
|
+
.split("\n\n")
|
|
214
|
+
.map((block) => {
|
|
215
|
+
let path = "";
|
|
216
|
+
let branch = null;
|
|
217
|
+
for (const line of block.split("\n")) {
|
|
218
|
+
if (line.startsWith("worktree ")) {
|
|
219
|
+
path = resolve(line.slice("worktree ".length));
|
|
220
|
+
}
|
|
221
|
+
else if (line.startsWith("branch ")) {
|
|
222
|
+
branch = line.slice("branch ".length).replace("refs/heads/", "");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return { path, branch };
|
|
226
|
+
})
|
|
227
|
+
.filter((entry) => entry.path.length > 0);
|
|
228
|
+
}
|
|
229
|
+
/** Only allow safe characters in path segments to prevent directory traversal */
|
|
230
|
+
const SAFE_PATH_SEGMENT = /^[a-zA-Z0-9_-]+$/;
|
|
231
|
+
function assertSafePathSegment(value, label) {
|
|
232
|
+
if (!SAFE_PATH_SEGMENT.test(value)) {
|
|
233
|
+
throw new Error(`Invalid ${label} "${value}": must match ${SAFE_PATH_SEGMENT}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/** Expand ~ to home directory */
|
|
237
|
+
function expandPath(p) {
|
|
238
|
+
if (p.startsWith("~/")) {
|
|
239
|
+
return join(homedir(), p.slice(2));
|
|
240
|
+
}
|
|
241
|
+
return p;
|
|
242
|
+
}
|
|
243
|
+
export function create(config) {
|
|
244
|
+
const worktreeBaseDir = config?.worktreeDir
|
|
245
|
+
? expandPath(config.worktreeDir)
|
|
246
|
+
: join(homedir(), ".worktrees");
|
|
247
|
+
return {
|
|
248
|
+
name: "worktree",
|
|
249
|
+
async create(cfg) {
|
|
250
|
+
assertSafePathSegment(cfg.projectId, "projectId");
|
|
251
|
+
assertSafePathSegment(cfg.sessionId, "sessionId");
|
|
252
|
+
const repoPath = expandPath(cfg.project.path);
|
|
253
|
+
const effectiveBaseDir = cfg.worktreeDir ?? worktreeBaseDir;
|
|
254
|
+
const projectWorktreeDir = cfg.worktreeDir
|
|
255
|
+
? effectiveBaseDir
|
|
256
|
+
: join(effectiveBaseDir, cfg.projectId);
|
|
257
|
+
const worktreePath = join(projectWorktreeDir, cfg.sessionId);
|
|
258
|
+
mkdirSync(projectWorktreeDir, { recursive: true });
|
|
259
|
+
await clearStaleWorktreePath(repoPath, worktreePath);
|
|
260
|
+
const hasOrigin = await hasOriginRemote(repoPath);
|
|
261
|
+
// Fetch latest from remote when origin exists
|
|
262
|
+
if (hasOrigin) {
|
|
263
|
+
try {
|
|
264
|
+
await git(repoPath, "fetch", "origin", "--quiet");
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Fetch may fail if offline — continue anyway
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
const baseRef = await resolveBaseRef(repoPath, cfg.project.defaultBranch, { hasOrigin });
|
|
271
|
+
// Create worktree with a new branch
|
|
272
|
+
try {
|
|
273
|
+
await git(repoPath, "worktree", "add", "-b", cfg.branch, worktreePath, baseRef);
|
|
274
|
+
}
|
|
275
|
+
catch (err) {
|
|
276
|
+
// Only retry if the error is "branch already exists"
|
|
277
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
278
|
+
if (!msg.includes("already exists")) {
|
|
279
|
+
throw new Error(`Failed to create worktree for branch "${cfg.branch}": ${msg}`, {
|
|
280
|
+
cause: err,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
// Branch already exists. It may be a stale session branch left behind
|
|
284
|
+
// from an earlier spawn, so compare it with the freshly-resolved base
|
|
285
|
+
// before reusing it. Surface the collision shape for RCA before the
|
|
286
|
+
// recovery path decides whether to reuse or reset the local branch.
|
|
287
|
+
recordActivityEvent({
|
|
288
|
+
projectId: cfg.projectId,
|
|
289
|
+
sessionId: cfg.sessionId,
|
|
290
|
+
source: "workspace",
|
|
291
|
+
kind: "workspace.branch_collision",
|
|
292
|
+
level: "warn",
|
|
293
|
+
summary: `branch "${cfg.branch}" already exists; falling back to worktree recovery`,
|
|
294
|
+
data: {
|
|
295
|
+
plugin: "workspace-worktree",
|
|
296
|
+
branch: cfg.branch,
|
|
297
|
+
errorMessage: msg,
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
const baseSha = await git(repoPath, "rev-parse", baseRef);
|
|
301
|
+
const branchRef = `refs/heads/${cfg.branch}`;
|
|
302
|
+
const existingBranchSha = (await refExists(repoPath, branchRef))
|
|
303
|
+
? await git(repoPath, "rev-parse", branchRef)
|
|
304
|
+
: undefined;
|
|
305
|
+
try {
|
|
306
|
+
if (existingBranchSha === baseSha) {
|
|
307
|
+
await git(repoPath, "worktree", "add", worktreePath, cfg.branch);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
await git(repoPath, "worktree", "add", "-B", cfg.branch, worktreePath, baseRef);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
catch (retryErr) {
|
|
314
|
+
// Retry failed — remove any orphaned worktree before rethrowing
|
|
315
|
+
try {
|
|
316
|
+
await git(repoPath, "worktree", "remove", "--force", worktreePath);
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
// Best-effort cleanup
|
|
320
|
+
}
|
|
321
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
322
|
+
throw new Error(`Failed to create worktree for branch "${cfg.branch}": ${retryMsg}`, {
|
|
323
|
+
cause: retryErr,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
path: worktreePath,
|
|
329
|
+
branch: cfg.branch,
|
|
330
|
+
sessionId: cfg.sessionId,
|
|
331
|
+
projectId: cfg.projectId,
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
async findManagedWorkspace(cfg) {
|
|
335
|
+
assertSafePathSegment(cfg.projectId, "projectId");
|
|
336
|
+
assertSafePathSegment(cfg.sessionId, "sessionId");
|
|
337
|
+
const repoPath = expandPath(cfg.project.path);
|
|
338
|
+
const effectiveBaseDir = cfg.worktreeDir ?? worktreeBaseDir;
|
|
339
|
+
const projectWorktreeDir = cfg.worktreeDir
|
|
340
|
+
? effectiveBaseDir
|
|
341
|
+
: join(effectiveBaseDir, cfg.projectId);
|
|
342
|
+
const currentManagedPath = resolve(join(projectWorktreeDir, cfg.sessionId));
|
|
343
|
+
const legacyManagedPath = resolve(join(worktreeBaseDir, cfg.projectId, cfg.sessionId));
|
|
344
|
+
const allowedPaths = new Set([currentManagedPath, legacyManagedPath]);
|
|
345
|
+
const worktrees = parseWorktreeList(await git(repoPath, "worktree", "list", "--porcelain"));
|
|
346
|
+
const matches = worktrees.filter((entry) => entry.branch === cfg.branch && existsSync(entry.path));
|
|
347
|
+
if (matches.length === 0)
|
|
348
|
+
return null;
|
|
349
|
+
if (matches.length > 1) {
|
|
350
|
+
throw new Error(`Found multiple worktrees for orchestrator branch "${cfg.branch}". Reuse one workspace or remove the extras before starting the orchestrator.`);
|
|
351
|
+
}
|
|
352
|
+
const match = matches[0];
|
|
353
|
+
if (!allowedPaths.has(match.path)) {
|
|
354
|
+
throw new Error(`Found existing worktree for orchestrator branch "${cfg.branch}" at "${match.path}", but it is outside AO-managed worktree directories. Reuse it manually or remove it and try again.`);
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
path: match.path,
|
|
358
|
+
branch: cfg.branch,
|
|
359
|
+
sessionId: cfg.sessionId,
|
|
360
|
+
projectId: cfg.projectId,
|
|
361
|
+
};
|
|
362
|
+
},
|
|
363
|
+
async destroy(workspacePath) {
|
|
364
|
+
try {
|
|
365
|
+
const gitCommonDir = await git(workspacePath, "rev-parse", "--path-format=absolute", "--git-common-dir");
|
|
366
|
+
// git-common-dir returns something like /path/to/repo/.git
|
|
367
|
+
const repoPath = resolve(gitCommonDir, "..");
|
|
368
|
+
await git(repoPath, "worktree", "remove", "--force", workspacePath);
|
|
369
|
+
// NOTE: We intentionally do NOT delete the branch here. The worktree
|
|
370
|
+
// removal is sufficient. Auto-deleting branches risks removing
|
|
371
|
+
// pre-existing local branches unrelated to this workspace (any branch
|
|
372
|
+
// containing "/" would have been deleted). Stale branches can be
|
|
373
|
+
// cleaned up separately via `git branch --merged` or similar.
|
|
374
|
+
}
|
|
375
|
+
catch (err) {
|
|
376
|
+
// If git commands fail, try to clean up the directory.
|
|
377
|
+
// The worktree metadata may be left stale in `git worktree list`
|
|
378
|
+
// because we couldn't run `worktree remove`. Surface so RCA can
|
|
379
|
+
// explain why a path was deleted but `git worktree list` still
|
|
380
|
+
// references it.
|
|
381
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
382
|
+
recordActivityEvent({
|
|
383
|
+
source: "workspace",
|
|
384
|
+
kind: "workspace.destroy_fell_back",
|
|
385
|
+
level: "warn",
|
|
386
|
+
summary: "destroy fell back to rmSync; git worktree metadata may be stale",
|
|
387
|
+
data: {
|
|
388
|
+
plugin: "workspace-worktree",
|
|
389
|
+
workspacePath,
|
|
390
|
+
errorMessage,
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
// On Windows, retry with backoff for the file-handle drain race
|
|
394
|
+
// (just-killed pty-host children still hold handles inside the worktree).
|
|
395
|
+
if (existsSync(workspacePath)) {
|
|
396
|
+
await removeDirWithRetry(workspacePath);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
async list(projectId) {
|
|
401
|
+
assertSafePathSegment(projectId, "projectId");
|
|
402
|
+
const projectWorktreeDir = join(worktreeBaseDir, projectId);
|
|
403
|
+
if (!existsSync(projectWorktreeDir))
|
|
404
|
+
return [];
|
|
405
|
+
const entries = readdirSync(projectWorktreeDir, { withFileTypes: true });
|
|
406
|
+
const dirs = entries
|
|
407
|
+
.filter((e) => e.isDirectory())
|
|
408
|
+
.map((e) => join(projectWorktreeDir, e.name));
|
|
409
|
+
if (dirs.length === 0)
|
|
410
|
+
return [];
|
|
411
|
+
// Use first valid worktree to get the list
|
|
412
|
+
let worktreeListOutput = "";
|
|
413
|
+
for (const dir of dirs) {
|
|
414
|
+
try {
|
|
415
|
+
worktreeListOutput = await git(dir, "worktree", "list", "--porcelain");
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
if (!worktreeListOutput)
|
|
423
|
+
return [];
|
|
424
|
+
// Parse porcelain output — only include worktrees within our project directory
|
|
425
|
+
const infos = [];
|
|
426
|
+
const blocks = worktreeListOutput.split("\n\n");
|
|
427
|
+
const projectDirCmp = toComparablePath(projectWorktreeDir);
|
|
428
|
+
for (const block of blocks) {
|
|
429
|
+
const lines = block.trim().split("\n");
|
|
430
|
+
let path = "";
|
|
431
|
+
let branch = "";
|
|
432
|
+
for (const line of lines) {
|
|
433
|
+
if (line.startsWith("worktree ")) {
|
|
434
|
+
path = line.slice("worktree ".length);
|
|
435
|
+
}
|
|
436
|
+
else if (line.startsWith("branch ")) {
|
|
437
|
+
// branch refs/heads/feat/INT-1234 → feat/INT-1234
|
|
438
|
+
branch = line.slice("branch ".length).replace("refs/heads/", "");
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const pathCmp = path ? toComparablePath(path) : "";
|
|
442
|
+
if (path && (pathCmp === projectDirCmp || pathCmp.startsWith(projectDirCmp + "/"))) {
|
|
443
|
+
const sessionId = basename(path);
|
|
444
|
+
infos.push({
|
|
445
|
+
path,
|
|
446
|
+
branch: branch || "detached",
|
|
447
|
+
sessionId,
|
|
448
|
+
projectId,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return infos;
|
|
453
|
+
},
|
|
454
|
+
async exists(workspacePath) {
|
|
455
|
+
if (!existsSync(workspacePath))
|
|
456
|
+
return false;
|
|
457
|
+
try {
|
|
458
|
+
await execFileAsync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
459
|
+
cwd: workspacePath,
|
|
460
|
+
timeout: GIT_TIMEOUT,
|
|
461
|
+
windowsHide: true,
|
|
462
|
+
});
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
async restore(cfg, workspacePath) {
|
|
470
|
+
const repoPath = expandPath(cfg.project.path);
|
|
471
|
+
// Prune stale worktree entries
|
|
472
|
+
try {
|
|
473
|
+
await git(repoPath, "worktree", "prune");
|
|
474
|
+
}
|
|
475
|
+
catch {
|
|
476
|
+
// Best effort
|
|
477
|
+
}
|
|
478
|
+
// Fetch latest
|
|
479
|
+
const hasOrigin = await hasOriginRemote(repoPath);
|
|
480
|
+
if (hasOrigin) {
|
|
481
|
+
try {
|
|
482
|
+
await git(repoPath, "fetch", "origin", "--quiet");
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
// May fail if offline
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
// Try to create worktree on the existing branch.
|
|
489
|
+
try {
|
|
490
|
+
await git(repoPath, "worktree", "add", workspacePath, cfg.branch);
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
if (await refExists(repoPath, `refs/heads/${cfg.branch}`)) {
|
|
494
|
+
await reattachExistingBranch(repoPath, workspacePath, cfg.branch);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
await createBranchFromBase(repoPath, workspacePath, cfg.branch, cfg.project.defaultBranch, hasOrigin);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return {
|
|
501
|
+
path: workspacePath,
|
|
502
|
+
branch: cfg.branch,
|
|
503
|
+
sessionId: cfg.sessionId,
|
|
504
|
+
projectId: cfg.projectId,
|
|
505
|
+
};
|
|
506
|
+
},
|
|
507
|
+
async postCreate(info, project) {
|
|
508
|
+
const repoPath = expandPath(project.path);
|
|
509
|
+
// Symlink shared resources
|
|
510
|
+
if (project.symlinks) {
|
|
511
|
+
for (const symlinkPath of project.symlinks) {
|
|
512
|
+
// Guard against absolute paths (Unix: leading "/", Windows: drive letter "C:\"
|
|
513
|
+
// or UNC "\\server\share") and directory traversal
|
|
514
|
+
if (symlinkPath.startsWith("/") ||
|
|
515
|
+
symlinkPath.includes("..") ||
|
|
516
|
+
/^[a-zA-Z]:[\\/]/.test(symlinkPath) ||
|
|
517
|
+
symlinkPath.startsWith("\\\\")) {
|
|
518
|
+
throw new Error(`Invalid symlink path "${symlinkPath}": must be a relative path without ".." segments`);
|
|
519
|
+
}
|
|
520
|
+
const sourcePath = join(repoPath, symlinkPath);
|
|
521
|
+
const targetPath = resolve(info.path, symlinkPath);
|
|
522
|
+
const normalizedBase = resolve(info.path);
|
|
523
|
+
// Verify resolved target is still within the workspace
|
|
524
|
+
if (!targetPath.startsWith(normalizedBase + sep) && targetPath !== normalizedBase) {
|
|
525
|
+
throw new Error(`Symlink target "${symlinkPath}" resolves outside workspace: ${targetPath}`);
|
|
526
|
+
}
|
|
527
|
+
if (!existsSync(sourcePath))
|
|
528
|
+
continue;
|
|
529
|
+
// Remove existing target if it exists
|
|
530
|
+
try {
|
|
531
|
+
const stat = lstatSync(targetPath);
|
|
532
|
+
if (stat.isSymbolicLink() || stat.isFile() || stat.isDirectory()) {
|
|
533
|
+
rmSync(targetPath, { recursive: true, force: true });
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
// Target doesn't exist — that's fine
|
|
538
|
+
}
|
|
539
|
+
// Ensure parent directory exists for nested symlink targets
|
|
540
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
541
|
+
try {
|
|
542
|
+
symlinkSync(sourcePath, targetPath);
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
if (isWindows()) {
|
|
546
|
+
// Symlinks need admin/Developer Mode on Windows. Try unprivileged
|
|
547
|
+
// alternatives first — junctions for dirs, hardlinks for files —
|
|
548
|
+
// before falling back to a recursive copy (slow + bloats every
|
|
549
|
+
// worktree, especially for node_modules).
|
|
550
|
+
const isDir = (() => {
|
|
551
|
+
try {
|
|
552
|
+
return statSync(sourcePath).isDirectory();
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
})();
|
|
558
|
+
try {
|
|
559
|
+
if (isDir) {
|
|
560
|
+
symlinkSync(sourcePath, targetPath, "junction");
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
linkSync(sourcePath, targetPath);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
catch {
|
|
567
|
+
fs.cpSync(sourcePath, targetPath, { recursive: true });
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
throw err;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// Run postCreate hooks
|
|
577
|
+
// NOTE: commands run with full shell privileges — they come from trusted YAML config
|
|
578
|
+
if (project.postCreate) {
|
|
579
|
+
const shell = getShell();
|
|
580
|
+
for (const command of project.postCreate) {
|
|
581
|
+
try {
|
|
582
|
+
await execFileAsync(shell.cmd, shell.args(command), {
|
|
583
|
+
cwd: info.path,
|
|
584
|
+
windowsHide: true,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
catch (err) {
|
|
588
|
+
// Surface which postCreate command failed. Lifecycle records
|
|
589
|
+
// a generic spawn_failed but loses the specific command and
|
|
590
|
+
// its sanitized error output.
|
|
591
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
592
|
+
recordActivityEvent({
|
|
593
|
+
projectId: info.projectId,
|
|
594
|
+
sessionId: info.sessionId,
|
|
595
|
+
source: "workspace",
|
|
596
|
+
kind: "workspace.post_create_failed",
|
|
597
|
+
level: "error",
|
|
598
|
+
summary: `postCreate command failed for session ${info.sessionId}`,
|
|
599
|
+
data: {
|
|
600
|
+
plugin: "workspace-worktree",
|
|
601
|
+
command,
|
|
602
|
+
errorMessage,
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
throw err;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
export default { manifest, create };
|
|
613
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|