@cleocode/worktree 2026.5.124 → 2026.5.126
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/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/napi-binding.d.ts +64 -9
- package/dist/napi-binding.d.ts.map +1 -1
- package/dist/napi-binding.js +114 -11
- package/dist/napi-binding.js.map +1 -1
- package/dist/worktree-create.d.ts.map +1 -1
- package/dist/worktree-create.js +66 -2
- package/dist/worktree-create.js.map +1 -1
- package/dist/worktree-destroy.d.ts.map +1 -1
- package/dist/worktree-destroy.js +17 -0
- package/dist/worktree-destroy.js.map +1 -1
- package/dist/worktree-include.d.ts +17 -22
- package/dist/worktree-include.d.ts.map +1 -1
- package/dist/worktree-include.js +67 -33
- package/dist/worktree-include.js.map +1 -1
- package/dist/worktree-migrate.d.ts +68 -0
- package/dist/worktree-migrate.d.ts.map +1 -0
- package/dist/worktree-migrate.js +146 -0
- package/dist/worktree-migrate.js.map +1 -0
- package/dist/worktree-pnpm.d.ts +34 -0
- package/dist/worktree-pnpm.d.ts.map +1 -0
- package/dist/worktree-pnpm.js +127 -0
- package/dist/worktree-pnpm.js.map +1 -0
- package/dist/worktree-prune.d.ts.map +1 -1
- package/dist/worktree-prune.js +28 -6
- package/dist/worktree-prune.js.map +1 -1
- package/native/worktree-napi.cjs +57 -0
- package/native/worktree-napi.darwin-arm64.node +0 -0
- package/native/worktree-napi.linux-arm64-gnu.node +0 -0
- package/native/worktree-napi.linux-x64-gnu.node +0 -0
- package/native/worktree-napi.win32-x64-msvc.node +0 -0
- package/package.json +6 -14
package/dist/worktree-include.js
CHANGED
|
@@ -123,60 +123,96 @@ function readPatternsFromLegacyShim(legacyPath) {
|
|
|
123
123
|
return readPatternsViaNapi(shimDir);
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
|
-
* Apply include patterns to a newly created worktree by
|
|
127
|
-
* from the
|
|
126
|
+
* Apply include patterns to a newly created worktree by copying files
|
|
127
|
+
* from the project root using @cleocode/worktree-napi's parallel reflink-aware
|
|
128
|
+
* copy primitive.
|
|
128
129
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
130
|
+
* Each non-negated pattern is copied from `<projectRoot>/<pattern>` to
|
|
131
|
+
* `<worktreePath>/<pattern>`. Negated patterns are excluded.
|
|
131
132
|
*
|
|
132
|
-
*
|
|
133
|
+
* Unlike the prior symlink-based implementation (removed in T10077), this
|
|
134
|
+
* produces full file copies so worktree isolation is preserved — modifying
|
|
135
|
+
* a file in one worktree does not affect any other worktree.
|
|
133
136
|
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
137
|
+
* The NAPI binding uses 4-thread rayon parallelism with reflink probing
|
|
138
|
+
* (APFS clonefile on macOS, btrfs/xfs/zfs reflink on Linux, regular copy
|
|
139
|
+
* fallback on other FS).
|
|
136
140
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* the parent is created with `mkdirSync({ recursive: true })` before the
|
|
140
|
-
* `symlinkSync` call. This prevents the `ENOENT` error reported in T9807.
|
|
141
|
-
*
|
|
142
|
-
* The pattern-evaluation strategy stays in TS for now because each pattern
|
|
143
|
-
* needs an existence check against the project tree + a per-pattern symlink —
|
|
144
|
-
* a thin wrapper that defers to the napi matcher would not measurably improve
|
|
145
|
-
* the hot path here (pattern lists are short and the work is dominated by
|
|
146
|
-
* filesystem syscalls, not regex matching).
|
|
141
|
+
* Already-existing paths in the worktree are left untouched by the NAPI
|
|
142
|
+
* layer (the `force` option defaults to `false`).
|
|
147
143
|
*
|
|
148
144
|
* @param patterns - Parsed include patterns from {@link loadWorktreeIncludePatterns}.
|
|
149
|
-
* @param projectRoot - Absolute path to the project root (
|
|
150
|
-
* @param worktreePath - Absolute path to the worktree directory.
|
|
151
|
-
* @returns Array of patterns that were successfully
|
|
145
|
+
* @param projectRoot - Absolute path to the project root (source base).
|
|
146
|
+
* @param worktreePath - Absolute path to the worktree directory (target base).
|
|
147
|
+
* @returns Array of patterns that were successfully copied.
|
|
152
148
|
*
|
|
153
|
-
* @task
|
|
154
|
-
* @task T9807
|
|
149
|
+
* @task T10077
|
|
155
150
|
*/
|
|
156
151
|
export function applyIncludePatterns(patterns, projectRoot, worktreePath) {
|
|
152
|
+
// Filter to non-negated patterns only.
|
|
153
|
+
const nonNegated = patterns.filter((p) => !p.negated);
|
|
154
|
+
if (nonNegated.length === 0)
|
|
155
|
+
return [];
|
|
156
|
+
// Map TS types to the NAPI IncludePatternNapi shape.
|
|
157
|
+
const napiPatterns = nonNegated.map((p) => ({
|
|
158
|
+
pattern: p.pattern,
|
|
159
|
+
isNegation: false,
|
|
160
|
+
}));
|
|
161
|
+
const opts = {
|
|
162
|
+
force: false,
|
|
163
|
+
rootGuard: worktreePath,
|
|
164
|
+
includeSymlinks: true,
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
const { applyInclude } = require('./napi-binding.js');
|
|
168
|
+
const result = applyInclude(napiPatterns, projectRoot, worktreePath, opts);
|
|
169
|
+
// Build the applied list — patterns that succeeded (not in failedPaths).
|
|
170
|
+
const failedSet = new Set(result.failedPaths);
|
|
171
|
+
const applied = nonNegated.filter((p) => !failedSet.has(p.pattern));
|
|
172
|
+
if (failedSet.size > 0) {
|
|
173
|
+
process.stderr.write(`[worktree] include-pattern copy failed for: ${[...failedSet].join(', ')}\\n`);
|
|
174
|
+
}
|
|
175
|
+
return applied.map((p) => ({
|
|
176
|
+
pattern: p.pattern,
|
|
177
|
+
negated: false,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
// NAPI not available (test environment, missing binary, etc.) —
|
|
182
|
+
// fall back to symlink for backward compatibility.
|
|
183
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
184
|
+
process.stderr.write(`[worktree] napi.applyInclude unavailable, falling back to symlinks: ${message}\\n`);
|
|
185
|
+
return applyIncludePatternsLegacy(patterns, projectRoot, worktreePath);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Legacy symlink-based include pattern application.
|
|
190
|
+
*
|
|
191
|
+
* Used as a fallback when the NAPI binding is not available (test
|
|
192
|
+
* environments, platforms without a prebuilt binary, etc.).
|
|
193
|
+
*
|
|
194
|
+
* This is the OLD implementation that was replaced in T10077. It is kept
|
|
195
|
+
* as a fallback for environments where the NAPI binary cannot be loaded.
|
|
196
|
+
*
|
|
197
|
+
* @internal
|
|
198
|
+
*/
|
|
199
|
+
function applyIncludePatternsLegacy(patterns, projectRoot, worktreePath) {
|
|
157
200
|
const applied = [];
|
|
158
201
|
for (const entry of patterns) {
|
|
159
|
-
// Negated patterns are exclusions — no filesystem action needed.
|
|
160
202
|
if (entry.negated)
|
|
161
203
|
continue;
|
|
162
204
|
const sourcePath = resolve(projectRoot, entry.pattern);
|
|
163
205
|
const targetPath = resolve(worktreePath, entry.pattern);
|
|
164
|
-
// Skip if the source does not exist in the project tree.
|
|
165
206
|
if (!existsSync(sourcePath))
|
|
166
207
|
continue;
|
|
167
|
-
// Skip if a file/dir/symlink already exists at this path in the worktree.
|
|
168
208
|
if (existsSync(targetPath))
|
|
169
209
|
continue;
|
|
170
|
-
// T9807 — ensure the parent directory exists in the worktree before calling
|
|
171
|
-
// symlinkSync. Patterns like `.vscode/settings.json` require `.vscode/` to
|
|
172
|
-
// exist first; without this step, symlinkSync throws ENOENT for every spawn
|
|
173
|
-
// on machines where the parent directory was never checked in.
|
|
174
210
|
const parentDir = dirname(targetPath);
|
|
175
211
|
try {
|
|
176
212
|
mkdirSync(parentDir, { recursive: true });
|
|
177
213
|
}
|
|
178
214
|
catch {
|
|
179
|
-
process.stderr.write(`[worktree] include-pattern parent-dir creation failed: ${entry.pattern}
|
|
215
|
+
process.stderr.write(`[worktree] include-pattern parent-dir creation failed: ${entry.pattern}\\n`);
|
|
180
216
|
continue;
|
|
181
217
|
}
|
|
182
218
|
try {
|
|
@@ -184,9 +220,7 @@ export function applyIncludePatterns(patterns, projectRoot, worktreePath) {
|
|
|
184
220
|
applied.push(entry);
|
|
185
221
|
}
|
|
186
222
|
catch {
|
|
187
|
-
|
|
188
|
-
// which patterns succeeded.
|
|
189
|
-
process.stderr.write(`[worktree] include-pattern symlink failed: ${entry.pattern}\n`);
|
|
223
|
+
process.stderr.write(`[worktree] include-pattern symlink failed: ${entry.pattern}\\n`);
|
|
190
224
|
}
|
|
191
225
|
}
|
|
192
226
|
return applied;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree-include.js","sourceRoot":"","sources":["../src/worktree-include.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"worktree-include.js","sourceRoot":"","sources":["../src/worktree-include.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree identity migration for `@cleocode/worktree`.
|
|
3
|
+
*
|
|
4
|
+
* Backfills `project-info.json` into existing worktrees that were created
|
|
5
|
+
* before the identity system (T11033) was deployed. New worktrees get
|
|
6
|
+
* project-info.json at provision time; this module handles the legacy ones.
|
|
7
|
+
*
|
|
8
|
+
* @task T11036
|
|
9
|
+
* @epic T10299
|
|
10
|
+
* @saga T10295
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Result of a single worktree identity migration.
|
|
14
|
+
*/
|
|
15
|
+
export interface MigrateWorktreeResult {
|
|
16
|
+
/** Absolute path to the worktree that was checked. */
|
|
17
|
+
worktreePath: string;
|
|
18
|
+
/** Whether the migration actually backfilled (created) project-info.json. */
|
|
19
|
+
backfilled: boolean;
|
|
20
|
+
/** The projectId from the parent project's project-info.json, if present. */
|
|
21
|
+
projectId?: string;
|
|
22
|
+
/** The projectHash from the parent project's project-info.json, if present. */
|
|
23
|
+
projectHash?: string;
|
|
24
|
+
/** The resolved parent project root, if successfully discovered. */
|
|
25
|
+
parentProjectRoot?: string;
|
|
26
|
+
/** Human-readable error reason when migration could not proceed. */
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Discover the parent project root from a git worktree's `.git` gitlink file.
|
|
31
|
+
*
|
|
32
|
+
* Git worktrees use a `.git` FILE (not directory) containing a gitdir reference:
|
|
33
|
+
* `gitdir: /path/to/main/.git/worktrees/<name>`
|
|
34
|
+
*
|
|
35
|
+
* From this we derive: `<gitdir>/../..` → main repo root.
|
|
36
|
+
*
|
|
37
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
38
|
+
* @returns The resolved main repo root, or null if it cannot be determined.
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
export declare function discoverParentProjectRoot(worktreePath: string): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Backfill `project-info.json` into a worktree that lacks it.
|
|
44
|
+
*
|
|
45
|
+
* Discovers the parent project root via the worktree's `.git` gitlink, reads
|
|
46
|
+
* the parent's `.cleo/project-info.json`, and copies it into the worktree's
|
|
47
|
+
* `.cleo/` directory. Idempotent: if project-info.json already exists, the
|
|
48
|
+
* worktree is skipped with `backfilled: false`.
|
|
49
|
+
*
|
|
50
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
51
|
+
* @returns Migration result with backfill status and identity fields.
|
|
52
|
+
*
|
|
53
|
+
* @task T11036
|
|
54
|
+
*/
|
|
55
|
+
export declare function migrateWorktreeIdentity(worktreePath: string): MigrateWorktreeResult;
|
|
56
|
+
/**
|
|
57
|
+
* Migrate ALL existing worktrees for a given project root.
|
|
58
|
+
*
|
|
59
|
+
* Enumerates worktrees via the XDG directory scan, then backfills
|
|
60
|
+
* project-info.json into each worktree that lacks it.
|
|
61
|
+
*
|
|
62
|
+
* @param projectRoot - Absolute path to the project root.
|
|
63
|
+
* @returns Array of migration results, one per worktree.
|
|
64
|
+
*
|
|
65
|
+
* @task T11036
|
|
66
|
+
*/
|
|
67
|
+
export declare function migrateAllWorktreeIdentities(projectRoot: string): MigrateWorktreeResult[];
|
|
68
|
+
//# sourceMappingURL=worktree-migrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-migrate.d.ts","sourceRoot":"","sources":["../src/worktree-migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,UAAU,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwB7E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,qBAAqB,CAyEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,EAAE,CAGzF"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree identity migration for `@cleocode/worktree`.
|
|
3
|
+
*
|
|
4
|
+
* Backfills `project-info.json` into existing worktrees that were created
|
|
5
|
+
* before the identity system (T11033) was deployed. New worktrees get
|
|
6
|
+
* project-info.json at provision time; this module handles the legacy ones.
|
|
7
|
+
*
|
|
8
|
+
* @task T11036
|
|
9
|
+
* @epic T10299
|
|
10
|
+
* @saga T10295
|
|
11
|
+
*/
|
|
12
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { join, resolve } from 'node:path';
|
|
14
|
+
import { listWorktreesByProjectRoot } from './worktree-list.js';
|
|
15
|
+
/**
|
|
16
|
+
* Discover the parent project root from a git worktree's `.git` gitlink file.
|
|
17
|
+
*
|
|
18
|
+
* Git worktrees use a `.git` FILE (not directory) containing a gitdir reference:
|
|
19
|
+
* `gitdir: /path/to/main/.git/worktrees/<name>`
|
|
20
|
+
*
|
|
21
|
+
* From this we derive: `<gitdir>/../..` → main repo root.
|
|
22
|
+
*
|
|
23
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
24
|
+
* @returns The resolved main repo root, or null if it cannot be determined.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export function discoverParentProjectRoot(worktreePath) {
|
|
28
|
+
const gitFile = join(worktreePath, '.git');
|
|
29
|
+
// Not a worktree (or `.git` is a directory — linked checkout, not a worktree).
|
|
30
|
+
if (!existsSync(gitFile))
|
|
31
|
+
return null;
|
|
32
|
+
let content;
|
|
33
|
+
try {
|
|
34
|
+
content = readFileSync(gitFile, 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
// Parse the gitdir line from the gitlink.
|
|
40
|
+
const match = content.match(/^gitdir:\s*(.+)$/m);
|
|
41
|
+
if (!match)
|
|
42
|
+
return null;
|
|
43
|
+
// gitDir is something like: /path/to/main/.git/worktrees/<name>
|
|
44
|
+
// Resolve relative to the worktree path for portability.
|
|
45
|
+
const gitDir = resolve(worktreePath, match[1].trim());
|
|
46
|
+
// Main repo root = resolve(gitDir, '../../..') — go up from
|
|
47
|
+
// worktrees/<name> → .git → repo root (3 levels).
|
|
48
|
+
return resolve(gitDir, '../../..');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Backfill `project-info.json` into a worktree that lacks it.
|
|
52
|
+
*
|
|
53
|
+
* Discovers the parent project root via the worktree's `.git` gitlink, reads
|
|
54
|
+
* the parent's `.cleo/project-info.json`, and copies it into the worktree's
|
|
55
|
+
* `.cleo/` directory. Idempotent: if project-info.json already exists, the
|
|
56
|
+
* worktree is skipped with `backfilled: false`.
|
|
57
|
+
*
|
|
58
|
+
* @param worktreePath - Absolute path to the worktree directory.
|
|
59
|
+
* @returns Migration result with backfill status and identity fields.
|
|
60
|
+
*
|
|
61
|
+
* @task T11036
|
|
62
|
+
*/
|
|
63
|
+
export function migrateWorktreeIdentity(worktreePath) {
|
|
64
|
+
const worktreeCleoDir = join(worktreePath, '.cleo');
|
|
65
|
+
const worktreeInfoPath = join(worktreeCleoDir, 'project-info.json');
|
|
66
|
+
// ── Idempotency: skip if already present ──────────────────────────
|
|
67
|
+
if (existsSync(worktreeInfoPath)) {
|
|
68
|
+
try {
|
|
69
|
+
const existing = JSON.parse(readFileSync(worktreeInfoPath, 'utf-8'));
|
|
70
|
+
return {
|
|
71
|
+
worktreePath,
|
|
72
|
+
backfilled: false,
|
|
73
|
+
projectId: typeof existing.projectId === 'string' ? existing.projectId : undefined,
|
|
74
|
+
projectHash: typeof existing.projectHash === 'string' ? existing.projectHash : undefined,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Corrupt project-info.json — treat as missing and backfill.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// ── Discover parent project root ──────────────────────────────────
|
|
82
|
+
const parentProjectRoot = discoverParentProjectRoot(worktreePath);
|
|
83
|
+
if (!parentProjectRoot) {
|
|
84
|
+
return {
|
|
85
|
+
worktreePath,
|
|
86
|
+
backfilled: false,
|
|
87
|
+
error: 'Cannot determine parent project root — worktree has no .git gitlink',
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// ── Read parent project-info.json ─────────────────────────────────
|
|
91
|
+
const parentInfoPath = join(parentProjectRoot, '.cleo', 'project-info.json');
|
|
92
|
+
if (!existsSync(parentInfoPath)) {
|
|
93
|
+
return {
|
|
94
|
+
worktreePath,
|
|
95
|
+
backfilled: false,
|
|
96
|
+
error: `Parent project at ${parentProjectRoot} has no .cleo/project-info.json`,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
let parentInfo;
|
|
100
|
+
try {
|
|
101
|
+
parentInfo = JSON.parse(readFileSync(parentInfoPath, 'utf-8'));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return {
|
|
105
|
+
worktreePath,
|
|
106
|
+
backfilled: false,
|
|
107
|
+
error: `Cannot parse parent project-info.json at ${parentInfoPath}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// ── Backfill ──────────────────────────────────────────────────────
|
|
111
|
+
try {
|
|
112
|
+
mkdirSync(worktreeCleoDir, { recursive: true });
|
|
113
|
+
copyFileSync(parentInfoPath, worktreeInfoPath);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
117
|
+
return {
|
|
118
|
+
worktreePath,
|
|
119
|
+
backfilled: false,
|
|
120
|
+
error: `Failed to copy project-info.json: ${message}`,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
worktreePath,
|
|
125
|
+
backfilled: true,
|
|
126
|
+
projectId: typeof parentInfo.projectId === 'string' ? parentInfo.projectId : undefined,
|
|
127
|
+
projectHash: typeof parentInfo.projectHash === 'string' ? parentInfo.projectHash : undefined,
|
|
128
|
+
parentProjectRoot,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Migrate ALL existing worktrees for a given project root.
|
|
133
|
+
*
|
|
134
|
+
* Enumerates worktrees via the XDG directory scan, then backfills
|
|
135
|
+
* project-info.json into each worktree that lacks it.
|
|
136
|
+
*
|
|
137
|
+
* @param projectRoot - Absolute path to the project root.
|
|
138
|
+
* @returns Array of migration results, one per worktree.
|
|
139
|
+
*
|
|
140
|
+
* @task T11036
|
|
141
|
+
*/
|
|
142
|
+
export function migrateAllWorktreeIdentities(projectRoot) {
|
|
143
|
+
const worktrees = listWorktreesByProjectRoot(projectRoot);
|
|
144
|
+
return worktrees.map((wt) => migrateWorktreeIdentity(wt.path));
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=worktree-migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-migrate.js","sourceRoot":"","sources":["../src/worktree-migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialized pnpm install for worktree provisioning.
|
|
3
|
+
*
|
|
4
|
+
* When multiple worktrees are provisioned concurrently and pnpm-lock.yaml
|
|
5
|
+
* is included via .worktreeinclude, each worktree needs its own node_modules
|
|
6
|
+
* installed. Without serialization, concurrent pnpm installs race on the
|
|
7
|
+
* shared global content-addressable store and corrupt .pnpm/ with doubled
|
|
8
|
+
* @@-prefixed directories (T9938).
|
|
9
|
+
*
|
|
10
|
+
* This module provides a file-based mutex that ensures only one worktree
|
|
11
|
+
* runs pnpm install at a time during provisioning.
|
|
12
|
+
*
|
|
13
|
+
* @task T9938
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Run pnpm install in a worktree with serialization via file-based mutex.
|
|
17
|
+
*
|
|
18
|
+
* Only one worktree's pnpm install runs at a time across the entire project.
|
|
19
|
+
* This prevents the @@-prefixed doubled-directory corruption in .pnpm/
|
|
20
|
+
* caused by concurrent pnpm operations on the shared content-addressable store.
|
|
21
|
+
*
|
|
22
|
+
* After install, a `.pnpm-store/` directory is created in the worktree root
|
|
23
|
+
* and configured via `.npmrc` to isolate the worktree's pnpm store from the
|
|
24
|
+
* project root's global store. This prevents future races when the agent
|
|
25
|
+
* runs additional pnpm operations.
|
|
26
|
+
*
|
|
27
|
+
* @param worktreePath - Absolute path to the worktree.
|
|
28
|
+
* @param projectRoot - Absolute path to the project root (for lock file).
|
|
29
|
+
* @returns true if install succeeded, false otherwise.
|
|
30
|
+
*
|
|
31
|
+
* @task T9938
|
|
32
|
+
*/
|
|
33
|
+
export declare function installWorktreeDependencies(worktreePath: string, projectRoot: string): boolean;
|
|
34
|
+
//# sourceMappingURL=worktree-pnpm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-pnpm.d.ts","sourceRoot":"","sources":["../src/worktree-pnpm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA4DH;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CA2C9F"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialized pnpm install for worktree provisioning.
|
|
3
|
+
*
|
|
4
|
+
* When multiple worktrees are provisioned concurrently and pnpm-lock.yaml
|
|
5
|
+
* is included via .worktreeinclude, each worktree needs its own node_modules
|
|
6
|
+
* installed. Without serialization, concurrent pnpm installs race on the
|
|
7
|
+
* shared global content-addressable store and corrupt .pnpm/ with doubled
|
|
8
|
+
* @@-prefixed directories (T9938).
|
|
9
|
+
*
|
|
10
|
+
* This module provides a file-based mutex that ensures only one worktree
|
|
11
|
+
* runs pnpm install at a time during provisioning.
|
|
12
|
+
*
|
|
13
|
+
* @task T9938
|
|
14
|
+
*/
|
|
15
|
+
import { execFileSync } from 'node:child_process';
|
|
16
|
+
import { closeSync, existsSync, mkdirSync, openSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
const PNPM_INSTALL_TIMEOUT_MS = 120_000;
|
|
19
|
+
const LOCK_RETRY_INTERVAL_MS = 500;
|
|
20
|
+
const LOCK_MAX_WAIT_MS = 300_000; // 5 min max wait
|
|
21
|
+
/**
|
|
22
|
+
* Acquire a file-based mutex lock for serialized pnpm operations.
|
|
23
|
+
*
|
|
24
|
+
* Creates an exclusive lock file at `<projectRoot>/.cleo/pnpm-install.lock`.
|
|
25
|
+
* Uses O_CREAT|O_EXCL for atomic creation — no race window between check
|
|
26
|
+
* and create. Retries with backoff until the lock is acquired or timeout.
|
|
27
|
+
*
|
|
28
|
+
* Returns a release function that removes the lock file.
|
|
29
|
+
*
|
|
30
|
+
* @param projectRoot - Absolute path to the project root.
|
|
31
|
+
* @returns A function to call to release the lock.
|
|
32
|
+
*/
|
|
33
|
+
function acquirePnpmLock(projectRoot) {
|
|
34
|
+
const lockDir = join(projectRoot, '.cleo');
|
|
35
|
+
mkdirSync(lockDir, { recursive: true });
|
|
36
|
+
const lockPath = join(lockDir, 'pnpm-install.lock');
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
while (true) {
|
|
39
|
+
try {
|
|
40
|
+
// O_CREAT|O_EXCL — fail if file already exists (atomic)
|
|
41
|
+
const fd = openSync(lockPath, 'wx');
|
|
42
|
+
closeSync(fd);
|
|
43
|
+
return () => {
|
|
44
|
+
try {
|
|
45
|
+
unlinkSync(lockPath);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Best-effort cleanup — lock file may already be gone.
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Lock exists — another process has it.
|
|
54
|
+
const elapsed = Date.now() - startTime;
|
|
55
|
+
if (elapsed >= LOCK_MAX_WAIT_MS) {
|
|
56
|
+
throw new Error(`pnpm-install lock timeout after ${LOCK_MAX_WAIT_MS}ms — ` +
|
|
57
|
+
`stale lock at ${lockPath}? Remove it manually if no pnpm process is running.`);
|
|
58
|
+
}
|
|
59
|
+
// Busy-wait with small interval — the lock holder should finish quickly.
|
|
60
|
+
const waitUntil = Date.now() + LOCK_RETRY_INTERVAL_MS;
|
|
61
|
+
while (Date.now() < waitUntil) {
|
|
62
|
+
// Spin-wait — sub-ms precision is fine for short intervals.
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Run pnpm install in a worktree with serialization via file-based mutex.
|
|
69
|
+
*
|
|
70
|
+
* Only one worktree's pnpm install runs at a time across the entire project.
|
|
71
|
+
* This prevents the @@-prefixed doubled-directory corruption in .pnpm/
|
|
72
|
+
* caused by concurrent pnpm operations on the shared content-addressable store.
|
|
73
|
+
*
|
|
74
|
+
* After install, a `.pnpm-store/` directory is created in the worktree root
|
|
75
|
+
* and configured via `.npmrc` to isolate the worktree's pnpm store from the
|
|
76
|
+
* project root's global store. This prevents future races when the agent
|
|
77
|
+
* runs additional pnpm operations.
|
|
78
|
+
*
|
|
79
|
+
* @param worktreePath - Absolute path to the worktree.
|
|
80
|
+
* @param projectRoot - Absolute path to the project root (for lock file).
|
|
81
|
+
* @returns true if install succeeded, false otherwise.
|
|
82
|
+
*
|
|
83
|
+
* @task T9938
|
|
84
|
+
*/
|
|
85
|
+
export function installWorktreeDependencies(worktreePath, projectRoot) {
|
|
86
|
+
const pnpmLockPath = join(worktreePath, 'pnpm-lock.yaml');
|
|
87
|
+
if (!existsSync(pnpmLockPath)) {
|
|
88
|
+
// No lockfile — nothing to install.
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// Don't re-install if node_modules already exists (idempotent).
|
|
92
|
+
if (existsSync(join(worktreePath, 'node_modules'))) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
let releaseLock = null;
|
|
96
|
+
try {
|
|
97
|
+
releaseLock = acquirePnpmLock(projectRoot);
|
|
98
|
+
// Configure per-worktree pnpm store to isolate from global store.
|
|
99
|
+
// This prevents future races when agents run pnpm operations.
|
|
100
|
+
const npmrcPath = join(worktreePath, '.npmrc');
|
|
101
|
+
const storeDir = join(worktreePath, '.pnpm-store');
|
|
102
|
+
try {
|
|
103
|
+
writeFileSync(npmrcPath, `store-dir=${storeDir}\n`, 'utf-8');
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Best-effort — pnpm install still works with global store.
|
|
107
|
+
}
|
|
108
|
+
execFileSync('pnpm', ['install', '--frozen-lockfile', '--prefer-offline'], {
|
|
109
|
+
cwd: worktreePath,
|
|
110
|
+
encoding: 'utf-8',
|
|
111
|
+
timeout: PNPM_INSTALL_TIMEOUT_MS,
|
|
112
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
113
|
+
});
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
118
|
+
process.stderr.write(`[worktree] pnpm install failed for ${worktreePath}: ${message}\n`);
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
if (releaseLock) {
|
|
123
|
+
releaseLock();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=worktree-pnpm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-pnpm.js","sourceRoot":"","sources":["../src/worktree-pnpm.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree-prune.d.ts","sourceRoot":"","sources":["../src/worktree-prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,
|
|
1
|
+
{"version":3,"file":"worktree-prune.d.ts","sourceRoot":"","sources":["../src/worktree-prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAEvF,OAAO,EAEL,cAAc,IAAI,SAAS,EAE5B,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAiBnF;AAiMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,iBAAiB,EAAE,MAAM,GACxB,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,IAAI,CAMrC"}
|
package/dist/worktree-prune.js
CHANGED
|
@@ -27,7 +27,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
27
27
|
import { existsSync, readdirSync } from 'node:fs';
|
|
28
28
|
import { join } from 'node:path';
|
|
29
29
|
import { getGitRoot, gitSilent } from './git.js';
|
|
30
|
-
import { pruneWorktrees as napiPrune, removeDir as napiRemoveDir } from './napi-binding.js';
|
|
30
|
+
import { destroyWorktree as napiDestroyWorktree, pruneWorktrees as napiPrune, removeDir as napiRemoveDir, } from './napi-binding.js';
|
|
31
31
|
import { computeProjectHash, resolveWorktreeRootForHash } from './paths.js';
|
|
32
32
|
import { appendWorktreeAuditLog, removeWorktreeFromSentinelIndex } from './worktree-audit.js';
|
|
33
33
|
/**
|
|
@@ -145,20 +145,42 @@ function classifyPruneCandidate(entry, preserveTaskIds, idleDays, worktreeRoot)
|
|
|
145
145
|
*/
|
|
146
146
|
function pruneSingleEntry(decision, gitRoot, projectRoot, removed, errors) {
|
|
147
147
|
const { taskId, path, reason } = decision;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
// T11123: Use NAPI destroyWorktree (Rust worktrunk-core) instead of raw
|
|
149
|
+
// git worktree unlock + remove shell-outs. The NAPI binding handles
|
|
150
|
+
// unlock + force-remove atomically in Rust.
|
|
151
|
+
let pruneSuccess = false;
|
|
151
152
|
let errorMessage = null;
|
|
152
|
-
|
|
153
|
+
try {
|
|
154
|
+
const result = napiDestroyWorktree({
|
|
155
|
+
repoRoot: gitRoot,
|
|
156
|
+
worktreePath: path,
|
|
157
|
+
force: true,
|
|
158
|
+
});
|
|
159
|
+
pruneSuccess = result.removed;
|
|
160
|
+
// T11033 — NAPI may report success even when untracked directories
|
|
161
|
+
// survive inside the worktree. Verify on-disk reality.
|
|
162
|
+
if (pruneSuccess && existsSync(path)) {
|
|
163
|
+
pruneSuccess = false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
errorMessage = err instanceof Error ? err.message : String(err);
|
|
168
|
+
}
|
|
169
|
+
if (!pruneSuccess) {
|
|
153
170
|
try {
|
|
154
171
|
// Delegate the recursive directory removal to worktrunk-core via napi
|
|
155
172
|
// (T10203). The SDK is best-effort: read/unlink/rmdir errors are
|
|
156
173
|
// silently skipped, so a non-zero file count signals success.
|
|
157
174
|
napiRemoveDir({ path });
|
|
158
175
|
pruneSuccess = true;
|
|
176
|
+
// Also run git worktree prune to clean stale admin entries
|
|
177
|
+
// left behind by the failed NAPI destroy.
|
|
178
|
+
gitSilent(['worktree', 'prune'], gitRoot);
|
|
159
179
|
}
|
|
160
180
|
catch (err) {
|
|
161
|
-
|
|
181
|
+
if (!errorMessage) {
|
|
182
|
+
errorMessage = err instanceof Error ? err.message : String(err);
|
|
183
|
+
}
|
|
162
184
|
}
|
|
163
185
|
}
|
|
164
186
|
if (pruneSuccess) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree-prune.js","sourceRoot":"","sources":["../src/worktree-prune.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"worktree-prune.js","sourceRoot":"","sources":["../src/worktree-prune.ts"],"names":[],"mappings":"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"}
|