@agentproto/worktree 0.10.0 → 0.13.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.
@@ -1,12 +1,13 @@
1
- import { provisionWorktreeTool, cleanupWorktreeTool, runGateTool, runScriptTool, startServiceTool, stopServiceTool, listServicesTool } from './chunk-IKCBL2UN.mjs';
1
+ import { provisionWorktreeTool, cleanupWorktreeTool, runGateTool, runScriptTool, startServiceTool, stopServiceTool, listServicesTool } from './chunk-3FZWPMLF.mjs';
2
2
  import { implementTool, defineDriver } from '@agentproto/driver';
3
3
  import { randomUUID } from 'crypto';
4
- import { lstat, mkdir, symlink, appendFile, writeFile, copyFile, readdir, stat, readFile } from 'fs/promises';
5
- import { resolve, join, dirname, posix, basename, sep } from 'path';
4
+ import { lstat, mkdir, symlink, appendFile, writeFile, copyFile, readFile, rename, readdir, stat } from 'fs/promises';
5
+ import { resolve, join, dirname, basename, posix, sep } from 'path';
6
6
  import { ToolError } from '@agentproto/tool';
7
7
  import { spawn } from 'child_process';
8
8
  import { z } from 'zod';
9
9
  import { homedir } from 'os';
10
+ import { existsSync, mkdirSync, realpathSync, readdirSync } from 'fs';
10
11
  import { createServer } from 'net';
11
12
 
