@prestyj/cli 5.20.0 → 5.21.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.
@@ -0,0 +1,574 @@
1
+ import { execFile } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { getGitDirtyFileCount } from "../utils/git.js";
7
+ const exec = promisify(execFile);
8
+ const GIT_TIMEOUT_MS = 10_000;
9
+ const MAX_COLLISION_ATTEMPTS = 20;
10
+ /**
11
+ * `readOnly` plumbing sets GIT_OPTIONAL_LOCKS=0 so a query never takes the
12
+ * index lock and fights a concurrent git. The env is read per call, not
13
+ * captured at module load, so a later process.env change is honoured.
14
+ */
15
+ async function git(cwd, args, readOnly = true) {
16
+ const { stdout } = await exec("git", args, {
17
+ cwd,
18
+ timeout: GIT_TIMEOUT_MS,
19
+ maxBuffer: 8 * 1024 * 1024,
20
+ env: readOnly ? { ...process.env, GIT_OPTIONAL_LOCKS: "0" } : process.env,
21
+ });
22
+ return String(stdout);
23
+ }
24
+ /** Same as `git`, but a non-zero exit resolves to null instead of throwing. */
25
+ async function gitOrNull(cwd, args) {
26
+ try {
27
+ return await git(cwd, args);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ async function realpathOrSelf(p) {
34
+ try {
35
+ return await fs.realpath(p);
36
+ }
37
+ catch {
38
+ return p;
39
+ }
40
+ }
41
+ /**
42
+ * Walk up from `startDir` to the nearest `.git`. A `.git` directory means the
43
+ * main worktree; a `.git` *file* (`gitdir: <path>`) means an already-linked
44
+ * worktree. Returns null when no repository encloses `startDir`.
45
+ */
46
+ export async function gitLayout(startDir) {
47
+ let dir = path.resolve(startDir);
48
+ for (;;) {
49
+ const dotGit = path.join(dir, ".git");
50
+ let stat;
51
+ try {
52
+ stat = await fs.stat(dotGit);
53
+ }
54
+ catch {
55
+ stat = null;
56
+ }
57
+ if (stat?.isDirectory()) {
58
+ return { worktreeRoot: dir, gitDir: dotGit, isMain: true };
59
+ }
60
+ if (stat?.isFile()) {
61
+ const contents = await fs.readFile(dotGit, "utf-8");
62
+ const match = /^gitdir:\s*(.+)$/m.exec(contents);
63
+ const target = match?.[1]?.trim();
64
+ if (target) {
65
+ const resolved = path.isAbsolute(target) ? target : path.resolve(dir, target);
66
+ return { worktreeRoot: dir, gitDir: path.normalize(resolved), isMain: false };
67
+ }
68
+ }
69
+ const parent = path.dirname(dir);
70
+ if (parent === dir)
71
+ return null;
72
+ dir = parent;
73
+ }
74
+ }
75
+ /** The enclosing repo's root, but only when `startDir` is inside the MAIN worktree. */
76
+ export async function findMainWorktreeRoot(startDir) {
77
+ const layout = await gitLayout(startDir);
78
+ return layout?.isMain ? layout.worktreeRoot : null;
79
+ }
80
+ /**
81
+ * Parse `git worktree list --porcelain`. The first block is always the main
82
+ * worktree. Paths are canonicalised so callers can compare them by string
83
+ * equality (/var vs /private/var aliasing on macOS).
84
+ */
85
+ export async function listWorktrees(repoDir) {
86
+ const stdout = await git(repoDir, ["worktree", "list", "--porcelain"]);
87
+ const entries = [];
88
+ let current = null;
89
+ for (const rawLine of stdout.split(/\r?\n/)) {
90
+ const line = rawLine.trim();
91
+ if (!line) {
92
+ if (current)
93
+ entries.push(current);
94
+ current = null;
95
+ continue;
96
+ }
97
+ if (line.startsWith("worktree ")) {
98
+ if (current)
99
+ entries.push(current);
100
+ current = {
101
+ path: line.slice("worktree ".length).trim(),
102
+ branch: null,
103
+ head: null,
104
+ isBare: false,
105
+ isMain: entries.length === 0,
106
+ };
107
+ continue;
108
+ }
109
+ if (!current)
110
+ continue;
111
+ if (line.startsWith("HEAD "))
112
+ current.head = line.slice("HEAD ".length).trim();
113
+ else if (line.startsWith("branch "))
114
+ current.branch = line
115
+ .slice("branch ".length)
116
+ .trim()
117
+ .replace(/^refs\/heads\//, "");
118
+ else if (line === "bare")
119
+ current.isBare = true;
120
+ }
121
+ if (current)
122
+ entries.push(current);
123
+ for (const entry of entries)
124
+ entry.path = await realpathOrSelf(entry.path);
125
+ return entries;
126
+ }
127
+ /** True when `git status --porcelain` reports anything (tracked or untracked). */
128
+ export async function isWorkingTreeDirty(dir) {
129
+ return (await getGitDirtyFileCount(dir)) > 0;
130
+ }
131
+ /**
132
+ * Normalise arbitrary text into a branch name git will accept. Returns "" when
133
+ * nothing usable survives, so callers can fall back to a generated name.
134
+ */
135
+ export function slugifyBranch(input) {
136
+ const slug = input
137
+ .toLowerCase()
138
+ .replace(/[\s_]+/g, "-")
139
+ .replace(/[^a-z0-9._/-]+/g, "")
140
+ .replace(/-{2,}/g, "-")
141
+ .replace(/^[-./]+/, "")
142
+ .replace(/[-./]+$/, "");
143
+ if (!slug)
144
+ return "";
145
+ if (slug.includes(".."))
146
+ return "";
147
+ if (slug.endsWith(".lock") || slug.split("/").some((part) => part.endsWith(".lock")))
148
+ return "";
149
+ if (slug.startsWith("-"))
150
+ return "";
151
+ return slug;
152
+ }
153
+ /** Pure: `<home>/.ezcoder/worktrees/<basename(repoRoot)>`. */
154
+ export function worktreesRootFor(repoRoot, homeDir = os.homedir()) {
155
+ return path.join(homeDir, ".ezcoder", "worktrees", path.basename(path.resolve(repoRoot)));
156
+ }
157
+ /**
158
+ * Name of the file, inside a linked worktree's own git dir, recording the ref it
159
+ * was forked from.
160
+ *
161
+ * Reclaim has to answer "does this branch hold commits nobody else has", and
162
+ * that question is only meaningful against the ref the worktree ACTUALLY forked
163
+ * from. Comparing against whatever `main` points at today gets it wrong in both
164
+ * directions: main moving ahead makes an untouched worktree look behind, and a
165
+ * worktree forked from a feature branch looks full of "new" commits that its
166
+ * base already contains. Git does not record the fork point anywhere durable
167
+ * (reflogs expire, and a rebased base breaks merge-base), so it is written at
168
+ * creation time and read back verbatim.
169
+ */
170
+ const BASE_REF_FILE = "ezcoder-base";
171
+ async function pathExists(p) {
172
+ try {
173
+ await fs.lstat(p);
174
+ return true;
175
+ }
176
+ catch {
177
+ return false;
178
+ }
179
+ }
180
+ async function branchExists(repoDir, branch) {
181
+ const sha = await gitOrNull(repoDir, [
182
+ "rev-parse",
183
+ "--verify",
184
+ "--quiet",
185
+ `refs/heads/${branch}`,
186
+ ]);
187
+ return Boolean(sha?.trim());
188
+ }
189
+ /** Resolve the MAIN worktree root for any directory inside a repo (linked or not). */
190
+ async function resolveMainRoot(repoDir) {
191
+ const layout = await gitLayout(repoDir);
192
+ if (!layout)
193
+ throw new Error(`Not a git repository: ${repoDir}`);
194
+ if (layout.isMain)
195
+ return layout.worktreeRoot;
196
+ // Linked worktree: the common dir is the main checkout's .git, whose parent
197
+ // is the main worktree root.
198
+ const commonDir = (await gitOrNull(repoDir, ["rev-parse", "--git-common-dir"]))?.trim();
199
+ const resolved = commonDir
200
+ ? path.resolve(repoDir, commonDir)
201
+ : // .git/worktrees/<name> → .git
202
+ path.dirname(path.dirname(layout.gitDir));
203
+ return path.dirname(resolved);
204
+ }
205
+ /**
206
+ * Create a linked worktree on a fresh branch under `worktreesRootFor(mainRoot)`.
207
+ * Refuses to run against a dirty main checkout unless `allowDirty` is set — a
208
+ * half-committed main tree is the fastest way to lose work across worktrees.
209
+ */
210
+ export async function createWorktree(opts) {
211
+ const mainRoot = await resolveMainRoot(opts.repoDir);
212
+ let baseRef = opts.baseRef?.trim();
213
+ if (!baseRef) {
214
+ const head = (await gitOrNull(mainRoot, ["rev-parse", "--abbrev-ref", "HEAD"]))?.trim();
215
+ if (!head)
216
+ throw new Error(`Cannot determine HEAD of ${mainRoot} (no commits yet?)`);
217
+ baseRef =
218
+ head === "HEAD" ? ((await gitOrNull(mainRoot, ["rev-parse", "HEAD"]))?.trim() ?? head) : head;
219
+ }
220
+ if (!opts.allowDirty && (await isWorkingTreeDirty(mainRoot))) {
221
+ throw new Error(`The main checkout at ${mainRoot} has uncommitted changes; no worktree was created. ` +
222
+ `Commit or stash them first, or pass allowDirty to create the worktree anyway.`);
223
+ }
224
+ const requested = opts.branch ? slugifyBranch(opts.branch) : "";
225
+ const base = requested || `ez/${Date.now().toString(36)}`;
226
+ const worktreesRoot = worktreesRootFor(mainRoot);
227
+ await fs.mkdir(worktreesRoot, { recursive: true });
228
+ for (let attempt = 1; attempt <= MAX_COLLISION_ATTEMPTS; attempt++) {
229
+ const branch = attempt === 1 ? base : `${base}-${attempt}`;
230
+ const targetPath = path.join(worktreesRoot, branch.replace(/\//g, "-"));
231
+ if ((await branchExists(mainRoot, branch)) || (await pathExists(targetPath)))
232
+ continue;
233
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
234
+ await git(mainRoot, ["worktree", "add", "-b", branch, targetPath, baseRef], false);
235
+ await writeBaseRef(targetPath, baseRef);
236
+ return { path: await realpathOrSelf(targetPath), branch, baseRef, created: true };
237
+ }
238
+ throw new Error(`Could not find a free worktree branch name for "${base}" after ${MAX_COLLISION_ATTEMPTS} attempts.`);
239
+ }
240
+ /**
241
+ * Record the fork point inside the new worktree's own git dir (not its working
242
+ * tree): the working tree belongs to the user and an agent, and a stray file
243
+ * there would show up as an untracked change, which would in turn make the
244
+ * worktree permanently "dirty" and therefore never reclaimable.
245
+ *
246
+ * Best effort. A worktree with no base file still reclaims — `readBaseRef`
247
+ * falls back — so a write failure must not fail the creation that succeeded.
248
+ */
249
+ async function writeBaseRef(worktreePath, baseRef) {
250
+ try {
251
+ const layout = await gitLayout(worktreePath);
252
+ if (!layout)
253
+ return;
254
+ await fs.writeFile(path.join(layout.gitDir, BASE_REF_FILE), `${baseRef}\n`, "utf-8");
255
+ }
256
+ catch {
257
+ // Non-fatal: see doc comment.
258
+ }
259
+ }
260
+ /**
261
+ * The ref this worktree forked from, or null when unrecorded (a worktree made
262
+ * before this file existed, or by hand with plain git).
263
+ */
264
+ async function readBaseRef(worktreePath) {
265
+ try {
266
+ const layout = await gitLayout(worktreePath);
267
+ if (!layout)
268
+ return null;
269
+ const raw = await fs.readFile(path.join(layout.gitDir, BASE_REF_FILE), "utf-8");
270
+ return raw.trim() || null;
271
+ }
272
+ catch {
273
+ return null;
274
+ }
275
+ }
276
+ /**
277
+ * Pure: is `candidate` inside `root`?
278
+ *
279
+ * `path.relative` rather than `startsWith`: the string form says yes to
280
+ * `/a/worktrees-evil` for root `/a/worktrees`, and on Windows says no to a
281
+ * correct path that differs only in separator or drive-letter case. An empty
282
+ * relative path (candidate IS root) is deliberately NOT contained — removing
283
+ * the container itself is never what a caller means.
284
+ */
285
+ export function isInsideWorktreesRoot(root, candidate) {
286
+ const rel = path.relative(path.resolve(root), path.resolve(candidate));
287
+ if (!rel)
288
+ return false;
289
+ if (rel.startsWith(".."))
290
+ return false;
291
+ return !path.isAbsolute(rel);
292
+ }
293
+ /**
294
+ * The first symlink at or above `dir` (stopping at the filesystem root), or
295
+ * null when the whole chain is real directories.
296
+ *
297
+ * A containment check alone cannot see this: `stat` dereferences every path
298
+ * component, so a symlink at `~/.ezcoder/worktrees` makes every path under it
299
+ * look like an ordinary contained directory while the removal lands in whatever
300
+ * checkout it points at — the user's real repo, most likely. `lstat` sees the
301
+ * link itself. Every destructive path routes through here.
302
+ */
303
+ export async function redirectedAncestor(dir) {
304
+ let current = path.resolve(dir);
305
+ for (;;) {
306
+ try {
307
+ if ((await fs.lstat(current)).isSymbolicLink())
308
+ return current;
309
+ }
310
+ catch {
311
+ // Missing components cannot redirect anything.
312
+ }
313
+ const parent = path.dirname(current);
314
+ if (parent === current)
315
+ return null;
316
+ current = parent;
317
+ }
318
+ }
319
+ /** Count commits on `branch` absent from `baseRef`; null when git cannot say. */
320
+ async function commitsAhead(dir, baseRef, branch) {
321
+ // `--` guards a ref whose name could otherwise be read as a path.
322
+ const out = await gitOrNull(dir, ["rev-list", "--count", `${baseRef}..${branch}`, "--"]);
323
+ if (out === null)
324
+ return null;
325
+ const n = Number.parseInt(out.trim(), 10);
326
+ return Number.isFinite(n) ? n : null;
327
+ }
328
+ /**
329
+ * Describe one worktree well enough to decide its fate, from the worktree's own
330
+ * directory so a stale main-checkout view cannot mislead.
331
+ *
332
+ * Unknowns always count AGAINST reclaiming: a git call that fails leaves the
333
+ * entry blocked rather than deleted. The cost of a wrong "keep" is a stale
334
+ * folder; the cost of a wrong "delete" is lost work.
335
+ */
336
+ export async function worktreeStatus(mainRoot, entry, busyPaths = []) {
337
+ const blockedBy = [];
338
+ const busySet = new Set(await Promise.all(busyPaths.map((p) => realpathOrSelf(p))));
339
+ const busy = busySet.has(await realpathOrSelf(entry.path));
340
+ if (busy)
341
+ blockedBy.push("it is open in another window");
342
+ // -1 marks "could not read", which blocks just as a dirty tree does: an
343
+ // unreadable status is never evidence that a copy is empty.
344
+ const dirtyFiles = await getGitDirtyFileCount(entry.path).catch(() => -1);
345
+ if (dirtyFiles > 0)
346
+ blockedBy.push(`it has ${dirtyFiles} uncommitted file(s)`);
347
+ else if (dirtyFiles < 0)
348
+ blockedBy.push("its status could not be read");
349
+ const baseRef = (await readBaseRef(entry.path)) ?? (await defaultBaseRef(mainRoot));
350
+ let ahead = null;
351
+ if (baseRef && entry.branch) {
352
+ ahead = await commitsAhead(entry.path, baseRef, entry.branch);
353
+ if (ahead === null)
354
+ blockedBy.push("its commits could not be compared to the base branch");
355
+ else if (ahead > 0)
356
+ blockedBy.push(`it has ${ahead} unmerged commit(s)`);
357
+ }
358
+ else {
359
+ blockedBy.push("its base branch is unknown");
360
+ }
361
+ if (!isInsideWorktreesRoot(worktreesRootFor(mainRoot), entry.path)) {
362
+ blockedBy.push("it lives outside the managed copies folder");
363
+ }
364
+ if (entry.isMain)
365
+ blockedBy.push("it is the main checkout");
366
+ return {
367
+ path: entry.path,
368
+ branch: entry.branch,
369
+ baseRef,
370
+ dirtyFiles: Math.max(dirtyFiles, 0),
371
+ commitsAhead: ahead ?? 0,
372
+ merged: ahead === 0,
373
+ busy,
374
+ reclaimable: blockedBy.length === 0,
375
+ blockedBy,
376
+ };
377
+ }
378
+ /** The main checkout's current branch, used when no fork point was recorded. */
379
+ async function defaultBaseRef(mainRoot) {
380
+ const head = (await gitOrNull(mainRoot, ["rev-parse", "--abbrev-ref", "HEAD"]))?.trim();
381
+ return head && head !== "HEAD" ? head : null;
382
+ }
383
+ /** Status for every linked worktree of `repoDir`'s repo, main checkout excluded. */
384
+ export async function worktreeStatuses(repoDir, busyPaths = []) {
385
+ const mainRoot = await resolveMainRoot(repoDir);
386
+ const entries = await listWorktrees(mainRoot);
387
+ return await Promise.all(entries.filter((e) => !e.isMain).map((e) => worktreeStatus(mainRoot, e, busyPaths)));
388
+ }
389
+ /** Worktrees that can be removed right now with nothing lost. */
390
+ export async function reclaimableWorktrees(repoDir, busyPaths = []) {
391
+ return (await worktreeStatuses(repoDir, busyPaths)).filter((s) => s.reclaimable);
392
+ }
393
+ /**
394
+ * Free a worktree's path AND its branch. Never throws: cleanup runs on window
395
+ * close and on daemon startup, where an exception would surface as a crash in
396
+ * an unrelated flow. Everything it could not do comes back in the result.
397
+ *
398
+ * The order below is load-bearing and `prune` is not optional. `worktree
399
+ * remove` needs the directory to be there; a user reclaiming disk with
400
+ * `rm -rf ~/.ezcoder/worktrees` leaves the tree REGISTERED BUT MISSING, and git
401
+ * then refuses both of the things the next run needs:
402
+ *
403
+ * $ git worktree add <path> <branch>
404
+ * fatal: '<path>' is a missing but already registered worktree;
405
+ * use 'add -f' to override, or 'prune' or 'remove' to clear
406
+ *
407
+ * and `git branch -d <branch>`, because the branch counts as checked out in
408
+ * that phantom. `git worktree prune` is the only thing that clears the
409
+ * registration, and it is a no-op when nothing is stale — so it runs
410
+ * unconditionally, and BEFORE the branch delete that depends on it.
411
+ */
412
+ export async function removeWorktree(opts) {
413
+ let mainRoot;
414
+ try {
415
+ mainRoot = await resolveMainRoot(opts.repoDir);
416
+ }
417
+ catch (err) {
418
+ return { existed: false, freed: false, branchDeleted: false, reason: messageOf(err) };
419
+ }
420
+ const target = path.resolve(opts.worktreePath);
421
+ const root = worktreesRootFor(mainRoot);
422
+ // Containment BEFORE anything destructive. The path arrives over HTTP from
423
+ // the app; a request naming a path is not authorization to delete it.
424
+ if (!isInsideWorktreesRoot(root, target)) {
425
+ return {
426
+ existed: true,
427
+ freed: false,
428
+ branchDeleted: false,
429
+ reason: `refusing to remove ${target}: it is outside ${root}`,
430
+ };
431
+ }
432
+ // A symlink ANYWHERE above the target redirects both the git remove and the
433
+ // rm fallback into whatever it points at, while the containment check above
434
+ // still reads as contained. `dirname`, because a link AT the target is
435
+ // unlinked below rather than followed.
436
+ try {
437
+ const redirected = await redirectedAncestor(path.dirname(target));
438
+ if (redirected !== null) {
439
+ return {
440
+ existed: true,
441
+ freed: false,
442
+ branchDeleted: false,
443
+ reason: `refusing to remove through a symlink: ${redirected} is a link, so the removal would land wherever it points`,
444
+ };
445
+ }
446
+ }
447
+ catch (err) {
448
+ return { existed: true, freed: false, branchDeleted: false, reason: messageOf(err) };
449
+ }
450
+ const existed = await pathExists(target);
451
+ // Read the branch BEFORE the removal: afterwards the registration is gone and
452
+ // there is nothing left to ask.
453
+ const registeredBranch = await branchAtPath(mainRoot, target);
454
+ const branch = opts.deleteBranch === false ? null : registeredBranch;
455
+ const isRegistered = registeredBranch !== null;
456
+ let removeError;
457
+ if (existed) {
458
+ // `--force` only when the caller actually asked for it. Without it git
459
+ // refuses to remove a worktree holding uncommitted work, which is a second
460
+ // safety net under the `reclaimable` check the sweep already did.
461
+ const args = opts.force
462
+ ? ["worktree", "remove", "--force", target]
463
+ : ["worktree", "remove", target];
464
+ try {
465
+ await git(mainRoot, args, false);
466
+ }
467
+ catch (err) {
468
+ removeError = err;
469
+ // Fall back to a direct delete ONLY when nothing would be lost by it:
470
+ // either the caller forced, or the path is not a registered worktree at
471
+ // all (a leftover directory git has already forgotten). A non-forced
472
+ // refusal over a REGISTERED tree is git protecting real work, and
473
+ // deleting it here would turn that protection into data loss.
474
+ if (opts.force || !isRegistered) {
475
+ try {
476
+ await fs.rm(target, { recursive: true, force: true });
477
+ removeError = undefined;
478
+ }
479
+ catch (rmErr) {
480
+ removeError = rmErr;
481
+ }
482
+ }
483
+ }
484
+ }
485
+ // Always, even when nothing existed: this is what clears a registration whose
486
+ // directory someone deleted by hand, and it must precede the branch delete.
487
+ const pruned = (await gitOrNull(mainRoot, ["worktree", "prune"])) !== null;
488
+ const stillThere = await pathExists(target);
489
+ if (existed && stillThere) {
490
+ return {
491
+ existed,
492
+ freed: false,
493
+ branchDeleted: false,
494
+ reason: removeError
495
+ ? messageOf(removeError)
496
+ : "the path is still there after `git worktree remove --force` and a direct delete",
497
+ };
498
+ }
499
+ if (!pruned) {
500
+ return {
501
+ existed,
502
+ freed: false,
503
+ branchDeleted: false,
504
+ reason: "`git worktree prune` could not run, so the registration and the branch survive; " +
505
+ "the next copy over this path would fail with \u201cmissing but already registered\u201d",
506
+ };
507
+ }
508
+ let branchDeleted = false;
509
+ if (branch) {
510
+ // -D rather than -d when forcing: an unmerged branch whose removal the user
511
+ // confirmed must not survive as a dangling ref.
512
+ const flag = opts.force ? "-D" : "-d";
513
+ branchDeleted = (await gitOrNull(mainRoot, ["branch", flag, "--", branch])) !== null;
514
+ }
515
+ return { existed, freed: true, branchDeleted };
516
+ }
517
+ function messageOf(err) {
518
+ return err instanceof Error ? err.message : String(err);
519
+ }
520
+ /** The branch checked out at `target`, read from the worktree itself. */
521
+ async function branchAtPath(mainRoot, target) {
522
+ const entries = await listWorktrees(mainRoot).catch(() => []);
523
+ for (const entry of entries) {
524
+ if ((await realpathOrSelf(entry.path)) === (await realpathOrSelf(target)))
525
+ return entry.branch;
526
+ }
527
+ return null;
528
+ }
529
+ /**
530
+ * Remove every worktree of `repoDir`'s repo that is provably free of work.
531
+ *
532
+ * The automatic entry point: window close and daemon startup. It never forces,
533
+ * so anything holding uncommitted or unmerged work is reported as kept, with
534
+ * the reason, and waits for a human. Failures are collected rather than thrown
535
+ * — one wedged worktree must not stop the rest of the sweep.
536
+ */
537
+ export async function sweepWorktrees(repoDir, busyPaths = []) {
538
+ const result = { removed: [], kept: [] };
539
+ let statuses;
540
+ try {
541
+ statuses = await worktreeStatuses(repoDir, busyPaths);
542
+ }
543
+ catch {
544
+ return result;
545
+ }
546
+ for (const status of statuses) {
547
+ if (!status.reclaimable) {
548
+ result.kept.push({ status, reason: status.blockedBy.join("; ") });
549
+ continue;
550
+ }
551
+ const release = await removeWorktree({
552
+ repoDir,
553
+ worktreePath: status.path,
554
+ force: false,
555
+ deleteBranch: true,
556
+ });
557
+ if (release.freed)
558
+ result.removed.push(status);
559
+ else
560
+ result.kept.push({ status, reason: release.reason ?? "it could not be removed" });
561
+ }
562
+ return result;
563
+ }
564
+ /** True when the repo already has at least one linked worktree registered. */
565
+ export async function repoHasLinkedWorktrees(mainRoot) {
566
+ try {
567
+ const entries = await fs.readdir(path.join(mainRoot, ".git", "worktrees"));
568
+ return entries.some((name) => !name.startsWith("."));
569
+ }
570
+ catch {
571
+ return false;
572
+ }
573
+ }
574
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../src/core/worktree.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ export declare function isModelUnavailableError(stderr: string): boolean;
8
8
  declare const SubAgentParams: z.ZodObject<{
9
9
  task: z.ZodString;
10
10
  agent: z.ZodOptional<z.ZodString>;
11
+ isolate: z.ZodOptional<z.ZodBoolean>;
11
12
  }, z.core.$strip>;
12
13
  export interface SubAgentUpdate {
13
14
  toolUseCount: number;