@clipboard-health/groundcrew 4.47.0 → 4.47.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.
@@ -58,6 +58,13 @@ export type WorktreeDirtiness = {
58
58
  } | {
59
59
  kind: "unknown";
60
60
  };
61
+ export declare function isRecoverableRemovalError(error: unknown): boolean;
62
+ export interface ForceRemoveDirectoryOptions {
63
+ attempts?: number;
64
+ delayMs?: number;
65
+ remove?: (target: string) => void;
66
+ }
67
+ export declare function forceRemoveDirectory(targetDir: string, options?: ForceRemoveDirectoryOptions): Promise<void>;
61
68
  declare function list(config: ResolvedConfig): WorktreeEntry[];
62
69
  declare function findByTask(config: ResolvedConfig, task: string): WorktreeEntry[];
63
70
  export interface PredictedWorktreeEntry {
@@ -1 +1 @@
1
- {"version":3,"file":"worktrees.d.ts","sourceRoot":"","sources":["../../src/lib/worktrees.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worktrees.d.ts","sourceRoot":"","sources":["../../src/lib/worktrees.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@
11
11
  import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
12
12
  import { userInfo } from "node:os";
13
13
  import path from "node:path";
14
+ import { setTimeout as sleep } from "node:timers/promises";
14
15
  import { applySubstitutions } from "./adapters/shell/invoke.js";
15
16
  import { runCommandAsync } from "./commandRunner.js";
16
17
  import { repositoryBaseDir, worktreeBaseDir, } from "./config.js";
@@ -384,7 +385,7 @@ async function removeWorktree(config, entry, options) {
384
385
  if (registration !== "orphan") {
385
386
  throw error;
386
387
  }
387
- removeOrphanWorktreeDirectory(config, entry);
388
+ await removeOrphanWorktreeDirectory(config, entry);
388
389
  }
389
390
  else {
390
391
  const dirtiness = await throwIfWorktreeDirty(entry, options.signal, error);
@@ -533,7 +534,46 @@ function isInsideDirectory(parentDir, childDir) {
533
534
  !childRelativePath.startsWith("..") &&
534
535
  !path.isAbsolute(childRelativePath));
535
536
  }
536
- function removeOrphanWorktreeDirectory(config, entry) {
537
+ // APFS reports ENOTEMPTY (and occasionally EBUSY/EPERM) from a recursive rmdir
538
+ // when directory-entry caches lag behind the unlinks that just emptied it. This
539
+ // bites large trees like node_modules, where `rmSync` bails partway through even
540
+ // though a plain `rm -rf` succeeds. Retrying the removal lets the caches settle
541
+ // and drains the remaining entries.
542
+ const RECOVERABLE_REMOVAL_ERROR_CODES = new Set([
543
+ "ENOTEMPTY",
544
+ "EBUSY",
545
+ "EPERM",
546
+ "EMFILE",
547
+ "ENFILE",
548
+ ]);
549
+ export function isRecoverableRemovalError(error) {
550
+ return (error instanceof Error &&
551
+ "code" in error &&
552
+ typeof error.code === "string" &&
553
+ RECOVERABLE_REMOVAL_ERROR_CODES.has(error.code));
554
+ }
555
+ export async function forceRemoveDirectory(targetDir, options = {}) {
556
+ const attempts = options.attempts ?? 8;
557
+ const delayMs = options.delayMs ?? 100;
558
+ const removeDirectory = options.remove ??
559
+ ((target) => {
560
+ rmSync(target, { recursive: true, force: true });
561
+ });
562
+ for (let attempt = 1;; attempt += 1) {
563
+ try {
564
+ removeDirectory(targetDir);
565
+ return;
566
+ }
567
+ catch (error) {
568
+ if (attempt >= attempts || !isRecoverableRemovalError(error)) {
569
+ throw error;
570
+ }
571
+ // oxlint-disable-next-line no-await-in-loop -- retries are intentionally serial with a settle delay between attempts.
572
+ await sleep(delayMs);
573
+ }
574
+ }
575
+ }
576
+ async function removeOrphanWorktreeDirectory(config, entry) {
537
577
  const worktreeRoot = path.resolve(worktreeBaseDir(config));
538
578
  const expectedDir = expectedHostWorktreeDir(config, entry);
539
579
  const targetDir = path.resolve(entry.dir);
@@ -541,7 +581,7 @@ function removeOrphanWorktreeDirectory(config, entry) {
541
581
  throw new Error(`Refusing to force-delete ${entry.dir}: expected groundcrew worktree path ${expectedDir}.`);
542
582
  }
543
583
  debug(`Removing orphaned worktree directory ${entry.dir} (--force)...`);
544
- rmSync(targetDir, { recursive: true, force: true });
584
+ await forceRemoveDirectory(targetDir);
545
585
  }
546
586
  function list(config) {
547
587
  return listWorktrees(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clipboard-health/groundcrew",
3
- "version": "4.47.0",
3
+ "version": "4.47.1",
4
4
  "description": "Linear-driven orchestrator that launches AI coding agents in git worktrees, with workspace lifecycle and usage tracking.",
5
5
  "keywords": [
6
6
  "agent",
@@ -84,7 +84,7 @@
84
84
  "@nx/js": "22.7.6",
85
85
  "@tsconfig/node24": "24.0.4",
86
86
  "@tsconfig/strictest": "2.0.8",
87
- "@types/node": "25.9.4",
87
+ "@types/node": "25.9.5",
88
88
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
89
89
  "@vitest/coverage-v8": "4.1.9",
90
90
  "cspell": "10.0.1",