12
13
  /**
@@ -105,6 +106,53 @@ async function expandGlob(root, pattern) {
105
106
  const candidates = await walk(root, base);
106
107
  return candidates.filter((rel) => regex.test(rel));
107
108
  }
109
+ var GlobTraversalError = class extends Error {
110
+ constructor(pattern) {
111
+ super(`glob pattern '${pattern}' escapes the repo root (path traversal)`);
112
+ this.name = "GlobTraversalError";
113
+ }
114
+ };
115
+ function assertNoTraversal(pattern) {
116
+ if (pattern.startsWith("/")) throw new GlobTraversalError(pattern);
117
+ if (pattern.split("/").some((seg) => seg === "..")) throw new GlobTraversalError(pattern);
118
+ }
119
+ async function expandCloneGlob(root, pattern) {
120
+ assertNoTraversal(pattern);
121
+ const segments = pattern.split("/").filter((seg) => seg.length > 0);
122
+ if (segments.length === 0) return [];
123
+ if (segments.includes("**")) {
124
+ throw new Error(
125
+ `cloneGlobs pattern '${pattern}' uses '**', which is not supported \u2014 name each path segment explicitly so a directory match clones as one unit.`
126
+ );
127
+ }
128
+ async function walkMatch(dirRel, idx) {
129
+ const seg = segments[idx];
130
+ const isLast = idx === segments.length - 1;
131
+ const abs = dirRel ? join(root, dirRel) : root;
132
+ let entries;
133
+ try {
134
+ entries = await readdir(abs, { withFileTypes: true });
135
+ } catch {
136
+ return [];
137
+ }
138
+ const regex = new RegExp(`^${escapeSegment(seg)}$`);
139
+ const out = [];
140
+ for (const entry of entries) {
141
+ if (entry.name === ".git") continue;
142
+ if (!regex.test(entry.name)) continue;
143
+ const rel = dirRel ? posix.join(dirRel, entry.name) : entry.name;
144
+ if (isLast) {
145
+ out.push(rel);
146
+ continue;
147
+ }
148
+ if (entry.isDirectory()) {
149
+ out.push(...await walkMatch(rel, idx + 1));
150
+ }
151
+ }
152
+ return out;
153
+ }
154
+ return walkMatch("", 0);
155
+ }
108
156
  var CONFIG_FILENAME = "agentproto.json";
109
157
  var hookSchema = z.union([z.string(), z.array(z.string())]);
110
158
  var scriptSchema = z.object({
@@ -181,6 +229,86 @@ async function loadConfigFromBase(repoRoot, base = "origin/main") {
181
229
  }
182
230
  return parseConfig(result.stdout);
183
231
  }
232
+ var LOCAL_WORKTREE_CONFIG_REL = ".agentproto/worktree.json";
233
+ var localWriteFileEntrySchema = z.object({
234
+ path: z.string().min(1, "writeFiles[].path must be non-empty"),
235
+ content: z.string(),
236
+ mode: z.enum(["create", "append"]).optional()
237
+ });
238
+ var localWorktreeConfigSchema = z.object({
239
+ copyGlobs: z.array(z.string()).optional(),
240
+ /** Gitignored dirs/files cloned (copy-on-write where the filesystem
241
+ * supports it) from the source checkout into the worktree before
242
+ * `depsCmd` runs — see `clone.ts`. */
243
+ cloneGlobs: z.array(z.string()).optional(),
244
+ writeFiles: z.array(localWriteFileEntrySchema).optional(),
245
+ depsCmd: z.string().optional(),
246
+ linkPaths: z.array(z.string()).optional()
247
+ });
248
+ function parseLocalWorktreeConfig(raw) {
249
+ let json;
250
+ try {
251
+ json = JSON.parse(raw);
252
+ } catch (err) {
253
+ throw new ConfigError(
254
+ `${LOCAL_WORKTREE_CONFIG_REL} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`
255
+ );
256
+ }
257
+ const result = localWorktreeConfigSchema.safeParse(json);
258
+ if (!result.success) {
259
+ const issues = result.error.issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ");
260
+ throw new ConfigError(`${LOCAL_WORKTREE_CONFIG_REL} failed validation: ${issues}`);
261
+ }
262
+ return result.data;
263
+ }
264
+ async function loadLocalWorktreeConfig(workspace) {
265
+ const path = resolve(workspace, LOCAL_WORKTREE_CONFIG_REL);
266
+ let raw;
267
+ try {
268
+ raw = await readFile(path, "utf8");
269
+ } catch (err) {
270
+ if (err.code === "ENOENT") return null;
271
+ throw err;
272
+ }
273
+ return parseLocalWorktreeConfig(raw);
274
+ }
275
+ var SLUG_PLACEHOLDER = /\{slug\}/g;
276
+ function applySlugPlaceholder(text, slug) {
277
+ return text.replace(SLUG_PLACEHOLDER, slug);
278
+ }
279
+ function resolveLocalWriteFiles(files, slug) {
280
+ return (files ?? []).map((file) => ({
281
+ ...file,
282
+ path: applySlugPlaceholder(file.path, slug),
283
+ content: applySlugPlaceholder(file.content, slug)
284
+ }));
285
+ }
286
+ async function cloneEntry(src, dest) {
287
+ await mkdir(dirname(dest), { recursive: true });
288
+ const platform = process.platform;
289
+ const cloneArgs = platform === "darwin" ? ["-Rc", src, dest] : platform === "linux" ? ["-r", "--reflink=auto", src, dest] : null;
290
+ if (cloneArgs) {
291
+ const result = await execArgv("cp", cloneArgs, dirname(dest));
292
+ if (result.exitCode === 0) return;
293
+ }
294
+ const fallback = await execArgv("cp", ["-R", src, dest], dirname(dest));
295
+ if (fallback.exitCode !== 0) {
296
+ throw new Error(
297
+ `clone of '${src}' into '${dest}' failed: ${fallback.stderr || fallback.stdout}`
298
+ );
299
+ }
300
+ }
301
+ async function cloneEntries(repoRoot, cwd, patterns) {
302
+ for (const pattern of patterns) {
303
+ const matches = await expandCloneGlob(repoRoot, pattern);
304
+ for (const rel of matches) {
305
+ const dest = join(cwd, rel);
306
+ const existing = await lstat(dest).catch(() => null);
307
+ if (existing) continue;
308
+ await cloneEntry(join(repoRoot, rel), dest);
309
+ }
310
+ }
311
+ }
184
312
  var ENV_VARS = {
185
313
  /** Absolute path to the original repo checkout the worktree was cut from. */
186
314
  sourceCheckoutPath: "AGENTPROTO_SOURCE_CHECKOUT_PATH",
@@ -232,38 +360,78 @@ function resolveWorktreesTurboCacheDir() {
232
360
  }
233
361
 
234
362
  // src/lifecycle.ts
363
+ var NOISE_LINE_RES = [
364
+ /Failed to replace env in config: \$\{NODE_AUTH_TOKEN\}/,
365
+ /^\s*WARN\s+Issue while reading ".*\.npmrc"\.?\s*$/
366
+ ];
367
+ function filteredTail(result) {
368
+ const combined = [result.stdout, result.stderr].filter(Boolean).join("\n");
369
+ const lines = combined.split("\n").filter((line) => !NOISE_LINE_RES.some((re) => re.test(line)));
370
+ const tail = lines.slice(-60).join("\n").trim();
371
+ return tail || "(no output captured)";
372
+ }
235
373
  var HookError = class extends Error {
236
374
  command;
237
375
  result;
238
- constructor(phase, run) {
376
+ /** Path to the full, unfiltered stdout+stderr log for this and every
377
+ * other hook command in the same run, when the caller asked for one to
378
+ * be persisted (see {@link runSetup}'s `opts.logPath`). */
379
+ logPath;
380
+ constructor(phase, run, logPath) {
239
381
  super(
240
382
  `worktree ${phase} hook failed (exit ${run.result.exitCode}): ${run.command}
241
- ` + (run.result.stderr || run.result.stdout).trim()
383
+ ` + filteredTail(run.result) + (logPath ? `
384
+
385
+ (full hook output: ${logPath})` : "")
242
386
  );
243
387
  this.name = "HookError";
244
388
  this.command = run.command;
245
389
  this.result = run.result;
390
+ if (logPath !== void 0) this.logPath = logPath;
246
391
  }
247
392
  };
248
- async function runSetup(config, ctx) {
393
+ async function appendHookLog(logPath, command, result) {
394
+ if (!logPath) return;
395
+ try {
396
+ await mkdir(dirname(logPath), { recursive: true });
397
+ const parts = [
398
+ `$ ${command}`,
399
+ result.stdout,
400
+ result.stderr,
401
+ `(exit ${result.exitCode})`,
402
+ ""
403
+ ].filter(Boolean);
404
+ await appendFile(logPath, parts.join("\n") + "\n", "utf8");
405
+ } catch {
406
+ }
407
+ }
408
+ async function runSetup(config, ctx, opts = {}) {
249
409
  const commands = normalizeHook(config.worktree?.setup);
250
410
  const runs = [];
251
411
  const env = { ...hookEnv(ctx), TURBO_CACHE_DIR: resolveWorktreesTurboCacheDir() };
252
412
  for (const command of commands) {
253
- const result = await execShell(command, ctx.worktreePath, { env });
254
- const run = { command, result };
413
+ let result = await execShell(command, ctx.worktreePath, { env });
414
+ let run = { command, result };
255
415
  runs.push(run);
256
- if (result.exitCode !== 0) throw new HookError("setup", run);
416
+ await appendHookLog(opts.logPath, command, result);
417
+ if (result.exitCode !== 0 && opts.retryOnFailure) {
418
+ result = await execShell(command, ctx.worktreePath, { env });
419
+ run = { command, result };
420
+ runs.push(run);
421
+ await appendHookLog(opts.logPath, `${command} (retry 1/1)`, result);
422
+ }
423
+ if (result.exitCode !== 0) throw new HookError("setup", run, opts.logPath);
257
424
  }
258
425
  return runs;
259
426
  }
260
- async function runTeardown(config, ctx) {
427
+ async function runTeardown(config, ctx, opts = {}) {
261
428
  const commands = normalizeHook(config.worktree?.teardown);
262
429
  const runs = [];
263
430
  const env = hookEnv(ctx);
264
431
  for (const command of commands) {
265
432
  const result = await execShell(command, ctx.worktreePath, { env });
266
433
  runs.push({ command, result });
434
+ await appendHookLog(opts.logPath, command, result);
267
435
  }
268
436
  return runs;
269
437
  }
@@ -414,8 +582,12 @@ var provisionWorktreeBuiltin = implementTool(
414
582
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
415
583
  });
416
584
  const config = input.runSetup !== false ? await loadConfigFromBase(input.repoRoot, base) : null;
417
- const linkPaths = input.linkPaths ?? config?.worktree?.linkPaths ?? [];
418
- const depsCmd = input.depsCmd ?? config?.worktree?.depsCmd;
585
+ const localConfig = input.runSetup !== false ? await loadLocalWorktreeConfig(input.repoRoot) : null;
586
+ const linkPaths = input.linkPaths ?? localConfig?.linkPaths ?? config?.worktree?.linkPaths ?? [];
587
+ const depsCmd = input.depsCmd ?? localConfig?.depsCmd ?? config?.worktree?.depsCmd;
588
+ const copyGlobs = input.copyGlobs ?? localConfig?.copyGlobs ?? [];
589
+ const cloneGlobs = input.cloneGlobs ?? localConfig?.cloneGlobs ?? [];
590
+ const writeFiles = input.writeFiles ?? resolveLocalWriteFiles(localConfig?.writeFiles, input.slug);
419
591
  for (const rel of linkPaths) {
420
592
  const target = resolve(input.repoRoot, rel);
421
593
  const dest = join(cwd, rel);
@@ -424,7 +596,7 @@ var provisionWorktreeBuiltin = implementTool(
424
596
  await mkdir(dirname(dest), { recursive: true });
425
597
  await symlink(target, dest, "dir");
426
598
  }
427
- for (const file of input.writeFiles ?? []) {
599
+ for (const file of writeFiles) {
428
600
  const dest = join(cwd, file.path);
429
601
  await mkdir(dirname(dest), { recursive: true });
430
602
  if (file.mode === "append") {
@@ -437,6 +609,16 @@ var provisionWorktreeBuiltin = implementTool(
437
609
  await writeFile(dest, file.content);
438
610
  }
439
611
  }
612
+ if (cloneGlobs.length > 0) {
613
+ try {
614
+ await cloneEntries(input.repoRoot, cwd, cloneGlobs);
615
+ } catch (err) {
616
+ throw new ToolError({
617
+ code: "execution_failed",
618
+ message: `cloneGlobs failed: ${err instanceof Error ? err.message : String(err)}`
619
+ });
620
+ }
621
+ }
440
622
  if (depsCmd) {
441
623
  const result = await execShell(depsCmd, cwd);
442
624
  if (result.exitCode !== 0) {
@@ -446,7 +628,7 @@ var provisionWorktreeBuiltin = implementTool(
446
628
  });
447
629
  }
448
630
  }
449
- for (const pattern of input.copyGlobs ?? []) {
631
+ for (const pattern of copyGlobs) {
450
632
  const matches = await expandGlob(input.repoRoot, pattern);
451
633
  for (const rel of matches) {
452
634
  const dest = join(cwd, rel);
@@ -456,11 +638,18 @@ var provisionWorktreeBuiltin = implementTool(
456
638
  }
457
639
  if (config) {
458
640
  try {
459
- await runSetup(config, {
460
- sourceCheckoutPath: input.repoRoot,
461
- worktreePath: cwd,
462
- branchName: branch
463
- });
641
+ await runSetup(
642
+ config,
643
+ {
644
+ sourceCheckoutPath: input.repoRoot,
645
+ worktreePath: cwd,
646
+ branchName: branch
647
+ },
648
+ {
649
+ ...input.setupLogPath ? { logPath: input.setupLogPath } : {},
650
+ ...input.retrySetupOnFailure ? { retryOnFailure: true } : {}
651
+ }
652
+ );
464
653
  } catch (err) {
465
654
  if (err instanceof HookError) {
466
655
  throw new ToolError({ code: "execution_failed", message: err.message });
@@ -471,25 +660,105 @@ var provisionWorktreeBuiltin = implementTool(
471
660
  return { cwd, branch };
472
661
  }
473
662
  );
663
+ var WORKTREE_TRASH_DIRNAME = ".trash";
664
+ function realOrResolved(path) {
665
+ try {
666
+ return realpathSync(path);
667
+ } catch {
668
+ return path;
669
+ }
670
+ }
671
+ async function removeWorktreeFast(repoRoot, path, options = {}) {
672
+ const force = options.force === true;
673
+ if (!force) {
674
+ const status = await execArgv(
675
+ "git",
676
+ ["-C", path, "status", "--porcelain=v2", "--ignored=matching"],
677
+ repoRoot
678
+ );
679
+ if (status.exitCode !== 0) {
680
+ throw new Error(
681
+ `git status failed in ${path} (exit ${status.exitCode}): ${status.stderr.trim() || status.stdout.trim()}`
682
+ );
683
+ }
684
+ if (status.stdout.trim().length > 0) {
685
+ const probe = await execArgv("git", ["-C", repoRoot, "worktree", "remove", path], repoRoot);
686
+ if (probe.exitCode !== 0) {
687
+ throw new Error(
688
+ `git worktree remove failed (exit ${probe.exitCode}): ${probe.stderr.trim() || probe.stdout.trim()}`
689
+ );
690
+ }
691
+ await execGit(repoRoot, ["worktree", "prune"]);
692
+ return;
693
+ }
694
+ }
695
+ const list = await execArgv("git", ["-C", repoRoot, "worktree", "list", "--porcelain"], repoRoot);
696
+ if (list.exitCode !== 0) {
697
+ throw new Error(
698
+ `git worktree list failed (exit ${list.exitCode}): ${list.stderr.trim() || list.stdout.trim()}`
699
+ );
700
+ }
701
+ const registered = new Set(
702
+ list.stdout.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => line.slice("worktree ".length).trim())
703
+ );
704
+ const registeredReal = new Set([...registered].map(realOrResolved));
705
+ if (!registeredReal.has(realOrResolved(path))) {
706
+ throw new Error(`not a linked worktree of ${repoRoot}: ${path}`);
707
+ }
708
+ const poolDir = join(path, "..");
709
+ const stamp = (options.now ?? Date.now)();
710
+ const trashDir = join(poolDir, WORKTREE_TRASH_DIRNAME, `${basename(path)}-${stamp}`);
711
+ try {
712
+ if (!existsSync(join(poolDir, WORKTREE_TRASH_DIRNAME))) {
713
+ mkdirSync(join(poolDir, WORKTREE_TRASH_DIRNAME));
714
+ }
715
+ await rename(path, trashDir);
716
+ } catch {
717
+ await execGit(repoRoot, force ? ["worktree", "remove", "--force", path] : ["worktree", "remove", path]);
718
+ return;
719
+ }
720
+ await execGit(repoRoot, ["worktree", "prune"]);
721
+ if (options.spawnRemoval) {
722
+ options.spawnRemoval(trashDir);
723
+ } else {
724
+ spawn("rm", ["-rf", trashDir], { detached: true, stdio: "ignore" }).unref();
725
+ }
726
+ }
727
+ function sweepWorktreeTrash(root, options = {}) {
728
+ let names;
729
+ try {
730
+ names = readdirSync(join(root, WORKTREE_TRASH_DIRNAME));
731
+ } catch {
732
+ return;
733
+ }
734
+ for (const name of names) {
735
+ const trashDir = join(root, WORKTREE_TRASH_DIRNAME, name);
736
+ if (options.spawnRemoval) {
737
+ options.spawnRemoval(trashDir);
738
+ } else {
739
+ spawn("rm", ["-rf", trashDir], { detached: true, stdio: "ignore" }).unref();
740
+ }
741
+ }
742
+ }
474
743
  function isPortFree(port) {
475
- return new Promise((resolve5) => {
744
+ return new Promise((resolve6) => {
476
745
  const server = createServer();
477
- server.once("error", () => resolve5(false));
746
+ server.once("error", () => resolve6(false));
478
747
  server.once("listening", () => {
479
- server.close(() => resolve5(true));
748
+ server.close(() => resolve6(true));
480
749
  });
481
750
  server.listen(port, "127.0.0.1");
482
751
  });
483
752
  }
484
753
  function ephemeralPort() {
485
- return new Promise((resolve5, reject) => {
754
+ return new Promise((resolve6, reject) => {
486
755
  const server = createServer();
487
756
  server.once("error", reject);
488
757
  server.listen(0, "127.0.0.1", () => {
489
758
  const address = server.address();
490
759
  if (address && typeof address === "object") {
491
760
  const port = address.port;
492
- server.close(() => resolve5(port));
761
+ server.close(() => resolve6(port));
493
762
  } else {
494
763
  server.close(() => reject(new Error("could not determine an ephemeral port")));
495
764
  }
@@ -624,10 +893,10 @@ var ServiceSupervisor = class _ServiceSupervisor {
624
893
  this.opts.proxyTable?.delete(t.runtime.hostname);
625
894
  const child = t.child;
626
895
  if (!child || t.status !== "running") return false;
627
- return new Promise((resolve5) => {
896
+ return new Promise((resolve6) => {
628
897
  const done = () => {
629
898
  t.status = "exited";
630
- resolve5(true);
899
+ resolve6(true);
631
900
  };
632
901
  child.once("exit", done);
633
902
  child.kill("SIGTERM");
@@ -769,6 +1038,7 @@ async function computeTreeState(repoRoot, worktreePath, options = {}) {
769
1038
  );
770
1039
  }
771
1040
  const noise = [];
1041
+ const dirtyPaths = [];
772
1042
  let modified = 0;
773
1043
  let staged = 0;
774
1044
  let untracked = 0;
@@ -779,6 +1049,7 @@ async function computeTreeState(repoRoot, worktreePath, options = {}) {
779
1049
  noise.push(path);
780
1050
  continue;
781
1051
  }
1052
+ if (path !== null) dirtyPaths.push(path);
782
1053
  if (line.startsWith("? ")) {
783
1054
  untracked++;
784
1055
  continue;
@@ -790,12 +1061,14 @@ async function computeTreeState(repoRoot, worktreePath, options = {}) {
790
1061
  }
791
1062
  }
792
1063
  if (modified === 0 && staged === 0 && untracked === 0) return noise.length > 0 ? { state: "clean", noise } : { state: "clean" };
1064
+ const onlyUnder = dirtyPaths.length > 0 && dirtyPaths.every((p) => p.startsWith(".plans/")) ? ".plans/" : void 0;
793
1065
  return {
794
1066
  state: "dirty",
795
1067
  modified,
796
1068
  staged,
797
1069
  untracked,
798
- newestMtimeMs: await newestDirtyMtimeMs(repoRoot, worktreePath)
1070
+ newestMtimeMs: await newestDirtyMtimeMs(repoRoot, worktreePath),
1071
+ ...onlyUnder ? { onlyUnder } : {}
799
1072
  };
800
1073
  }
801
1074
  async function newestDirtyMtimeMs(repoRoot, worktreePath) {
@@ -1062,6 +1335,7 @@ function classify(tree, integration, liveness, nowMs = Date.now()) {
1062
1335
  const idleOrUnreachable = liveness.state === "idle" || liveness.state === "daemon-unreachable";
1063
1336
  if ((merged || fresh) && clean && idleOrUnreachable) return { reclaimable: true, class: "reclaim" };
1064
1337
  if (merged && !clean) {
1338
+ if (!idleOrUnreachable) return { reclaimable: false, class: "hold" };
1065
1339
  const writtenRecently = tree.state === "dirty" && typeof tree.newestMtimeMs === "number" && nowMs - tree.newestMtimeMs < RECENT_WRITE_HOLD_WINDOW_MS;
1066
1340
  if (writtenRecently) return { reclaimable: false, class: "hold" };
1067
1341
  return { reclaimable: false, class: "salvage" };
@@ -1189,13 +1463,13 @@ var cleanupWorktreeBuiltin = implementTool(
1189
1463
  if (tree.untracked > 0 && !discardUntracked) blocked.push("untracked");
1190
1464
  if ((tree.modified > 0 || tree.staged > 0) && !discardModified) blocked.push("modified");
1191
1465
  if (blocked.length > 0) throw new WorktreeNotRemovableError(input.cwd, blocked);
1192
- await execGit(input.repoRoot, ["worktree", "remove", "--force", input.cwd]);
1466
+ await removeWorktreeFast(input.repoRoot, input.cwd, { force: true });
1193
1467
  } else {
1194
- await execGit(input.repoRoot, ["worktree", "remove", input.cwd]);
1468
+ await removeWorktreeFast(input.repoRoot, input.cwd);
1195
1469
  }
1196
1470
  } else {
1197
1471
  try {
1198
- await execGit(input.repoRoot, ["worktree", "remove", input.cwd]);
1472
+ await removeWorktreeFast(input.repoRoot, input.cwd);
1199
1473
  } catch (err) {
1200
1474
  throw new WorktreeNotRemovableError(input.cwd, [], err instanceof Error ? err.message : String(err));
1201
1475
  }
@@ -1287,6 +1561,6 @@ var worktreeProvider = defineDriver({
1287
1561
  ]
1288
1562
  });
1289
1563
 
1290
- export { CONFIG_FILENAME, ConfigError, DEFAULT_PROXY_PORT, ENV_VARS, FileVerdictMemoStore, HookError, InMemoryVerdictMemoStore, ProxyTable, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, ServiceSupervisor, VERDICT_MEMO_PATH, WORKTREES_TURBO_CACHE_DIR_ENV, WorktreeNotRemovableError, allocatePort, classify, computeBaseDivergence, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, normalizeHook, parseConfig, peerEnv, peerEnvKey, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, repoLabel, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, stripPort, worktreeProvider, writeWorktreeMarker };
1291
- //# sourceMappingURL=chunk-KRQFVJPK.mjs.map
1292
- //# sourceMappingURL=chunk-KRQFVJPK.mjs.map
1564
+ export { CONFIG_FILENAME, ConfigError, DEFAULT_PROXY_PORT, ENV_VARS, FileVerdictMemoStore, GlobTraversalError, HookError, InMemoryVerdictMemoStore, LOCAL_WORKTREE_CONFIG_REL, ProxyTable, SESSIONS_BUCKETS_ROOT, SESSIONS_FILE_PATH, ServiceSupervisor, VERDICT_MEMO_PATH, WORKTREES_TURBO_CACHE_DIR_ENV, WORKTREE_TRASH_DIRNAME, WorktreeNotRemovableError, allocatePort, applySlugPlaceholder, classify, cloneEntries, computeBaseDivergence, computeLiveness, computeProvenance, computeTreeState, computeWorktreeStatus, detectDefaultBranch, disposeSupervisor, ephemeralPort, execArgv, execGit, execShell, expandCloneGlob, expandGlob, getScript, getSupervisor, globToRegExp, hookEnv, isPortFree, listGitWorktrees, listScripts, listServices, listWorktreeStatuses, loadConfigFromBase, loadLocalWorktreeConfig, normalizeHook, parseConfig, parseLocalWorktreeConfig, peerEnv, peerEnvKey, readSessionsRegistry, readWorktreeMarker, reconcileIntegration, removeWorktreeFast, repoLabel, resolveLocalWriteFiles, resolveSupervisor, resolveWorktreesTurboCacheDir, runSetup, runTeardown, serviceEnv, serviceEnvToken, serviceHostname, serviceUrl, sessionInWorktree, sharedProxyTable, slugify, stripPort, sweepWorktreeTrash, worktreeProvider, writeWorktreeMarker };
1565
+ //# sourceMappingURL=chunk-MYH5XOX6.mjs.map
1566
+ //# sourceMappingURL=chunk-MYH5XOX6.mjs.map