claude-nomad 0.43.0 → 0.44.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.
package/dist/nomad.mjs CHANGED
@@ -561,31 +561,31 @@ var init_utils_fs = __esm({
561
561
  });
562
562
 
563
563
  // src/push-gitleaks.config.ts
564
- import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
564
+ import { existsSync as existsSync11, mkdtempSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
565
565
  import { tmpdir } from "node:os";
566
- import { join as join11 } from "node:path";
566
+ import { join as join12 } from "node:path";
567
567
  import { fileURLToPath } from "node:url";
568
568
  function resolveTomlPath() {
569
- const repoToml = join11(REPO_HOME, ".gitleaks.toml");
570
- if (existsSync10(repoToml)) return repoToml;
569
+ const repoToml = join12(REPO_HOME, ".gitleaks.toml");
570
+ if (existsSync11(repoToml)) return repoToml;
571
571
  const bundled = fileURLToPath(new URL("../.gitleaks.toml", import.meta.url));
572
- return existsSync10(bundled) ? bundled : null;
572
+ return existsSync11(bundled) ? bundled : null;
573
573
  }
574
574
  function buildOverlayTempConfig(overlayBody, bundled) {
575
575
  const tempBody = `[extend]
576
576
  path = ${JSON.stringify(bundled)}
577
577
 
578
578
  ${overlayBody}`;
579
- const tempPath = mkdtempSync(join11(tmpdir(), "nomad-gitleaks-cfg-"));
580
- const configPath = join11(tempPath, "config.toml");
579
+ const tempPath = mkdtempSync(join12(tmpdir(), "nomad-gitleaks-cfg-"));
580
+ const configPath = join12(tempPath, "config.toml");
581
581
  writeFileSync2(configPath, tempBody, { mode: 384, flag: "wx" });
582
582
  return { configPath, tempPath };
583
583
  }
584
584
  function resolveTomlConfig() {
585
- const overlayPath = join11(REPO_HOME, ".gitleaks.overlay.toml");
586
- const repoToml = join11(REPO_HOME, ".gitleaks.toml");
585
+ const overlayPath = join12(REPO_HOME, ".gitleaks.overlay.toml");
586
+ const repoToml = join12(REPO_HOME, ".gitleaks.toml");
587
587
  const bundled = resolveTomlPath();
588
- if (!existsSync10(overlayPath)) {
588
+ if (!existsSync11(overlayPath)) {
589
589
  return { path: bundled, tempPath: null };
590
590
  }
591
591
  if (bundled === repoToml) {
@@ -626,9 +626,9 @@ var init_push_gitleaks_config = __esm({
626
626
 
627
627
  // src/push-checks.ts
628
628
  import { execFileSync as execFileSync2 } from "node:child_process";
629
- import { readdirSync as readdirSync4, rmSync as rmSync3 } from "node:fs";
629
+ import { readdirSync as readdirSync4, rmSync as rmSync4 } from "node:fs";
630
630
  import { homedir as homedir2, platform } from "node:os";
631
- import { join as join12 } from "node:path";
631
+ import { join as join13 } from "node:path";
632
632
  function gitleaksInstallHint() {
633
633
  const head = "gitleaks not on PATH (required for nomad push). Install:";
634
634
  const plat = platform();
@@ -671,7 +671,7 @@ function findGitlinks(dir) {
671
671
  return;
672
672
  }
673
673
  for (const e of entries) {
674
- const p = join12(current, e.name);
674
+ const p = join13(current, e.name);
675
675
  if (e.name === ".git") {
676
676
  hits.push(p);
677
677
  continue;
@@ -693,7 +693,7 @@ function probeGitleaks() {
693
693
  if (e.code === "ENOENT") throw new NomadFatal(gitleaksInstallHint());
694
694
  throw new NomadFatal(`gitleaks --version failed: ${e.message}`);
695
695
  } finally {
696
- if (tempPath !== null) rmSync3(tempPath, { recursive: true, force: true });
696
+ if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
697
697
  }
698
698
  }
699
699
  function rebaseBeforePush() {
@@ -721,9 +721,9 @@ var init_push_checks = __esm({
721
721
 
722
722
  // src/push-gitleaks.scan.ts
723
723
  import { execFileSync as execFileSync5 } from "node:child_process";
724
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync4 } from "node:fs";
724
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync5 } from "node:fs";
725
725
  import { homedir as homedir3 } from "node:os";
726
- import { join as join16 } from "node:path";
726
+ import { join as join17 } from "node:path";
727
727
  function readGitleaksReport(reportPath) {
728
728
  try {
729
729
  const raw = readFileSync4(reportPath, "utf8");
@@ -735,9 +735,9 @@ function readGitleaksReport(reportPath) {
735
735
  }
736
736
  }
737
737
  function scanStagedTree(repoDir, forwardStreams = false) {
738
- const cacheDir = join16(homedir3(), ".cache", "claude-nomad");
738
+ const cacheDir = join17(homedir3(), ".cache", "claude-nomad");
739
739
  mkdirSync2(cacheDir, { recursive: true });
740
- const reportPath = join16(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
740
+ const reportPath = join17(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
741
741
  const { path: toml, tempPath } = resolveTomlConfig();
742
742
  const args = [
743
743
  "protect",
@@ -764,14 +764,14 @@ function scanStagedTree(repoDir, forwardStreams = false) {
764
764
  }
765
765
  return report;
766
766
  } finally {
767
- if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
768
- rmSync4(reportPath, { force: true });
767
+ if (tempPath !== null) rmSync5(tempPath, { recursive: true, force: true });
768
+ rmSync5(reportPath, { force: true });
769
769
  }
770
770
  }
771
771
  function scanFile(filePath, forwardStreams = false) {
772
- const cacheDir = join16(homedir3(), ".cache", "claude-nomad");
772
+ const cacheDir = join17(homedir3(), ".cache", "claude-nomad");
773
773
  mkdirSync2(cacheDir, { recursive: true });
774
- const reportPath = join16(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}.json`);
774
+ const reportPath = join17(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}.json`);
775
775
  const { path: toml, tempPath } = resolveTomlConfig();
776
776
  const args = [
777
777
  "detect",
@@ -796,8 +796,8 @@ function scanFile(filePath, forwardStreams = false) {
796
796
  }
797
797
  return report;
798
798
  } finally {
799
- if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
800
- rmSync4(reportPath, { force: true });
799
+ if (tempPath !== null) rmSync5(tempPath, { recursive: true, force: true });
800
+ rmSync5(reportPath, { force: true });
801
801
  }
802
802
  }
803
803
  var init_push_gitleaks_scan = __esm({
@@ -1219,15 +1219,178 @@ function cmdClean(opts, backupBase = BACKUP_BASE) {
1219
1219
  log(`removed ${targets.length} backup(s)`);
1220
1220
  }
1221
1221
 
1222
+ // src/commands.eject.ts
1223
+ init_config();
1224
+ init_utils();
1225
+ init_utils_json();
1226
+ import { cpSync as cpSync3, existsSync as existsSync5, lstatSync as lstatSync4, realpathSync, renameSync as renameSync2, rmSync as rmSync3 } from "node:fs";
1227
+ import { join as join6, sep } from "node:path";
1228
+ var EJECT_CHECKLIST = [
1229
+ "Manual steps remaining to finish leaving claude-nomad on this host:",
1230
+ ` 1. Uninstall the CLI: npm uninstall -g claude-nomad`,
1231
+ ` 2. Remove NOMAD_HOST and NOMAD_REPO from your shell rc (~/.zshrc or ~/.bashrc)`,
1232
+ ` 3. Optionally delete the local sync checkout: rm -rf ${REPO_HOME}`,
1233
+ ` 4. Optionally delete the private sync repo on GitHub`,
1234
+ ` 5. Optionally delete the backup cache: rm -rf ${BACKUP_BASE}`
1235
+ ].join("\n");
1236
+ var DEFAULT_ROOTS = { claudeHome: CLAUDE_HOME, repoHome: REPO_HOME };
1237
+ function errMessage(err) {
1238
+ return err instanceof Error ? err.message : String(err);
1239
+ }
1240
+ function lexists2(p) {
1241
+ try {
1242
+ lstatSync4(p);
1243
+ return true;
1244
+ } catch {
1245
+ return false;
1246
+ }
1247
+ }
1248
+ function readMapIfPresent2(repoHome) {
1249
+ const mapPath = join6(repoHome, "path-map.json");
1250
+ return existsSync5(mapPath) ? readPathMap(mapPath) : { projects: {} };
1251
+ }
1252
+ function classifyName(linkPath) {
1253
+ if (!lexists2(linkPath)) return "absent";
1254
+ if (!lstatSync4(linkPath).isSymbolicLink()) return "skip-real";
1255
+ if (!existsSync5(linkPath)) return "dangling";
1256
+ return "materialize";
1257
+ }
1258
+ function resolveSharedRoot(repoHome) {
1259
+ try {
1260
+ return realpathSync(join6(repoHome, "shared"));
1261
+ } catch {
1262
+ return die(
1263
+ `cannot resolve ${join6(repoHome, "shared")} (repo checkout incomplete). run \`nomad pull\` first, then re-run \`nomad eject\``
1264
+ );
1265
+ }
1266
+ }
1267
+ function isManagedTarget(target, sharedRoot) {
1268
+ return target.startsWith(sharedRoot + sep);
1269
+ }
1270
+ function materializeOne(name, linkPath, sharedRoot) {
1271
+ const target = realpathSync(linkPath);
1272
+ if (!isManagedTarget(target, sharedRoot)) {
1273
+ log(`skipped (not a nomad-managed target): ${name} -> ${target}`);
1274
+ return false;
1275
+ }
1276
+ const tmp = `${linkPath}.eject.tmp.${process.pid}.${Date.now()}`;
1277
+ try {
1278
+ rmSync3(tmp, { recursive: true, force: true });
1279
+ cpSync3(target, tmp, {
1280
+ recursive: true,
1281
+ force: true,
1282
+ dereference: true,
1283
+ preserveTimestamps: true
1284
+ });
1285
+ rmSync3(linkPath, { force: true });
1286
+ renameSync2(tmp, linkPath);
1287
+ log(`ejected: ${name}`);
1288
+ return true;
1289
+ } catch (err) {
1290
+ try {
1291
+ rmSync3(tmp, { recursive: true, force: true });
1292
+ } catch {
1293
+ }
1294
+ throw err;
1295
+ }
1296
+ }
1297
+ function previewDryRun(names, classifications, claudeHome, sharedRoot) {
1298
+ for (const name of names) {
1299
+ const cls = classifications.get(name);
1300
+ const linkPath = join6(claudeHome, name);
1301
+ if (cls === "absent") {
1302
+ log(`skipped (absent): ${name}`);
1303
+ } else if (cls === "skip-real") {
1304
+ log(`skipped (not a symlink): ${name}`);
1305
+ } else {
1306
+ previewMaterialize(name, linkPath, sharedRoot);
1307
+ }
1308
+ }
1309
+ log(EJECT_CHECKLIST);
1310
+ }
1311
+ function previewMaterialize(name, linkPath, sharedRoot) {
1312
+ let target;
1313
+ try {
1314
+ target = realpathSync(linkPath);
1315
+ } catch {
1316
+ log(`would materialize: ${name} (target now unresolvable; re-run to re-classify)`);
1317
+ return;
1318
+ }
1319
+ if (!isManagedTarget(target, sharedRoot)) {
1320
+ log(`skipped (not a nomad-managed target): ${name} -> ${target}`);
1321
+ return;
1322
+ }
1323
+ log(`would materialize: ${name} (copy ${target} -> ${linkPath})`);
1324
+ }
1325
+ function runLiveEject(names, classifications, claudeHome, sharedRoot) {
1326
+ const done = [];
1327
+ let skipped = 0;
1328
+ for (const name of names) {
1329
+ const cls = classifications.get(name);
1330
+ const linkPath = join6(claudeHome, name);
1331
+ if (cls === "absent") {
1332
+ log(`skipped (absent): ${name}`);
1333
+ skipped++;
1334
+ } else if (cls === "skip-real") {
1335
+ log(`skipped (not a symlink): ${name}`);
1336
+ skipped++;
1337
+ } else if (materializeOneOrDie(name, linkPath, sharedRoot, done)) {
1338
+ done.push(name);
1339
+ } else {
1340
+ skipped++;
1341
+ }
1342
+ }
1343
+ log(`materialized ${done.length}, skipped ${skipped}`);
1344
+ log(EJECT_CHECKLIST);
1345
+ }
1346
+ function materializeOneOrDie(name, linkPath, sharedRoot, done) {
1347
+ try {
1348
+ return materializeOne(name, linkPath, sharedRoot);
1349
+ } catch (err) {
1350
+ const msg = errMessage(err);
1351
+ return die(
1352
+ `failed to materialize ${name}: ${msg}. already materialized: ${done.join(", ") || "(none)"}. the remaining names are still symlinks; do NOT delete ${REPO_HOME} yet, fix the cause and re-run \`nomad eject\` (it is idempotent on already-real names)`
1353
+ );
1354
+ }
1355
+ }
1356
+ function cmdEject(opts = {}, roots = DEFAULT_ROOTS) {
1357
+ const dryRun = opts.dryRun === true;
1358
+ const { claudeHome, repoHome } = roots;
1359
+ const map = readMapIfPresent2(repoHome);
1360
+ const names = allSharedLinks(map);
1361
+ const classifications = /* @__PURE__ */ new Map();
1362
+ for (const name of names) {
1363
+ classifications.set(name, classifyName(join6(claudeHome, name)));
1364
+ }
1365
+ const dangling = names.filter((n) => classifications.get(n) === "dangling");
1366
+ if (dangling.length > 0) {
1367
+ fail(
1368
+ `dangling symlink(s): ${dangling.join(", ")}. run \`nomad pull\` first to restore the missing target, then re-run \`nomad eject\``
1369
+ );
1370
+ process.exit(1);
1371
+ }
1372
+ const sharedRoot = resolveSharedRoot(repoHome);
1373
+ if (dryRun) {
1374
+ previewDryRun(names, classifications, claudeHome, sharedRoot);
1375
+ return;
1376
+ }
1377
+ try {
1378
+ runLiveEject(names, classifications, claudeHome, sharedRoot);
1379
+ } catch (err) {
1380
+ fail(errMessage(err));
1381
+ process.exit(1);
1382
+ }
1383
+ }
1384
+
1222
1385
  // src/commands.doctor.ts
1223
- import { existsSync as existsSync21 } from "node:fs";
1224
- import { join as join25 } from "node:path";
1386
+ import { existsSync as existsSync22 } from "node:fs";
1387
+ import { join as join26 } from "node:path";
1225
1388
 
1226
1389
  // src/commands.doctor.checks.repo.ts
1227
1390
  init_color();
1228
1391
  init_config();
1229
- import { existsSync as existsSync6, lstatSync as lstatSync4, statSync as statSync3 } from "node:fs";
1230
- import { join as join7 } from "node:path";
1392
+ import { existsSync as existsSync7, lstatSync as lstatSync5, statSync as statSync3 } from "node:fs";
1393
+ import { join as join8 } from "node:path";
1231
1394
 
1232
1395
  // src/commands.doctor.format.ts
1233
1396
  init_color();
@@ -1305,15 +1468,15 @@ function readJsonSafe(path, label, section2) {
1305
1468
  // src/init.classify.ts
1306
1469
  init_config();
1307
1470
  init_utils_json();
1308
- import { existsSync as existsSync5 } from "node:fs";
1309
- import { join as join6 } from "node:path";
1471
+ import { existsSync as existsSync6 } from "node:fs";
1472
+ import { join as join7 } from "node:path";
1310
1473
  function classifyRepoState(repoHome, host) {
1311
- const basePath = join6(repoHome, "shared", "settings.base.json");
1312
- const mapPath = join6(repoHome, "path-map.json");
1313
- const hostPath = join6(repoHome, "hosts", `${host}.json`);
1314
- const hasBase = existsSync5(basePath);
1315
- const hasMap = existsSync5(mapPath);
1316
- const hasHost = existsSync5(hostPath);
1474
+ const basePath = join7(repoHome, "shared", "settings.base.json");
1475
+ const mapPath = join7(repoHome, "path-map.json");
1476
+ const hostPath = join7(repoHome, "hosts", `${host}.json`);
1477
+ const hasBase = existsSync6(basePath);
1478
+ const hasMap = existsSync6(mapPath);
1479
+ const hasHost = existsSync6(hostPath);
1317
1480
  let mapEntryCount = 0;
1318
1481
  if (hasMap) {
1319
1482
  try {
@@ -1328,11 +1491,11 @@ function classifyRepoState(repoHome, host) {
1328
1491
  return "partial";
1329
1492
  }
1330
1493
  function reasonForPartial(repoHome, host) {
1331
- const basePath = join6(repoHome, "shared", "settings.base.json");
1332
- const mapPath = join6(repoHome, "path-map.json");
1333
- const hostPath = join6(repoHome, "hosts", `${host}.json`);
1334
- if (!existsSync5(basePath)) return "- shared/settings.base.json missing";
1335
- if (!existsSync5(mapPath)) return "- path-map.json missing";
1494
+ const basePath = join7(repoHome, "shared", "settings.base.json");
1495
+ const mapPath = join7(repoHome, "path-map.json");
1496
+ const hostPath = join7(repoHome, "hosts", `${host}.json`);
1497
+ if (!existsSync6(basePath)) return "- shared/settings.base.json missing";
1498
+ if (!existsSync6(mapPath)) return "- path-map.json missing";
1336
1499
  let mapEntryCount;
1337
1500
  try {
1338
1501
  const map = readJson(mapPath);
@@ -1341,7 +1504,7 @@ function reasonForPartial(repoHome, host) {
1341
1504
  mapEntryCount = 0;
1342
1505
  }
1343
1506
  if (mapEntryCount === 0) return "- path-map.json.projects has no entries";
1344
- if (!existsSync5(hostPath)) return `- hosts/${host}.json missing`;
1507
+ if (!existsSync6(hostPath)) return `- hosts/${host}.json missing`;
1345
1508
  return "- partial state (unknown gap)";
1346
1509
  }
1347
1510
 
@@ -1357,11 +1520,11 @@ function reportHostAndPaths(section2) {
1357
1520
  }
1358
1521
  addItem(
1359
1522
  section2,
1360
- `${existsSync6(REPO_HOME) ? green(okGlyph) : yellow(warnGlyph)} repo: ${blue(REPO_HOME)}`
1523
+ `${existsSync7(REPO_HOME) ? green(okGlyph) : yellow(warnGlyph)} repo: ${blue(REPO_HOME)}`
1361
1524
  );
1362
1525
  addItem(
1363
1526
  section2,
1364
- `${existsSync6(CLAUDE_HOME) ? green(okGlyph) : yellow(warnGlyph)} claude home: ${blue(CLAUDE_HOME)}`
1527
+ `${existsSync7(CLAUDE_HOME) ? green(okGlyph) : yellow(warnGlyph)} claude home: ${blue(CLAUDE_HOME)}`
1365
1528
  );
1366
1529
  }
1367
1530
  function reportRepoState(section2) {
@@ -1383,12 +1546,12 @@ function reportRepoState(section2) {
1383
1546
  }
1384
1547
  }
1385
1548
  function repoHasSharedSource(name) {
1386
- return existsSync6(join7(REPO_HOME, "shared", name));
1549
+ return existsSync7(join8(REPO_HOME, "shared", name));
1387
1550
  }
1388
1551
  function classifySharedLink(name, p) {
1389
1552
  let stat;
1390
1553
  try {
1391
- stat = lstatSync4(p);
1554
+ stat = lstatSync5(p);
1392
1555
  } catch (err) {
1393
1556
  const code = err.code;
1394
1557
  if (code === "ENOENT") {
@@ -1430,7 +1593,7 @@ function classifySymlinkTarget(name, p) {
1430
1593
  }
1431
1594
  function reportSharedLinks(section2, map) {
1432
1595
  for (const name of allSharedLinks(map)) {
1433
- const p = join7(CLAUDE_HOME, name);
1596
+ const p = join8(CLAUDE_HOME, name);
1434
1597
  const { line, fail: fail2 } = classifySharedLink(name, p);
1435
1598
  addItem(section2, line);
1436
1599
  if (fail2) process.exitCode = 1;
@@ -1440,11 +1603,11 @@ function reportSharedLinks(section2, map) {
1440
1603
  // src/commands.doctor.checks.settings.ts
1441
1604
  init_color();
1442
1605
  init_config();
1443
- import { existsSync as existsSync7, readdirSync as readdirSync2 } from "node:fs";
1444
- import { join as join8 } from "node:path";
1606
+ import { existsSync as existsSync8, readdirSync as readdirSync2 } from "node:fs";
1607
+ import { join as join9 } from "node:path";
1445
1608
  function loadBaseSettings(section2) {
1446
- const basePath = join8(REPO_HOME, "shared", "settings.base.json");
1447
- if (!existsSync7(basePath)) {
1609
+ const basePath = join9(REPO_HOME, "shared", "settings.base.json");
1610
+ if (!existsSync8(basePath)) {
1448
1611
  addItem(section2, `${red(failGlyph)} shared/settings.base.json missing at ${blue(basePath)}`);
1449
1612
  process.exitCode = 1;
1450
1613
  return null;
@@ -1452,8 +1615,8 @@ function loadBaseSettings(section2) {
1452
1615
  return readJsonSafe(basePath, basePath, section2);
1453
1616
  }
1454
1617
  function loadAndReportSettings(section2) {
1455
- const settingsPath = join8(CLAUDE_HOME, "settings.json");
1456
- if (!existsSync7(settingsPath)) return null;
1618
+ const settingsPath = join9(CLAUDE_HOME, "settings.json");
1619
+ if (!existsSync8(settingsPath)) return null;
1457
1620
  const settings = readJsonSafe(settingsPath, settingsPath, section2);
1458
1621
  if (settings === null) return null;
1459
1622
  const unknownKeys = Object.keys(settings).filter((k) => !KNOWN_SETTINGS_KEYS.has(k));
@@ -1468,13 +1631,13 @@ function loadAndReportSettings(section2) {
1468
1631
  return settings;
1469
1632
  }
1470
1633
  function reportHostOverrides(section2, base, settings) {
1471
- const hostFile = join8(REPO_HOME, "hosts", `${HOST}.json`);
1634
+ const hostFile = join9(REPO_HOME, "hosts", `${HOST}.json`);
1472
1635
  let drift = [];
1473
1636
  if (base !== null && settings !== null) {
1474
1637
  const baseKeys = new Set(Object.keys(base));
1475
1638
  drift = Object.keys(settings).filter((k) => !baseKeys.has(k));
1476
1639
  }
1477
- if (existsSync7(hostFile)) {
1640
+ if (existsSync8(hostFile)) {
1478
1641
  if (readJsonSafe(hostFile, hostFile, section2) !== null) {
1479
1642
  addItem(section2, `${green(okGlyph)} host overrides: ${blue(hostFile)}`);
1480
1643
  }
@@ -1483,8 +1646,8 @@ function reportHostOverrides(section2, base, settings) {
1483
1646
  section2,
1484
1647
  `${red(failGlyph)} no hosts/${HOST}.json AND settings.json has unbased keys ${JSON.stringify(drift)}`
1485
1648
  );
1486
- const hostsDir = join8(REPO_HOME, "hosts");
1487
- if (existsSync7(hostsDir)) {
1649
+ const hostsDir = join9(REPO_HOME, "hosts");
1650
+ if (existsSync8(hostsDir)) {
1488
1651
  const cands = readdirSync2(hostsDir).filter((f) => f.endsWith(".json"));
1489
1652
  if (cands.length > 0) addItem(section2, `${dim(infoGlyph)} candidates: ${cands.join(", ")}`);
1490
1653
  }
@@ -1500,8 +1663,8 @@ function reportHostOverrides(section2, base, settings) {
1500
1663
  // src/commands.doctor.checks.pathmap.ts
1501
1664
  init_color();
1502
1665
  init_config();
1503
- import { existsSync as existsSync8, readdirSync as readdirSync3 } from "node:fs";
1504
- import { join as join9 } from "node:path";
1666
+ import { existsSync as existsSync9, readdirSync as readdirSync3 } from "node:fs";
1667
+ import { join as join10 } from "node:path";
1505
1668
  init_utils_json();
1506
1669
  function reportMappedProjects(section2, map) {
1507
1670
  const mapped = Object.entries(map.projects).filter(([, hosts]) => hosts[HOST]);
@@ -1511,8 +1674,8 @@ function reportMappedProjects(section2, map) {
1511
1674
  }
1512
1675
  }
1513
1676
  function reportUnmappedProjects(section2, map) {
1514
- const localProjects = join9(CLAUDE_HOME, "projects");
1515
- if (!existsSync8(localProjects)) return;
1677
+ const localProjects = join10(CLAUDE_HOME, "projects");
1678
+ if (!existsSync9(localProjects)) return;
1516
1679
  let localDirs;
1517
1680
  try {
1518
1681
  localDirs = readdirSync3(localProjects);
@@ -1552,8 +1715,8 @@ function reportPathCollisions(section2, map) {
1552
1715
  else addItem(section2, `${green(okGlyph)} path-encoding: no collisions`);
1553
1716
  }
1554
1717
  function reportPathMap(section2) {
1555
- const mapPath = join9(REPO_HOME, "path-map.json");
1556
- if (!existsSync8(mapPath)) {
1718
+ const mapPath = join10(REPO_HOME, "path-map.json");
1719
+ if (!existsSync9(mapPath)) {
1557
1720
  addItem(section2, `${red(failGlyph)} path-map.json missing at ${blue(mapPath)}`);
1558
1721
  process.exitCode = 1;
1559
1722
  return;
@@ -1606,16 +1769,16 @@ function reportNeverSync(section2) {
1606
1769
  init_color();
1607
1770
  init_config();
1608
1771
  import { execFileSync as execFileSync3 } from "node:child_process";
1609
- import { existsSync as existsSync11 } from "node:fs";
1610
- import { join as join13, relative as relative2 } from "node:path";
1772
+ import { existsSync as existsSync12 } from "node:fs";
1773
+ import { join as join14, relative as relative2 } from "node:path";
1611
1774
 
1612
1775
  // src/commands.pull.wedge.ts
1613
- import { existsSync as existsSync9 } from "node:fs";
1614
- import { join as join10 } from "node:path";
1776
+ import { existsSync as existsSync10 } from "node:fs";
1777
+ import { join as join11 } from "node:path";
1615
1778
  function detectWedge(repo) {
1616
- const g = join10(repo, ".git");
1617
- if (existsSync9(join10(g, "rebase-merge")) || existsSync9(join10(g, "rebase-apply"))) return "rebase";
1618
- if (existsSync9(join10(g, "MERGE_HEAD"))) return "merge";
1779
+ const g = join11(repo, ".git");
1780
+ if (existsSync10(join11(g, "rebase-merge")) || existsSync10(join11(g, "rebase-apply"))) return "rebase";
1781
+ if (existsSync10(join11(g, "MERGE_HEAD"))) return "merge";
1619
1782
  return null;
1620
1783
  }
1621
1784
 
@@ -1640,8 +1803,8 @@ function reportGitleaksProbe(section2) {
1640
1803
  }
1641
1804
  }
1642
1805
  function reportGitlinks(section2) {
1643
- const sharedDir = join13(REPO_HOME, "shared");
1644
- if (existsSync11(sharedDir)) {
1806
+ const sharedDir = join14(REPO_HOME, "shared");
1807
+ if (existsSync12(sharedDir)) {
1645
1808
  const gitlinks = findGitlinks(sharedDir);
1646
1809
  for (const p of gitlinks) {
1647
1810
  const rel = relative2(REPO_HOME, p);
@@ -1697,8 +1860,8 @@ function reportRebaseState(section2) {
1697
1860
 
1698
1861
  // src/commands.doctor.checks.backups.ts
1699
1862
  init_color();
1700
- import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync5 } from "node:fs";
1701
- import { join as join14 } from "node:path";
1863
+ import { existsSync as existsSync13, lstatSync as lstatSync6, readdirSync as readdirSync5 } from "node:fs";
1864
+ import { join as join15 } from "node:path";
1702
1865
  init_config();
1703
1866
  var TS_SHAPE2 = /^\d{8}-\d{6}(-\d+)?$/;
1704
1867
  function safeReaddir(dir) {
@@ -1714,8 +1877,8 @@ var BYTES_PER_MB = 1024 * 1024;
1714
1877
  function dirSizeBytes(dir) {
1715
1878
  let bytes = 0;
1716
1879
  for (const entry of safeReaddir(dir)) {
1717
- const full = join14(dir, entry);
1718
- const st = lstatSync5(full, { throwIfNoEntry: false });
1880
+ const full = join15(dir, entry);
1881
+ const st = lstatSync6(full, { throwIfNoEntry: false });
1719
1882
  if (!st) continue;
1720
1883
  if (st.isSymbolicLink()) continue;
1721
1884
  if (st.isDirectory()) bytes += dirSizeBytes(full);
@@ -1725,11 +1888,11 @@ function dirSizeBytes(dir) {
1725
1888
  }
1726
1889
  function totalSizeMb(backupBase, dirs) {
1727
1890
  let bytes = 0;
1728
- for (const name of dirs) bytes += dirSizeBytes(join14(backupBase, name));
1891
+ for (const name of dirs) bytes += dirSizeBytes(join15(backupBase, name));
1729
1892
  return bytes / BYTES_PER_MB;
1730
1893
  }
1731
1894
  function reportBackupsCheck(section2, backupBase = BACKUP_BASE) {
1732
- if (!existsSync12(backupBase)) return;
1895
+ if (!existsSync13(backupBase)) return;
1733
1896
  const dirs = safeReaddir(backupBase).filter((n) => TS_SHAPE2.test(n));
1734
1897
  const count = dirs.length;
1735
1898
  const sizeMb = totalSizeMb(backupBase, dirs);
@@ -1743,8 +1906,8 @@ function reportBackupsCheck(section2, backupBase = BACKUP_BASE) {
1743
1906
 
1744
1907
  // src/commands.doctor.check-schema.ts
1745
1908
  init_color();
1746
- import { existsSync as existsSync13 } from "node:fs";
1747
- import { join as join15 } from "node:path";
1909
+ import { existsSync as existsSync14 } from "node:fs";
1910
+ import { join as join16 } from "node:path";
1748
1911
  init_config();
1749
1912
 
1750
1913
  // src/http-fetch.ts
@@ -1781,8 +1944,8 @@ function fetchSchemaKeys() {
1781
1944
  }
1782
1945
  }
1783
1946
  function reportCheckSchema(section2) {
1784
- const settingsPath = join15(CLAUDE_HOME, "settings.json");
1785
- if (!existsSync13(settingsPath)) {
1947
+ const settingsPath = join16(CLAUDE_HOME, "settings.json");
1948
+ if (!existsSync14(settingsPath)) {
1786
1949
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json to check`);
1787
1950
  return;
1788
1951
  }
@@ -1812,18 +1975,18 @@ function reportCheckSchema(section2) {
1812
1975
  init_color();
1813
1976
  import { randomBytes } from "node:crypto";
1814
1977
  import { execFileSync as execFileSync6 } from "node:child_process";
1815
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readdirSync as readdirSync7, rmSync as rmSync6 } from "node:fs";
1978
+ import { existsSync as existsSync16, mkdirSync as mkdirSync4, readdirSync as readdirSync7, rmSync as rmSync7 } from "node:fs";
1816
1979
  import { homedir as homedir4 } from "node:os";
1817
- import { join as join19 } from "node:path";
1980
+ import { join as join20 } from "node:path";
1818
1981
 
1819
1982
  // src/commands.doctor.check-shared.scan.ts
1820
1983
  init_color();
1821
- import { join as join17 } from "node:path";
1984
+ import { join as join18 } from "node:path";
1822
1985
  init_config();
1823
1986
  init_push_gitleaks();
1824
1987
  function scrubPath(logical, sid, logicalToEncoded) {
1825
1988
  const encoded = logicalToEncoded.get(logical) ?? logical;
1826
- return join17(CLAUDE_HOME, "projects", encoded, `${sid}.jsonl`);
1989
+ return join18(CLAUDE_HOME, "projects", encoded, `${sid}.jsonl`);
1827
1990
  }
1828
1991
  function reportSessionFindings(section2, bySession) {
1829
1992
  for (const [sid, counts] of bySession) {
@@ -1915,21 +2078,21 @@ init_config();
1915
2078
  init_utils();
1916
2079
  init_utils_fs();
1917
2080
  init_utils_json();
1918
- import { cpSync as cpSync3, existsSync as existsSync14, mkdirSync as mkdirSync3, readdirSync as readdirSync6, rmSync as rmSync5, statSync as statSync4 } from "node:fs";
1919
- import { join as join18, relative as relative3, sep } from "node:path";
2081
+ import { cpSync as cpSync4, existsSync as existsSync15, mkdirSync as mkdirSync3, readdirSync as readdirSync6, rmSync as rmSync6, statSync as statSync4 } from "node:fs";
2082
+ import { join as join19, relative as relative3, sep as sep2 } from "node:path";
1920
2083
  function copyDir(src, dst) {
1921
- rmSync5(dst, { recursive: true, force: true });
1922
- cpSync3(src, dst, { recursive: true, force: true });
2084
+ rmSync6(dst, { recursive: true, force: true });
2085
+ cpSync4(src, dst, { recursive: true, force: true });
1923
2086
  }
1924
2087
  function copyDirJsonlOnly(src, dst) {
1925
- rmSync5(dst, { recursive: true, force: true });
1926
- cpSync3(src, dst, {
2088
+ rmSync6(dst, { recursive: true, force: true });
2089
+ cpSync4(src, dst, {
1927
2090
  recursive: true,
1928
2091
  force: true,
1929
2092
  filter: (srcPath) => {
1930
2093
  const rel = relative3(src, srcPath);
1931
2094
  if (rel === "") return true;
1932
- if (rel.split(sep).length > 1) return true;
2095
+ if (rel.split(sep2).length > 1) return true;
1933
2096
  if (statSync4(srcPath).isDirectory()) return true;
1934
2097
  if (srcPath.endsWith(".jsonl")) return true;
1935
2098
  log(`skip ${rel}: extension not in allowlist`);
@@ -1946,15 +2109,15 @@ function remapPull(ts, opts = {}) {
1946
2109
  let unmapped = 0;
1947
2110
  const pulled = [];
1948
2111
  const wouldPull = [];
1949
- const mapPath = join18(REPO_HOME, "path-map.json");
1950
- const repoProjects = join18(REPO_HOME, "shared", "projects");
1951
- if (!existsSync14(mapPath) || !existsSync14(repoProjects)) {
2112
+ const mapPath = join19(REPO_HOME, "path-map.json");
2113
+ const repoProjects = join19(REPO_HOME, "shared", "projects");
2114
+ if (!existsSync15(mapPath) || !existsSync15(repoProjects)) {
1952
2115
  const text = "no path-map or repo projects dir; skipping session remap";
1953
2116
  emitPreview(opts.onPreview, { kind: "note", text }, text);
1954
2117
  return { unmapped: 0, pulled, wouldPull };
1955
2118
  }
1956
2119
  const map = readJson(mapPath);
1957
- const localProjects = join18(CLAUDE_HOME, "projects");
2120
+ const localProjects = join19(CLAUDE_HOME, "projects");
1958
2121
  if (!dryRun) mkdirSync3(localProjects, { recursive: true });
1959
2122
  for (const [logical, hosts] of Object.entries(map.projects)) {
1960
2123
  assertSafeLogical(logical);
@@ -1963,9 +2126,9 @@ function remapPull(ts, opts = {}) {
1963
2126
  unmapped++;
1964
2127
  continue;
1965
2128
  }
1966
- const src = join18(repoProjects, logical);
1967
- if (!existsSync14(src)) continue;
1968
- const dst = join18(localProjects, encodePath(localPath));
2129
+ const src = join19(repoProjects, logical);
2130
+ if (!existsSync15(src)) continue;
2131
+ const dst = join19(localProjects, encodePath(localPath));
1969
2132
  if (dryRun) {
1970
2133
  wouldPull.push(logical);
1971
2134
  emitPreview(
@@ -2010,16 +2173,16 @@ function remapPush(ts, opts = {}) {
2010
2173
  let unmapped = 0;
2011
2174
  const pushed = [];
2012
2175
  const wouldPush = [];
2013
- const mapPath = join18(REPO_HOME, "path-map.json");
2014
- if (!existsSync14(mapPath)) {
2176
+ const mapPath = join19(REPO_HOME, "path-map.json");
2177
+ if (!existsSync15(mapPath)) {
2015
2178
  log("no path-map.json; skipping session export");
2016
2179
  return { unmapped: 0, collisions: 0, pushed, wouldPush };
2017
2180
  }
2018
2181
  const map = readJson(mapPath);
2019
- const localProjects = join18(CLAUDE_HOME, "projects");
2020
- const repoProjects = join18(REPO_HOME, "shared", "projects");
2182
+ const localProjects = join19(CLAUDE_HOME, "projects");
2183
+ const repoProjects = join19(REPO_HOME, "shared", "projects");
2021
2184
  const reverse = buildReverseMap(map);
2022
- if (!existsSync14(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
2185
+ if (!existsSync15(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
2023
2186
  if (!dryRun) mkdirSync3(repoProjects, { recursive: true });
2024
2187
  for (const dir of readdirSync6(localProjects)) {
2025
2188
  const logical = reverse.get(dir);
@@ -2027,13 +2190,13 @@ function remapPush(ts, opts = {}) {
2027
2190
  unmapped++;
2028
2191
  continue;
2029
2192
  }
2030
- const repoDst = join18(repoProjects, logical);
2193
+ const repoDst = join19(repoProjects, logical);
2031
2194
  if (dryRun) {
2032
2195
  wouldPush.push(logical);
2033
2196
  continue;
2034
2197
  }
2035
2198
  backupRepoWrite(repoDst, ts, REPO_HOME);
2036
- copyDirJsonlOnly(join18(localProjects, dir), repoDst);
2199
+ copyDirJsonlOnly(join19(localProjects, dir), repoDst);
2037
2200
  pushed.push(logical);
2038
2201
  }
2039
2202
  return { unmapped, collisions: 0, pushed, wouldPush };
@@ -2045,8 +2208,8 @@ init_utils_json();
2045
2208
  function buildScanTree(tmpRoot) {
2046
2209
  const logicalToEncoded = /* @__PURE__ */ new Map();
2047
2210
  let staged = 0;
2048
- const mapPath = join19(REPO_HOME, "path-map.json");
2049
- if (!existsSync15(mapPath)) return { logicalToEncoded, staged, malformed: false };
2211
+ const mapPath = join20(REPO_HOME, "path-map.json");
2212
+ if (!existsSync16(mapPath)) return { logicalToEncoded, staged, malformed: false };
2050
2213
  let map;
2051
2214
  try {
2052
2215
  map = readJson(mapPath);
@@ -2063,12 +2226,12 @@ function buildScanTree(tmpRoot) {
2063
2226
  if (!p || p === "TBD") continue;
2064
2227
  reverse.set(encodePath(p), logical);
2065
2228
  }
2066
- const localProjects = join19(CLAUDE_HOME, "projects");
2067
- if (!existsSync15(localProjects)) return { logicalToEncoded, staged, malformed: false };
2229
+ const localProjects = join20(CLAUDE_HOME, "projects");
2230
+ if (!existsSync16(localProjects)) return { logicalToEncoded, staged, malformed: false };
2068
2231
  for (const dir of readdirSync7(localProjects)) {
2069
2232
  const logical = reverse.get(dir);
2070
2233
  if (!logical) continue;
2071
- copyDirJsonlOnly(join19(localProjects, dir), join19(tmpRoot, "shared", "projects", logical));
2234
+ copyDirJsonlOnly(join20(localProjects, dir), join20(tmpRoot, "shared", "projects", logical));
2072
2235
  logicalToEncoded.set(logical, dir);
2073
2236
  staged++;
2074
2237
  }
@@ -2099,11 +2262,11 @@ function ensureGitleaksReady(section2, gitleaksReady) {
2099
2262
  }
2100
2263
  function reportCheckShared(section2, gitleaksReady) {
2101
2264
  if (!ensureGitleaksReady(section2, gitleaksReady)) return;
2102
- const cacheDir = join19(homedir4(), ".cache", "claude-nomad");
2265
+ const cacheDir = join20(homedir4(), ".cache", "claude-nomad");
2103
2266
  mkdirSync4(cacheDir, { recursive: true });
2104
2267
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes(4).toString("hex")}`;
2105
- const reportPath = join19(cacheDir, `check-shared-${stamp}.json`);
2106
- const tmpRoot = join19(cacheDir, `check-shared-tree-${stamp}`);
2268
+ const reportPath = join20(cacheDir, `check-shared-${stamp}.json`);
2269
+ const tmpRoot = join20(cacheDir, `check-shared-tree-${stamp}`);
2107
2270
  try {
2108
2271
  const { logicalToEncoded, staged, malformed } = buildScanTree(tmpRoot);
2109
2272
  if (malformed) {
@@ -2117,15 +2280,15 @@ function reportCheckShared(section2, gitleaksReady) {
2117
2280
  }
2118
2281
  scanAndReport(section2, tmpRoot, staged, logicalToEncoded);
2119
2282
  } finally {
2120
- rmSync6(reportPath, { force: true });
2121
- rmSync6(tmpRoot, { recursive: true, force: true });
2283
+ rmSync7(reportPath, { force: true });
2284
+ rmSync7(tmpRoot, { recursive: true, force: true });
2122
2285
  }
2123
2286
  }
2124
2287
 
2125
2288
  // src/commands.doctor.checks.hooks.scope.ts
2126
2289
  init_color();
2127
- import { existsSync as existsSync16, readFileSync as readFileSync5, readdirSync as readdirSync8, realpathSync } from "node:fs";
2128
- import { dirname as dirname2, extname, join as join20 } from "node:path";
2290
+ import { existsSync as existsSync17, readFileSync as readFileSync5, readdirSync as readdirSync8, realpathSync as realpathSync2 } from "node:fs";
2291
+ import { dirname as dirname2, extname, join as join21 } from "node:path";
2129
2292
  init_config();
2130
2293
  function typeFromPackageJson(pkgPath) {
2131
2294
  try {
@@ -2141,14 +2304,14 @@ function effectiveType(hookPath) {
2141
2304
  if (ext === ".cjs") return "cjs";
2142
2305
  let real;
2143
2306
  try {
2144
- real = realpathSync(hookPath);
2307
+ real = realpathSync2(hookPath);
2145
2308
  } catch {
2146
2309
  return null;
2147
2310
  }
2148
2311
  let dir = dirname2(real);
2149
2312
  for (; ; ) {
2150
- const pkg = join20(dir, "package.json");
2151
- if (existsSync16(pkg)) return typeFromPackageJson(pkg);
2313
+ const pkg = join21(dir, "package.json");
2314
+ if (existsSync17(pkg)) return typeFromPackageJson(pkg);
2152
2315
  const parent = dirname2(dir);
2153
2316
  if (parent === dir) return "cjs";
2154
2317
  dir = parent;
@@ -2190,15 +2353,15 @@ function safeRead(path) {
2190
2353
  }
2191
2354
  }
2192
2355
  function reportHookScopeCheck(section2) {
2193
- const hooksDir = join20(CLAUDE_HOME, "hooks");
2194
- if (!existsSync16(hooksDir)) {
2356
+ const hooksDir = join21(CLAUDE_HOME, "hooks");
2357
+ if (!existsSync17(hooksDir)) {
2195
2358
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/hooks; skipping module-scope check`);
2196
2359
  return;
2197
2360
  }
2198
2361
  let anyWarn = false;
2199
2362
  for (const name of safeReaddir2(hooksDir)) {
2200
2363
  if (extname(name) !== ".js") continue;
2201
- const abs = join20(hooksDir, name);
2364
+ const abs = join21(hooksDir, name);
2202
2365
  const eff = effectiveType(abs);
2203
2366
  if (eff === null) continue;
2204
2367
  const src = safeRead(abs);
@@ -2218,8 +2381,8 @@ function reportHookScopeCheck(section2) {
2218
2381
 
2219
2382
  // src/commands.doctor.checks.hooks.ts
2220
2383
  init_color();
2221
- import { existsSync as existsSync17 } from "node:fs";
2222
- import { join as join21 } from "node:path";
2384
+ import { existsSync as existsSync18 } from "node:fs";
2385
+ import { join as join22 } from "node:path";
2223
2386
  init_config();
2224
2387
  function expandHome(token) {
2225
2388
  return token.replace(/^\$\{HOME\}/, HOME).replace(/^\$HOME/, HOME).replace(/^~/, HOME);
@@ -2257,7 +2420,7 @@ function checkEventGroups(section2, event, groups) {
2257
2420
  for (const group of groups) {
2258
2421
  for (const cmd of commandsFromGroup(group)) {
2259
2422
  for (const resolved of claudePathsIn(cmd)) {
2260
- if (existsSync17(resolved)) continue;
2423
+ if (existsSync18(resolved)) continue;
2261
2424
  addItem(
2262
2425
  section2,
2263
2426
  `${red(failGlyph)} hooks/${event}: command target missing: ${resolved} (run nomad pull)`
@@ -2270,8 +2433,8 @@ function checkEventGroups(section2, event, groups) {
2270
2433
  return anyFail;
2271
2434
  }
2272
2435
  function reportHooksTargetCheck(section2) {
2273
- const settingsPath = join21(CLAUDE_HOME, "settings.json");
2274
- if (!existsSync17(settingsPath)) {
2436
+ const settingsPath = join22(CLAUDE_HOME, "settings.json");
2437
+ if (!existsSync18(settingsPath)) {
2275
2438
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping hook target check`);
2276
2439
  return;
2277
2440
  }
@@ -2294,12 +2457,12 @@ function reportHooksTargetCheck(section2) {
2294
2457
 
2295
2458
  // src/commands.doctor.checks.hooks.preserve-symlinks.ts
2296
2459
  init_color();
2297
- import { existsSync as existsSync19, readFileSync as readFileSync6 } from "node:fs";
2298
- import { join as join23 } from "node:path";
2460
+ import { existsSync as existsSync20, readFileSync as readFileSync6 } from "node:fs";
2461
+ import { join as join24 } from "node:path";
2299
2462
 
2300
2463
  // src/commands.doctor.checks.hooks.preserve-symlinks.probe.ts
2301
- import { closeSync as closeSync2, existsSync as existsSync18, openSync as openSync2, readSync, realpathSync as realpathSync2 } from "node:fs";
2302
- import { dirname as dirname3, join as join22, resolve as resolve2 } from "node:path";
2464
+ import { closeSync as closeSync2, existsSync as existsSync19, openSync as openSync2, readSync, realpathSync as realpathSync3 } from "node:fs";
2465
+ import { dirname as dirname3, join as join23, resolve as resolve2 } from "node:path";
2303
2466
  function suppressedRanges(src) {
2304
2467
  const ranges = [];
2305
2468
  const re = /\/\*[\s\S]*?\*\/|\/\/[^\n]*|'[^']*'|"[^"]*"|`[^`]*`/g;
@@ -2331,19 +2494,19 @@ function topRelativeSpecifiers(src) {
2331
2494
  }
2332
2495
  function specifierIsMissing(specifier, baseDir) {
2333
2496
  const base = resolve2(baseDir, specifier);
2334
- if (existsSync18(base)) return false;
2497
+ if (existsSync19(base)) return false;
2335
2498
  for (const ext of [".js", ".cjs", ".mjs"]) {
2336
- if (existsSync18(base + ext)) return false;
2499
+ if (existsSync19(base + ext)) return false;
2337
2500
  }
2338
2501
  for (const idx of ["index.js", "index.cjs", "index.mjs"]) {
2339
- if (existsSync18(join22(base, idx))) return false;
2502
+ if (existsSync19(join23(base, idx))) return false;
2340
2503
  }
2341
2504
  return true;
2342
2505
  }
2343
2506
  function relativeRequireTargetsBroken(scriptPath) {
2344
2507
  let realPath;
2345
2508
  try {
2346
- realPath = realpathSync2(scriptPath);
2509
+ realPath = realpathSync3(scriptPath);
2347
2510
  } catch {
2348
2511
  return false;
2349
2512
  }
@@ -2390,8 +2553,8 @@ function commandTokens(command) {
2390
2553
  return tokens;
2391
2554
  }
2392
2555
  function readPathMapSafe() {
2393
- const mapPath = join23(REPO_HOME, "path-map.json");
2394
- if (!existsSync19(mapPath)) return { projects: {} };
2556
+ const mapPath = join24(REPO_HOME, "path-map.json");
2557
+ if (!existsSync20(mapPath)) return { projects: {} };
2395
2558
  try {
2396
2559
  return JSON.parse(readFileSync6(mapPath, "utf8"));
2397
2560
  } catch {
@@ -2464,8 +2627,8 @@ function checkEventForPreserveSymlinks(section2, event, groups, sharedLinkNames)
2464
2627
  return anyWarn;
2465
2628
  }
2466
2629
  function reportPreserveSymlinksCheck(section2) {
2467
- const settingsPath = join23(CLAUDE_HOME, "settings.json");
2468
- if (!existsSync19(settingsPath)) {
2630
+ const settingsPath = join24(CLAUDE_HOME, "settings.json");
2631
+ if (!existsSync20(settingsPath)) {
2469
2632
  addItem(
2470
2633
  section2,
2471
2634
  `${dim(infoGlyph)} no ~/.claude/settings.json; skipping preserve-symlinks-main check`
@@ -2611,8 +2774,8 @@ function reportNodeEngineCheck(section2) {
2611
2774
  // src/commands.doctor.gitleaks-version.ts
2612
2775
  init_color();
2613
2776
  import { execFileSync as execFileSync7 } from "node:child_process";
2614
- import { existsSync as existsSync20 } from "node:fs";
2615
- import { join as join24 } from "node:path";
2777
+ import { existsSync as existsSync21 } from "node:fs";
2778
+ import { join as join25 } from "node:path";
2616
2779
  init_config();
2617
2780
  var SEMVER_MAJOR_MINOR = /^(\d+)\.(\d+)\.\d+$/;
2618
2781
  var GITLEAKS_TIMEOUT_MS = 5e3;
@@ -2621,7 +2784,7 @@ function majorMinorOf(value) {
2621
2784
  return m === null ? null : [m[1], m[2]];
2622
2785
  }
2623
2786
  function readGitleaksVersion(run, tomlExists) {
2624
- const tomlPath = join24(REPO_HOME, ".gitleaks.toml");
2787
+ const tomlPath = join25(REPO_HOME, ".gitleaks.toml");
2625
2788
  const args = ["version"];
2626
2789
  if (tomlExists(tomlPath)) args.push("--config", tomlPath);
2627
2790
  try {
@@ -2633,7 +2796,7 @@ function readGitleaksVersion(run, tomlExists) {
2633
2796
  return null;
2634
2797
  }
2635
2798
  }
2636
- function reportGitleaksVersionCheck(section2, run = execFileSync7, tomlExists = existsSync20) {
2799
+ function reportGitleaksVersionCheck(section2, run = execFileSync7, tomlExists = existsSync21) {
2637
2800
  const raw = readGitleaksVersion(run, tomlExists);
2638
2801
  if (raw === null) return;
2639
2802
  const local = majorMinorOf(raw);
@@ -2833,8 +2996,8 @@ function cmdDoctor(opts = {}) {
2833
2996
  reportHostAndPaths(host);
2834
2997
  reportRepoState(host);
2835
2998
  const links = section("Shared links");
2836
- const mapPath = join25(REPO_HOME, "path-map.json");
2837
- const rawMap = existsSync21(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
2999
+ const mapPath = join26(REPO_HOME, "path-map.json");
3000
+ const rawMap = existsSync22(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
2838
3001
  const map = rawMap ?? { projects: {} };
2839
3002
  reportSharedLinks(links, map);
2840
3003
  const hooksScan = section("Hook targets");
@@ -2888,8 +3051,8 @@ function cmdDoctor(opts = {}) {
2888
3051
  // src/commands.drop-session.ts
2889
3052
  init_config();
2890
3053
  import { execFileSync as execFileSync12 } from "node:child_process";
2891
- import { existsSync as existsSync23, readdirSync as readdirSync9, statSync as statSync5 } from "node:fs";
2892
- import { join as join28, relative as relative4 } from "node:path";
3054
+ import { existsSync as existsSync24, readdirSync as readdirSync9, statSync as statSync5 } from "node:fs";
3055
+ import { join as join29, relative as relative4 } from "node:path";
2893
3056
 
2894
3057
  // src/commands.drop-session.git.ts
2895
3058
  init_config();
@@ -2932,8 +3095,8 @@ function isInIndex(rel) {
2932
3095
  init_config();
2933
3096
  init_utils();
2934
3097
  init_utils_json();
2935
- import { existsSync as existsSync22 } from "node:fs";
2936
- import { join as join26 } from "node:path";
3098
+ import { existsSync as existsSync23 } from "node:fs";
3099
+ import { join as join27 } from "node:path";
2937
3100
  var SHARED_PROJECT_LOGICAL = /^shared\/projects\/([^/]+)\//;
2938
3101
  function reportScrubHint(id, matches) {
2939
3102
  const live = resolveLiveTranscript(id, matches);
@@ -2949,16 +3112,16 @@ function reportScrubHint(id, matches) {
2949
3112
  }
2950
3113
  function resolveLiveTranscript(id, matches) {
2951
3114
  try {
2952
- const mapPath = join26(REPO_HOME, "path-map.json");
2953
- if (!existsSync22(mapPath)) return null;
3115
+ const mapPath = join27(REPO_HOME, "path-map.json");
3116
+ if (!existsSync23(mapPath)) return null;
2954
3117
  const projects = readJson(mapPath).projects;
2955
3118
  for (const rel of matches) {
2956
3119
  const logical = SHARED_PROJECT_LOGICAL.exec(rel)?.[1];
2957
3120
  if (logical === void 0) continue;
2958
3121
  const abs = projects[logical]?.[HOST];
2959
3122
  if (abs === void 0) continue;
2960
- const live = join26(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
2961
- if (existsSync22(live)) return live;
3123
+ const live = join27(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
3124
+ if (existsSync23(live)) return live;
2962
3125
  }
2963
3126
  return null;
2964
3127
  } catch {
@@ -2973,8 +3136,8 @@ init_utils();
2973
3136
  init_config();
2974
3137
  init_utils();
2975
3138
  import { closeSync as closeSync3, mkdirSync as mkdirSync5, openSync as openSync3, readFileSync as readFileSync9, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
2976
- import { dirname as dirname4, join as join27 } from "node:path";
2977
- var LOCK_PATH = join27(HOME, ".cache", "claude-nomad", "nomad.lock");
3139
+ import { dirname as dirname4, join as join28 } from "node:path";
3140
+ var LOCK_PATH = join28(HOME, ".cache", "claude-nomad", "nomad.lock");
2978
3141
  function acquireLock(verb) {
2979
3142
  mkdirSync5(dirname4(LOCK_PATH), { recursive: true });
2980
3143
  try {
@@ -3084,12 +3247,12 @@ function cmdDropSession(id) {
3084
3247
  fail(`invalid session id: ${id}`);
3085
3248
  process.exit(1);
3086
3249
  }
3087
- if (!existsSync23(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3250
+ if (!existsSync24(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3088
3251
  const handle = acquireLock("drop-session");
3089
3252
  if (handle === null) process.exit(0);
3090
3253
  try {
3091
- const repoProjects = join28(REPO_HOME, "shared", "projects");
3092
- if (!existsSync23(repoProjects)) {
3254
+ const repoProjects = join29(REPO_HOME, "shared", "projects");
3255
+ if (!existsSync24(repoProjects)) {
3093
3256
  throw new NomadFatal(`no staged session matches ${id}`);
3094
3257
  }
3095
3258
  const matches = collectMatches(repoProjects, id);
@@ -3111,12 +3274,12 @@ function cmdDropSession(id) {
3111
3274
  function collectMatches(repoProjects, id) {
3112
3275
  const matches = [];
3113
3276
  for (const logical of readdirSync9(repoProjects)) {
3114
- const candidate = join28(repoProjects, logical, `${id}.jsonl`);
3115
- if (existsSync23(candidate)) {
3277
+ const candidate = join29(repoProjects, logical, `${id}.jsonl`);
3278
+ if (existsSync24(candidate)) {
3116
3279
  matches.push(relative4(REPO_HOME, candidate));
3117
3280
  }
3118
- const dir = join28(repoProjects, logical, id);
3119
- if (existsSync23(dir) && statSync5(dir).isDirectory()) {
3281
+ const dir = join29(repoProjects, logical, id);
3282
+ if (existsSync24(dir) && statSync5(dir).isDirectory()) {
3120
3283
  const dirRel = relative4(REPO_HOME, dir);
3121
3284
  const staged = expandStagedDir(dirRel);
3122
3285
  if (staged.length > 0) matches.push(...staged);
@@ -3152,20 +3315,20 @@ function unstageOne(rel) {
3152
3315
 
3153
3316
  // src/commands.redact.ts
3154
3317
  init_config();
3155
- import { existsSync as existsSync25, statSync as statSync7 } from "node:fs";
3156
- import { dirname as dirname5, join as join30 } from "node:path";
3318
+ import { existsSync as existsSync26, statSync as statSync7 } from "node:fs";
3319
+ import { dirname as dirname5, join as join31 } from "node:path";
3157
3320
 
3158
3321
  // src/commands.redact.subtree.ts
3159
- import { existsSync as existsSync24, lstatSync as lstatSync6, readFileSync as readFileSync10, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
3160
- import { join as join29 } from "node:path";
3322
+ import { existsSync as existsSync25, lstatSync as lstatSync7, readFileSync as readFileSync10, readdirSync as readdirSync10, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
3323
+ import { join as join30 } from "node:path";
3161
3324
  init_utils_fs();
3162
3325
  function collectFiles(dir, out) {
3163
- if (!existsSync24(dir)) return;
3164
- const st = lstatSync6(dir);
3326
+ if (!existsSync25(dir)) return;
3327
+ const st = lstatSync7(dir);
3165
3328
  if (!st.isDirectory()) return;
3166
3329
  for (const entry of readdirSync10(dir)) {
3167
- const abs = join29(dir, entry);
3168
- const lst = lstatSync6(abs);
3330
+ const abs = join30(dir, entry);
3331
+ const lst = lstatSync7(abs);
3169
3332
  if (lst.isSymbolicLink()) continue;
3170
3333
  if (lst.isDirectory()) {
3171
3334
  collectFiles(abs, out);
@@ -3214,14 +3377,14 @@ init_utils_json();
3214
3377
  init_utils();
3215
3378
  function resolveLiveTranscript2(id) {
3216
3379
  try {
3217
- const mapPath = join30(REPO_HOME, "path-map.json");
3218
- if (!existsSync25(mapPath)) return null;
3380
+ const mapPath = join31(REPO_HOME, "path-map.json");
3381
+ if (!existsSync26(mapPath)) return null;
3219
3382
  const projects = readJson(mapPath).projects;
3220
3383
  for (const hostMap of Object.values(projects)) {
3221
3384
  const abs = hostMap[HOST];
3222
3385
  if (abs === void 0) continue;
3223
- const live = join30(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
3224
- if (existsSync25(live)) return live;
3386
+ const live = join31(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
3387
+ if (existsSync26(live)) return live;
3225
3388
  }
3226
3389
  return null;
3227
3390
  } catch {
@@ -3239,17 +3402,17 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
3239
3402
  fail(`invalid session id: ${id}`);
3240
3403
  process.exit(1);
3241
3404
  }
3242
- if (!existsSync25(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3405
+ if (!existsSync26(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3243
3406
  const handle = acquireLock("redact");
3244
3407
  if (handle === null) process.exit(0);
3245
3408
  try {
3246
3409
  const localPath = resolveLiveTranscript2(id);
3247
- if (localPath === null || !existsSync25(localPath)) {
3410
+ if (localPath === null || !existsSync26(localPath)) {
3248
3411
  fail(`could not resolve local transcript for session ${id} on this host`);
3249
3412
  process.exitCode = 1;
3250
3413
  return;
3251
3414
  }
3252
- const sessionDir = join30(dirname5(localPath), id);
3415
+ const sessionDir = join31(dirname5(localPath), id);
3253
3416
  const subtreeFiles = listSubtreeFiles(sessionDir);
3254
3417
  const subtreeMtime = newestSubtreeMtimeMs(localPath, subtreeFiles, (p) => statSync7(p).mtimeMs);
3255
3418
  if (isRecentlyModified(subtreeMtime, nowMs())) {
@@ -3302,8 +3465,8 @@ ${lines}`);
3302
3465
  }
3303
3466
 
3304
3467
  // src/commands.pull.ts
3305
- import { existsSync as existsSync33, mkdirSync as mkdirSync8 } from "node:fs";
3306
- import { join as join39 } from "node:path";
3468
+ import { existsSync as existsSync34, mkdirSync as mkdirSync8 } from "node:fs";
3469
+ import { join as join40 } from "node:path";
3307
3470
 
3308
3471
  // src/commands.push.sections.ts
3309
3472
  init_color();
@@ -3391,8 +3554,8 @@ init_config();
3391
3554
 
3392
3555
  // src/extras-sync.ts
3393
3556
  init_config();
3394
- import { existsSync as existsSync28 } from "node:fs";
3395
- import { join as join33 } from "node:path";
3557
+ import { existsSync as existsSync29 } from "node:fs";
3558
+ import { join as join34 } from "node:path";
3396
3559
 
3397
3560
  // src/extras-sync.diff.ts
3398
3561
  init_utils();
@@ -3431,8 +3594,8 @@ function listDivergingFiles(a, b) {
3431
3594
 
3432
3595
  // src/extras-sync.core.ts
3433
3596
  init_config();
3434
- import { cpSync as cpSync4, existsSync as existsSync26, rmSync as rmSync7 } from "node:fs";
3435
- import { join as join31 } from "node:path";
3597
+ import { cpSync as cpSync5, existsSync as existsSync27, rmSync as rmSync8 } from "node:fs";
3598
+ import { join as join32 } from "node:path";
3436
3599
 
3437
3600
  // src/extras-sync.guards.ts
3438
3601
  init_utils();
@@ -3455,9 +3618,9 @@ function assertSafeLocalRoot(localRoot, logical) {
3455
3618
  init_utils();
3456
3619
  init_utils_json();
3457
3620
  function loadValidatedExtras(opts) {
3458
- const mapPath = join31(REPO_HOME, "path-map.json");
3459
- const repoExtras = join31(REPO_HOME, "shared", "extras");
3460
- if (!existsSync26(mapPath) || opts.requireRepoExtras === true && !existsSync26(repoExtras)) {
3621
+ const mapPath = join32(REPO_HOME, "path-map.json");
3622
+ const repoExtras = join32(REPO_HOME, "shared", "extras");
3623
+ if (!existsSync27(mapPath) || opts.requireRepoExtras === true && !existsSync27(repoExtras)) {
3461
3624
  if (opts.missingMsg !== void 0) log(opts.missingMsg);
3462
3625
  return null;
3463
3626
  }
@@ -3489,8 +3652,8 @@ function* eachExtrasTarget(v, counts) {
3489
3652
  }
3490
3653
  }
3491
3654
  function copyExtras(src, dst) {
3492
- rmSync7(dst, { recursive: true, force: true });
3493
- cpSync4(src, dst, { recursive: true, force: true, verbatimSymlinks: true });
3655
+ rmSync8(dst, { recursive: true, force: true });
3656
+ cpSync5(src, dst, { recursive: true, force: true, verbatimSymlinks: true });
3494
3657
  }
3495
3658
 
3496
3659
  // src/extras-sync.ts
@@ -3499,8 +3662,8 @@ init_utils_json();
3499
3662
 
3500
3663
  // src/extras-sync.remap.ts
3501
3664
  init_config();
3502
- import { existsSync as existsSync27, mkdirSync as mkdirSync6 } from "node:fs";
3503
- import { join as join32 } from "node:path";
3665
+ import { existsSync as existsSync28, mkdirSync as mkdirSync6 } from "node:fs";
3666
+ import { join as join33 } from "node:path";
3504
3667
  init_utils_fs();
3505
3668
  function runExtrasOp(v, dryRun, paths, backup) {
3506
3669
  const counts = { unmapped: 0, skipped: 0 };
@@ -3508,7 +3671,7 @@ function runExtrasOp(v, dryRun, paths, backup) {
3508
3671
  const would = [];
3509
3672
  for (const t of eachExtrasTarget(v, counts)) {
3510
3673
  const { src, dst } = paths(t);
3511
- if (!existsSync27(src)) continue;
3674
+ if (!existsSync28(src)) continue;
3512
3675
  const item = `${t.logical}/${t.dirname}`;
3513
3676
  if (dryRun) {
3514
3677
  would.push(item);
@@ -3524,14 +3687,14 @@ function remapExtrasPush(ts, opts = {}) {
3524
3687
  const dryRun = opts.dryRun === true;
3525
3688
  const v = loadValidatedExtras({ missingMsg: "no path-map.json; skipping extras push" });
3526
3689
  if (v === null) return { unmapped: 0, skipped: 0, pushed: [], wouldPush: [] };
3527
- const repoExtras = join32(REPO_HOME, "shared", "extras");
3690
+ const repoExtras = join33(REPO_HOME, "shared", "extras");
3528
3691
  if (!dryRun) mkdirSync6(repoExtras, { recursive: true });
3529
3692
  const { unmapped, skipped, done, would } = runExtrasOp(
3530
3693
  v,
3531
3694
  dryRun,
3532
3695
  ({ localRoot, logical, dirname: dirname7 }) => ({
3533
- src: join32(localRoot, dirname7),
3534
- dst: join32(repoExtras, logical, dirname7)
3696
+ src: join33(localRoot, dirname7),
3697
+ dst: join33(repoExtras, logical, dirname7)
3535
3698
  }),
3536
3699
  (dst) => backupRepoWrite(dst, ts, REPO_HOME)
3537
3700
  );
@@ -3544,13 +3707,13 @@ function remapExtrasPull(ts, opts = {}) {
3544
3707
  missingMsg: "no path-map or repo extras dir; skipping extras remap"
3545
3708
  });
3546
3709
  if (v === null) return { unmapped: 0, skipped: 0, pulled: [], wouldPull: [] };
3547
- const repoExtras = join32(REPO_HOME, "shared", "extras");
3710
+ const repoExtras = join33(REPO_HOME, "shared", "extras");
3548
3711
  const { unmapped, skipped, done, would } = runExtrasOp(
3549
3712
  v,
3550
3713
  dryRun,
3551
3714
  ({ localRoot, logical, dirname: dirname7 }) => ({
3552
- src: join32(repoExtras, logical, dirname7),
3553
- dst: join32(localRoot, dirname7)
3715
+ src: join33(repoExtras, logical, dirname7),
3716
+ dst: join33(localRoot, dirname7)
3554
3717
  }),
3555
3718
  // Snapshot the host-side dst BEFORE copyExtras clobbers it. Anchor on
3556
3719
  // localRoot so the backup tree mirrors the project layout.
@@ -3564,14 +3727,14 @@ function divergenceCheckExtras(ts) {
3564
3727
  const v = loadValidatedExtras({});
3565
3728
  if (v === null) return;
3566
3729
  const counts = { unmapped: 0, skipped: 0 };
3567
- const backupRoot = join33(BACKUP_BASE, ts, "extras");
3730
+ const backupRoot = join34(BACKUP_BASE, ts, "extras");
3568
3731
  for (const { logical, localRoot, dirname: dirname7 } of eachExtrasTarget(v, counts)) {
3569
- const local = join33(localRoot, dirname7);
3570
- const repo = join33(REPO_HOME, "shared", "extras", logical, dirname7);
3571
- if (!existsSync28(local) || !existsSync28(repo)) continue;
3732
+ const local = join34(localRoot, dirname7);
3733
+ const repo = join34(REPO_HOME, "shared", "extras", logical, dirname7);
3734
+ if (!existsSync29(local) || !existsSync29(repo)) continue;
3572
3735
  const diff = listDivergingFiles(local, repo);
3573
3736
  if (diff.length === 0) continue;
3574
- const projectBackupRoot = join33(backupRoot, encodePath(localRoot));
3737
+ const projectBackupRoot = join34(backupRoot, encodePath(localRoot));
3575
3738
  warn(
3576
3739
  `local ${dirname7} for ${logical} diverges from origin in ${diff.length} file(s); next remapExtrasPull will overwrite them (backups at ${projectBackupRoot}/)`
3577
3740
  );
@@ -3584,8 +3747,8 @@ init_config();
3584
3747
  init_utils();
3585
3748
  init_utils_fs();
3586
3749
  init_utils_json();
3587
- import { existsSync as existsSync29, lstatSync as lstatSync7, rmSync as rmSync8 } from "node:fs";
3588
- import { join as join34 } from "node:path";
3750
+ import { existsSync as existsSync30, lstatSync as lstatSync8, rmSync as rmSync9 } from "node:fs";
3751
+ import { join as join35 } from "node:path";
3589
3752
  function emitAutoMove(onPreview, linkPath, ts, name) {
3590
3753
  if (onPreview) {
3591
3754
  onPreview({ kind: "auto-move", from: linkPath, to: `backup/${ts}/${name}` });
@@ -3604,41 +3767,41 @@ function applySharedLinks(ts, map, opts = {}) {
3604
3767
  const dryRun = opts.dryRun === true;
3605
3768
  const linkNames = allSharedLinks(map);
3606
3769
  for (const name of linkNames) {
3607
- const linkPath = join34(CLAUDE_HOME, name);
3608
- const target = join34(REPO_HOME, "shared", name);
3609
- if (!existsSync29(linkPath)) continue;
3610
- if (lstatSync7(linkPath).isSymbolicLink()) continue;
3611
- if (!existsSync29(target)) continue;
3770
+ const linkPath = join35(CLAUDE_HOME, name);
3771
+ const target = join35(REPO_HOME, "shared", name);
3772
+ if (!existsSync30(linkPath)) continue;
3773
+ if (lstatSync8(linkPath).isSymbolicLink()) continue;
3774
+ if (!existsSync30(target)) continue;
3612
3775
  if (dryRun) {
3613
3776
  emitAutoMove(opts.onPreview, linkPath, ts, name);
3614
3777
  continue;
3615
3778
  }
3616
3779
  backupBeforeWrite(linkPath, ts);
3617
- rmSync8(linkPath, { recursive: true, force: true });
3780
+ rmSync9(linkPath, { recursive: true, force: true });
3618
3781
  }
3619
3782
  for (const name of linkNames) {
3620
- const target = join34(REPO_HOME, "shared", name);
3621
- if (!existsSync29(target)) continue;
3783
+ const target = join35(REPO_HOME, "shared", name);
3784
+ if (!existsSync30(target)) continue;
3622
3785
  if (dryRun) {
3623
- emitCreate(opts.onPreview, join34(CLAUDE_HOME, name), target);
3786
+ emitCreate(opts.onPreview, join35(CLAUDE_HOME, name), target);
3624
3787
  continue;
3625
3788
  }
3626
- ensureSymlink(join34(CLAUDE_HOME, name), target);
3789
+ ensureSymlink(join35(CLAUDE_HOME, name), target);
3627
3790
  }
3628
3791
  }
3629
3792
  function regenerateSettings(ts, opts = {}) {
3630
3793
  const dryRun = opts.dryRun === true;
3631
- const basePath = join34(REPO_HOME, "shared", "settings.base.json");
3632
- const hostPath = join34(REPO_HOME, "hosts", `${HOST}.json`);
3633
- if (!existsSync29(basePath)) {
3794
+ const basePath = join35(REPO_HOME, "shared", "settings.base.json");
3795
+ const hostPath = join35(REPO_HOME, "hosts", `${HOST}.json`);
3796
+ if (!existsSync30(basePath)) {
3634
3797
  die("repo not initialized; run 'nomad init' to scaffold");
3635
3798
  }
3636
3799
  const base = readJson(basePath);
3637
- const hasOverrides = existsSync29(hostPath);
3800
+ const hasOverrides = existsSync30(hostPath);
3638
3801
  const overrides = hasOverrides ? readJson(hostPath) : {};
3639
3802
  const merged = deepMerge(base, overrides);
3640
- const settingsPath = join34(CLAUDE_HOME, "settings.json");
3641
- if (!hasOverrides && existsSync29(settingsPath)) {
3803
+ const settingsPath = join35(CLAUDE_HOME, "settings.json");
3804
+ if (!hasOverrides && existsSync30(settingsPath)) {
3642
3805
  try {
3643
3806
  const existing = readJson(settingsPath);
3644
3807
  const baseKeys = new Set(Object.keys(base));
@@ -3664,8 +3827,8 @@ function regenerateSettings(ts, opts = {}) {
3664
3827
 
3665
3828
  // src/preview.ts
3666
3829
  init_config();
3667
- import { existsSync as existsSync30 } from "node:fs";
3668
- import { join as join35 } from "node:path";
3830
+ import { existsSync as existsSync31 } from "node:fs";
3831
+ import { join as join36 } from "node:path";
3669
3832
 
3670
3833
  // node_modules/diff/libesm/diff/base.js
3671
3834
  var Diff = class {
@@ -3951,7 +4114,7 @@ function diffJsonStrings(currentJsonText, newJsonText) {
3951
4114
  return lines.join("\n");
3952
4115
  }
3953
4116
  function readJsonOrNull(path) {
3954
- if (!existsSync30(path)) return null;
4117
+ if (!existsSync31(path)) return null;
3955
4118
  try {
3956
4119
  return readJson(path);
3957
4120
  } catch {
@@ -3965,12 +4128,12 @@ function previewSettings(basePath, hostPath, settingsPath) {
3965
4128
  }
3966
4129
  const notes = [];
3967
4130
  const hostOverrides = readJsonOrNull(hostPath);
3968
- if (hostOverrides === null && existsSync30(hostPath)) {
4131
+ if (hostOverrides === null && existsSync31(hostPath)) {
3969
4132
  notes.push(`malformed hosts/${HOST}.json; ignoring overrides`);
3970
4133
  }
3971
4134
  const merged = deepMerge(base, hostOverrides ?? {});
3972
4135
  const current = readJsonOrNull(settingsPath);
3973
- if (current === null && existsSync30(settingsPath)) {
4136
+ if (current === null && existsSync31(settingsPath)) {
3974
4137
  return { diff: "", notes: [...notes, "malformed; skipping diff"] };
3975
4138
  }
3976
4139
  const rawEqual = JSON.stringify(current ?? {}, null, 2) === JSON.stringify(merged, null, 2);
@@ -4008,9 +4171,9 @@ function computePreview(ts, map, verb = "pull") {
4008
4171
  onPreview: (e) => addItem(links, formatLinkRow(e))
4009
4172
  });
4010
4173
  const settingsResult = previewSettings(
4011
- join35(REPO_HOME, "shared", "settings.base.json"),
4012
- join35(REPO_HOME, "hosts", `${HOST}.json`),
4013
- join35(CLAUDE_HOME, "settings.json")
4174
+ join36(REPO_HOME, "shared", "settings.base.json"),
4175
+ join36(REPO_HOME, "hosts", `${HOST}.json`),
4176
+ join36(CLAUDE_HOME, "settings.json")
4014
4177
  );
4015
4178
  const settingsSection = buildSettingsSectionForPreview(settingsResult);
4016
4179
  const sessions = section("Sessions");
@@ -4026,21 +4189,21 @@ function computePreview(ts, map, verb = "pull") {
4026
4189
 
4027
4190
  // src/spinner.ts
4028
4191
  init_color();
4029
- import { existsSync as existsSync32 } from "node:fs";
4192
+ import { existsSync as existsSync33 } from "node:fs";
4030
4193
  import { fileURLToPath as fileURLToPath4 } from "node:url";
4031
4194
  import { Worker } from "node:worker_threads";
4032
4195
 
4033
4196
  // src/commands.push.recovery.ts
4034
4197
  init_config();
4035
- import { readFileSync as readFileSync11, rmSync as rmSync10, writeFileSync as writeFileSync5 } from "node:fs";
4036
- import { join as join38 } from "node:path";
4198
+ import { readFileSync as readFileSync11, rmSync as rmSync11, writeFileSync as writeFileSync5 } from "node:fs";
4199
+ import { join as join39 } from "node:path";
4037
4200
  import { createInterface } from "node:readline/promises";
4038
4201
 
4039
4202
  // src/commands.push.recovery.redact.ts
4040
4203
  init_config();
4041
4204
  init_config_sharedDirs_guard();
4042
- import { cpSync as cpSync5, existsSync as existsSync31, mkdirSync as mkdirSync7, statSync as statSync8 } from "node:fs";
4043
- import { dirname as dirname6, join as join36, sep as sep2 } from "node:path";
4205
+ import { cpSync as cpSync6, existsSync as existsSync32, mkdirSync as mkdirSync7, statSync as statSync8 } from "node:fs";
4206
+ import { dirname as dirname6, join as join37, sep as sep3 } from "node:path";
4044
4207
  init_push_gitleaks_scan();
4045
4208
  init_utils_json();
4046
4209
  init_utils();
@@ -4071,8 +4234,8 @@ function resolveStagedDir(localPath, map) {
4071
4234
  assertSafeLogical(logical);
4072
4235
  const abs = hostMap[HOST];
4073
4236
  if (abs === void 0) continue;
4074
- if (localPath.startsWith(join36(CLAUDE_HOME, "projects", encodePath(abs)) + sep2)) {
4075
- return join36(REPO_HOME, "shared", "projects", logical);
4237
+ if (localPath.startsWith(join37(CLAUDE_HOME, "projects", encodePath(abs)) + sep3)) {
4238
+ return join37(REPO_HOME, "shared", "projects", logical);
4076
4239
  }
4077
4240
  }
4078
4241
  return null;
@@ -4094,7 +4257,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
4094
4257
  `could not locate the local transcript for session ${sid}; choose Skip or Drop session.`
4095
4258
  );
4096
4259
  }
4097
- const sessionDir = join36(dirname6(localPath), sid);
4260
+ const sessionDir = join37(dirname6(localPath), sid);
4098
4261
  const subtreeFiles = listSubtreeFiles(sessionDir);
4099
4262
  const subtreeMtime = newestSubtreeMtimeMs(localPath, subtreeFiles, (p) => statSync8(p).mtimeMs);
4100
4263
  if (isRecentlyModified(subtreeMtime, nowMs())) {
@@ -4128,25 +4291,25 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
4128
4291
  );
4129
4292
  }
4130
4293
  mkdirSync7(stagedProjectDir, { recursive: true });
4131
- cpSync5(localPath, join36(stagedProjectDir, `${sid}.jsonl`), { force: true });
4132
- if (existsSync31(sessionDir)) {
4133
- cpSync5(sessionDir, join36(stagedProjectDir, sid), { force: true, recursive: true });
4294
+ cpSync6(localPath, join37(stagedProjectDir, `${sid}.jsonl`), { force: true });
4295
+ if (existsSync32(sessionDir)) {
4296
+ cpSync6(sessionDir, join37(stagedProjectDir, sid), { force: true, recursive: true });
4134
4297
  }
4135
4298
  return true;
4136
4299
  }
4137
4300
 
4138
4301
  // src/commands.push.recovery.drop.ts
4139
4302
  init_config();
4140
- import { rmSync as rmSync9 } from "node:fs";
4141
- import { join as join37 } from "node:path";
4303
+ import { rmSync as rmSync10 } from "node:fs";
4304
+ import { join as join38 } from "node:path";
4142
4305
  function dropSessionFromStaged(sid, map) {
4143
4306
  const logicals = Object.keys(map.projects);
4144
4307
  if (logicals.length === 0) return false;
4145
4308
  for (const logical of logicals) {
4146
- const jsonl = join37(REPO_HOME, "shared", "projects", logical, `${sid}.jsonl`);
4147
- const dir = join37(REPO_HOME, "shared", "projects", logical, sid);
4148
- rmSync9(jsonl, { force: true });
4149
- rmSync9(dir, { recursive: true, force: true });
4309
+ const jsonl = join38(REPO_HOME, "shared", "projects", logical, `${sid}.jsonl`);
4310
+ const dir = join38(REPO_HOME, "shared", "projects", logical, sid);
4311
+ rmSync10(jsonl, { force: true });
4312
+ rmSync10(dir, { recursive: true, force: true });
4150
4313
  }
4151
4314
  return true;
4152
4315
  }
@@ -4262,7 +4425,7 @@ function applyThenRescan(scanVerdict, repoHome) {
4262
4425
  return next;
4263
4426
  }
4264
4427
  function allowThenRescan(append, scanVerdict, repoHome) {
4265
- const ignPath = join38(repoHome, ".gitleaksignore");
4428
+ const ignPath = join39(repoHome, ".gitleaksignore");
4266
4429
  let before;
4267
4430
  try {
4268
4431
  before = readFileSync11(ignPath, "utf8");
@@ -4273,7 +4436,7 @@ function allowThenRescan(append, scanVerdict, repoHome) {
4273
4436
  try {
4274
4437
  return applyThenRescan(scanVerdict, repoHome);
4275
4438
  } catch (err) {
4276
- if (before === null) rmSync10(ignPath, { force: true });
4439
+ if (before === null) rmSync11(ignPath, { force: true });
4277
4440
  else writeFileSync5(ignPath, before, "utf8");
4278
4441
  throw err;
4279
4442
  }
@@ -4360,7 +4523,7 @@ function writeAnimatedDone(out, label, ms, useTTY) {
4360
4523
  `);
4361
4524
  }
4362
4525
  function resolveWorkerPath(deps = {}) {
4363
- const check = deps.existsSyncFn ?? existsSync32;
4526
+ const check = deps.existsSyncFn ?? existsSync33;
4364
4527
  const base = deps.baseUrl ?? import.meta.url;
4365
4528
  const mjs = fileURLToPath4(new URL("./nomad.worker.mjs", base));
4366
4529
  if (check(mjs)) return mjs;
@@ -4566,8 +4729,8 @@ function handleWedge(repo, forceRemote) {
4566
4729
  function cmdPull(opts = {}) {
4567
4730
  const dryRun = opts.dryRun === true;
4568
4731
  const forceRemote = opts.forceRemote === true;
4569
- if (!existsSync33(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4570
- if (!existsSync33(join39(REPO_HOME, "shared", "settings.base.json"))) {
4732
+ if (!existsSync34(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4733
+ if (!existsSync34(join40(REPO_HOME, "shared", "settings.base.json"))) {
4571
4734
  die("repo not initialized; run 'nomad init' to scaffold");
4572
4735
  }
4573
4736
  const handle = acquireLock("pull");
@@ -4576,7 +4739,7 @@ function cmdPull(opts = {}) {
4576
4739
  const ts = freshBackupTs(BACKUP_BASE);
4577
4740
  handleWedge(REPO_HOME, forceRemote);
4578
4741
  if (!dryRun) {
4579
- const backupRoot = join39(BACKUP_BASE, ts);
4742
+ const backupRoot = join40(BACKUP_BASE, ts);
4580
4743
  try {
4581
4744
  mkdirSync8(backupRoot, { recursive: true });
4582
4745
  } catch (err) {
@@ -4587,8 +4750,8 @@ function cmdPull(opts = {}) {
4587
4750
  dryRun ? `pulling on host=${HOST} (backup=${ts}; dry-run)` : `pull on host=${HOST} (backup=${ts})`
4588
4751
  );
4589
4752
  gitOrFatal(["pull", "--rebase", "--autostash"], "git pull --rebase", REPO_HOME);
4590
- const mapPath = join39(REPO_HOME, "path-map.json");
4591
- const map = existsSync33(mapPath) ? readPathMap(mapPath) : { projects: {} };
4753
+ const mapPath = join40(REPO_HOME, "path-map.json");
4754
+ const map = existsSync34(mapPath) ? readPathMap(mapPath) : { projects: {} };
4592
4755
  divergenceCheckExtras(ts);
4593
4756
  if (dryRun) {
4594
4757
  computePreview(ts, map, "pull");
@@ -4610,8 +4773,8 @@ function cmdPull(opts = {}) {
4610
4773
 
4611
4774
  // src/commands.push.ts
4612
4775
  init_config();
4613
- import { existsSync as existsSync35 } from "node:fs";
4614
- import { join as join41, relative as relative5 } from "node:path";
4776
+ import { existsSync as existsSync36 } from "node:fs";
4777
+ import { join as join42, relative as relative5 } from "node:path";
4615
4778
 
4616
4779
  // src/commands.push.allowlist.ts
4617
4780
  init_config();
@@ -4691,9 +4854,9 @@ init_color();
4691
4854
  init_config();
4692
4855
  init_config_sharedDirs_guard();
4693
4856
  import { randomBytes as randomBytes2 } from "node:crypto";
4694
- import { copyFileSync, existsSync as existsSync34, mkdirSync as mkdirSync9, readdirSync as readdirSync11, rmSync as rmSync11 } from "node:fs";
4857
+ import { copyFileSync, existsSync as existsSync35, mkdirSync as mkdirSync9, readdirSync as readdirSync11, rmSync as rmSync12 } from "node:fs";
4695
4858
  import { homedir as homedir5 } from "node:os";
4696
- import { join as join40 } from "node:path";
4859
+ import { join as join41 } from "node:path";
4697
4860
  init_push_leak_verdict();
4698
4861
  init_push_gitleaks();
4699
4862
  init_utils_fs();
@@ -4708,13 +4871,13 @@ function stageSessions(tmpRoot, map) {
4708
4871
  if (!p || p === "TBD") continue;
4709
4872
  reverse.set(encodePath(p), logical);
4710
4873
  }
4711
- const localProjects = join40(CLAUDE_HOME, "projects");
4712
- if (!existsSync34(localProjects)) return 0;
4874
+ const localProjects = join41(CLAUDE_HOME, "projects");
4875
+ if (!existsSync35(localProjects)) return 0;
4713
4876
  let staged = 0;
4714
4877
  for (const dir of readdirSync11(localProjects)) {
4715
4878
  const logical = reverse.get(dir);
4716
4879
  if (!logical) continue;
4717
- copyDirJsonlOnly(join40(localProjects, dir), join40(tmpRoot, "shared", "projects", logical));
4880
+ copyDirJsonlOnly(join41(localProjects, dir), join41(tmpRoot, "shared", "projects", logical));
4718
4881
  staged++;
4719
4882
  }
4720
4883
  return staged;
@@ -4730,9 +4893,9 @@ function stageExtras(tmpRoot, map) {
4730
4893
  if (!localRoot || localRoot === "TBD") continue;
4731
4894
  for (const dirname7 of dirnames) {
4732
4895
  if (!whitelist.includes(dirname7)) continue;
4733
- const src = join40(localRoot, dirname7);
4734
- if (!existsSync34(src)) continue;
4735
- const dst = join40(tmpRoot, "shared", "extras", logical, dirname7);
4896
+ const src = join41(localRoot, dirname7);
4897
+ if (!existsSync35(src)) continue;
4898
+ const dst = join41(tmpRoot, "shared", "extras", logical, dirname7);
4736
4899
  copyExtras(src, dst);
4737
4900
  staged++;
4738
4901
  }
@@ -4740,19 +4903,19 @@ function stageExtras(tmpRoot, map) {
4740
4903
  return staged;
4741
4904
  }
4742
4905
  function previewPushLeaks(map) {
4743
- const cacheDir = join40(homedir5(), ".cache", "claude-nomad");
4906
+ const cacheDir = join41(homedir5(), ".cache", "claude-nomad");
4744
4907
  mkdirSync9(cacheDir, { recursive: true });
4745
4908
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes2(4).toString("hex")}`;
4746
- const tmpRoot = join40(cacheDir, `push-preview-tree-${stamp}`);
4909
+ const tmpRoot = join41(cacheDir, `push-preview-tree-${stamp}`);
4747
4910
  try {
4748
4911
  const sessionCount = stageSessions(tmpRoot, map);
4749
4912
  const extrasCount = stageExtras(tmpRoot, map);
4750
4913
  if (sessionCount + extrasCount === 0) {
4751
4914
  return { leak: false, verdictRow: NOTHING_TO_SCAN_ROW, recovery: null, findings: [] };
4752
4915
  }
4753
- const ignoreFile = join40(REPO_HOME, ".gitleaksignore");
4754
- if (existsSync34(ignoreFile)) {
4755
- copyFileSync(ignoreFile, join40(tmpRoot, ".gitleaksignore"));
4916
+ const ignoreFile = join41(REPO_HOME, ".gitleaksignore");
4917
+ if (existsSync35(ignoreFile)) {
4918
+ copyFileSync(ignoreFile, join41(tmpRoot, ".gitleaksignore"));
4756
4919
  }
4757
4920
  let findings;
4758
4921
  try {
@@ -4765,7 +4928,7 @@ function previewPushLeaks(map) {
4765
4928
  }
4766
4929
  return verdictFromFindings(findings);
4767
4930
  } finally {
4768
- rmSync11(tmpRoot, { recursive: true, force: true });
4931
+ rmSync12(tmpRoot, { recursive: true, force: true });
4769
4932
  }
4770
4933
  }
4771
4934
 
@@ -4774,7 +4937,7 @@ init_utils();
4774
4937
  init_utils_fs();
4775
4938
  init_utils_json();
4776
4939
  function guardGitlinks() {
4777
- const gitlinks = findGitlinks(join41(REPO_HOME, "shared"));
4940
+ const gitlinks = findGitlinks(join42(REPO_HOME, "shared"));
4778
4941
  if (gitlinks.length === 0) return;
4779
4942
  for (const p of gitlinks) {
4780
4943
  const rel = relative5(REPO_HOME, p);
@@ -4826,7 +4989,7 @@ async function cmdPush(opts = {}) {
4826
4989
  const allowAll = opts.allowAll === true;
4827
4990
  const allowRule = opts.allowRule;
4828
4991
  guardResolutionModeConflicts(dryRun, redactAll, allowAll, allowRule);
4829
- if (!existsSync35(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4992
+ if (!existsSync36(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4830
4993
  const handle = acquireLock("push");
4831
4994
  if (handle === null) process.exit(0);
4832
4995
  try {
@@ -4844,8 +5007,8 @@ async function cmdPush(opts = {}) {
4844
5007
  renderNoScanTree(st);
4845
5008
  return;
4846
5009
  }
4847
- const mapPath = join41(REPO_HOME, "path-map.json");
4848
- if (!existsSync35(mapPath)) {
5010
+ const mapPath = join42(REPO_HOME, "path-map.json");
5011
+ if (!existsSync36(mapPath)) {
4849
5012
  if (dryRun) return runDryRunPreview(st, null);
4850
5013
  die("path-map.json missing, cannot enforce push allow-list");
4851
5014
  }
@@ -4885,17 +5048,17 @@ init_config();
4885
5048
 
4886
5049
  // src/diff.ts
4887
5050
  init_config();
4888
- import { existsSync as existsSync36 } from "node:fs";
4889
- import { join as join42 } from "node:path";
5051
+ import { existsSync as existsSync37 } from "node:fs";
5052
+ import { join as join43 } from "node:path";
4890
5053
  init_utils();
4891
5054
  init_utils_fs();
4892
5055
  init_utils_json();
4893
5056
  function cmdDiff() {
4894
5057
  try {
4895
- if (!existsSync36(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
5058
+ if (!existsSync37(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4896
5059
  const ts = freshBackupTs(BACKUP_BASE);
4897
- const mapPath = join42(REPO_HOME, "path-map.json");
4898
- const map = existsSync36(mapPath) ? readPathMap(mapPath) : { projects: {} };
5060
+ const mapPath = join43(REPO_HOME, "path-map.json");
5061
+ const map = existsSync37(mapPath) ? readPathMap(mapPath) : { projects: {} };
4899
5062
  computePreview(ts, map, "diff");
4900
5063
  } catch (err) {
4901
5064
  if (err instanceof NomadFatal) {
@@ -4909,8 +5072,8 @@ function cmdDiff() {
4909
5072
 
4910
5073
  // src/init.ts
4911
5074
  init_config();
4912
- import { existsSync as existsSync38, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
4913
- import { join as join44 } from "node:path";
5075
+ import { existsSync as existsSync39, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
5076
+ import { join as join45 } from "node:path";
4914
5077
 
4915
5078
  // src/init.gh-onboard.ts
4916
5079
  init_config();
@@ -4991,31 +5154,31 @@ init_config();
4991
5154
  init_utils();
4992
5155
  init_utils_fs();
4993
5156
  init_utils_json();
4994
- import { copyFileSync as copyFileSync2, cpSync as cpSync6, existsSync as existsSync37, rmSync as rmSync12, statSync as statSync9 } from "node:fs";
4995
- import { join as join43 } from "node:path";
5157
+ import { copyFileSync as copyFileSync2, cpSync as cpSync7, existsSync as existsSync38, rmSync as rmSync13, statSync as statSync9 } from "node:fs";
5158
+ import { join as join44 } from "node:path";
4996
5159
  function snapshotIntoShared(map) {
4997
5160
  for (const name of allSharedLinks(map)) {
4998
- const src = join43(CLAUDE_HOME, name);
4999
- if (!existsSync37(src)) continue;
5000
- const dst = join43(REPO_HOME, "shared", name);
5161
+ const src = join44(CLAUDE_HOME, name);
5162
+ if (!existsSync38(src)) continue;
5163
+ const dst = join44(REPO_HOME, "shared", name);
5001
5164
  if (statSync9(src).isDirectory()) {
5002
- const gk = join43(dst, ".gitkeep");
5003
- if (existsSync37(gk)) rmSync12(gk);
5004
- cpSync6(src, dst, { recursive: true, force: false, errorOnExist: true });
5165
+ const gk = join44(dst, ".gitkeep");
5166
+ if (existsSync38(gk)) rmSync13(gk);
5167
+ cpSync7(src, dst, { recursive: true, force: false, errorOnExist: true });
5005
5168
  } else {
5006
5169
  copyFileSync2(src, dst);
5007
5170
  }
5008
5171
  log(`snapshotted shared/${name} from ${src}`);
5009
5172
  }
5010
- const userSettings = join43(CLAUDE_HOME, "settings.json");
5011
- if (existsSync37(userSettings)) {
5173
+ const userSettings = join44(CLAUDE_HOME, "settings.json");
5174
+ if (existsSync38(userSettings)) {
5012
5175
  let parsed;
5013
5176
  try {
5014
5177
  parsed = readJson(userSettings);
5015
5178
  } catch (err) {
5016
5179
  return die(`malformed ${userSettings}: ${err.message}`);
5017
5180
  }
5018
- const hostFile = join43(REPO_HOME, "hosts", `${HOST}.json`);
5181
+ const hostFile = join44(REPO_HOME, "hosts", `${HOST}.json`);
5019
5182
  writeJsonAtomic(hostFile, parsed);
5020
5183
  log(`snapshotted hosts/${HOST}.json from ${userSettings}`);
5021
5184
  }
@@ -5028,14 +5191,14 @@ var SHARED_CLAUDE_MD = "<!-- claude-nomad shared CLAUDE.md; symlinked into ~/.cl
5028
5191
  var SHARED_KEEP_DIRS = ["agents", "skills", "commands", "rules", "hooks"];
5029
5192
  function preflightConflict(repoHome) {
5030
5193
  const candidates = [
5031
- join44(repoHome, "shared", "settings.base.json"),
5032
- join44(repoHome, "shared", "CLAUDE.md"),
5033
- join44(repoHome, "path-map.json"),
5034
- join44(repoHome, "hosts"),
5035
- join44(repoHome, "shared")
5194
+ join45(repoHome, "shared", "settings.base.json"),
5195
+ join45(repoHome, "shared", "CLAUDE.md"),
5196
+ join45(repoHome, "path-map.json"),
5197
+ join45(repoHome, "hosts"),
5198
+ join45(repoHome, "shared")
5036
5199
  ];
5037
5200
  for (const c of candidates) {
5038
- if (existsSync38(c)) return c;
5201
+ if (existsSync39(c)) return c;
5039
5202
  }
5040
5203
  return null;
5041
5204
  }
@@ -5048,25 +5211,25 @@ function cmdInit(opts = {}) {
5048
5211
  die(`already initialized; refusing to clobber ${conflict}`);
5049
5212
  }
5050
5213
  ensureOriginRepo(opts.repoName ?? DEFAULT_REPO_NAME, opts.run);
5051
- mkdirSync10(join44(REPO_HOME, "shared"), { recursive: true });
5052
- mkdirSync10(join44(REPO_HOME, "hosts"), { recursive: true });
5214
+ mkdirSync10(join45(REPO_HOME, "shared"), { recursive: true });
5215
+ mkdirSync10(join45(REPO_HOME, "hosts"), { recursive: true });
5053
5216
  for (const name of SHARED_KEEP_DIRS) {
5054
- mkdirSync10(join44(REPO_HOME, "shared", name), { recursive: true });
5217
+ mkdirSync10(join45(REPO_HOME, "shared", name), { recursive: true });
5055
5218
  }
5056
- const userClaudeMd = join44(CLAUDE_HOME, "CLAUDE.md");
5057
- if (!snapshot || !existsSync38(userClaudeMd)) {
5058
- writeFileSync6(join44(REPO_HOME, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
5219
+ const userClaudeMd = join45(CLAUDE_HOME, "CLAUDE.md");
5220
+ if (!snapshot || !existsSync39(userClaudeMd)) {
5221
+ writeFileSync6(join45(REPO_HOME, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
5059
5222
  log("created shared/CLAUDE.md");
5060
5223
  }
5061
5224
  for (const name of SHARED_KEEP_DIRS) {
5062
- writeFileSync6(join44(REPO_HOME, "shared", name, ".gitkeep"), "");
5225
+ writeFileSync6(join45(REPO_HOME, "shared", name, ".gitkeep"), "");
5063
5226
  log(`created shared/${name}/.gitkeep`);
5064
5227
  }
5065
- writeFileSync6(join44(REPO_HOME, "hosts", ".gitkeep"), "");
5228
+ writeFileSync6(join45(REPO_HOME, "hosts", ".gitkeep"), "");
5066
5229
  log("created hosts/.gitkeep");
5067
- writeJsonAtomic(join44(REPO_HOME, "shared", "settings.base.json"), {});
5230
+ writeJsonAtomic(join45(REPO_HOME, "shared", "settings.base.json"), {});
5068
5231
  log("created shared/settings.base.json");
5069
- writeJsonAtomic(join44(REPO_HOME, "path-map.json"), { projects: {} });
5232
+ writeJsonAtomic(join45(REPO_HOME, "path-map.json"), { projects: {} });
5070
5233
  log("created path-map.json");
5071
5234
  if (snapshot) {
5072
5235
  snapshotIntoShared({ projects: {} });
@@ -5260,6 +5423,23 @@ function parseCleanArgs(argv) {
5260
5423
  return { dryRun: st.dryRun, olderThan: st.olderThan, keep: st.keep };
5261
5424
  }
5262
5425
 
5426
+ // src/nomad.dispatch.eject.ts
5427
+ function parseEjectArgs(argv) {
5428
+ let dryRun = false;
5429
+ let i = 3;
5430
+ while (i < argv.length) {
5431
+ const token = argv[i];
5432
+ if (token === "--dry-run") {
5433
+ if (dryRun) return null;
5434
+ dryRun = true;
5435
+ } else {
5436
+ return null;
5437
+ }
5438
+ i++;
5439
+ }
5440
+ return { dryRun };
5441
+ }
5442
+
5263
5443
  // src/nomad.dispatch.allow.ts
5264
5444
  function parseAllowArgs(argv) {
5265
5445
  const positionals = argv.slice(3);
@@ -5350,7 +5530,7 @@ function parsePushArgs(argv) {
5350
5530
  // package.json
5351
5531
  var package_default = {
5352
5532
  name: "claude-nomad",
5353
- version: "0.43.0",
5533
+ version: "0.44.0",
5354
5534
  type: "module",
5355
5535
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
5356
5536
  keywords: [
@@ -5509,6 +5689,11 @@ var DEFAULT_HELP = [
5509
5689
  cont("symlink, and stage for push. <name> must be in SHARED_LINKS or sharedDirs."),
5510
5690
  row(" --dry-run", "Preview backup, move, and git-add without writing."),
5511
5691
  "",
5692
+ row(" eject", "Materialize every managed ~/.claude/ symlink into a real copy so the"),
5693
+ cont("setup keeps working after deleting the sync repo. Prints a"),
5694
+ cont("manual-remainder checklist (uninstall CLI, drop env vars, optional deletes)."),
5695
+ row(" --dry-run", "List what would be materialized without writing anything."),
5696
+ "",
5512
5697
  row(
5513
5698
  " redact <session-id>",
5514
5699
  "Rewrite the secret span in the local source transcript for a session,"
@@ -5545,15 +5730,15 @@ var DEFAULT_HELP = [
5545
5730
  init_config();
5546
5731
  init_utils();
5547
5732
  init_utils_json();
5548
- import { existsSync as existsSync39, readFileSync as readFileSync12, readdirSync as readdirSync12 } from "node:fs";
5549
- import { join as join45 } from "node:path";
5733
+ import { existsSync as existsSync40, readFileSync as readFileSync12, readdirSync as readdirSync12 } from "node:fs";
5734
+ import { join as join46 } from "node:path";
5550
5735
  function resumeCmd(sessionId) {
5551
5736
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId) || sessionId.length > 128) {
5552
5737
  fail(`invalid session id: ${sessionId}`);
5553
5738
  process.exit(1);
5554
5739
  }
5555
- const projectsRoot = join45(CLAUDE_HOME, "projects");
5556
- if (!existsSync39(projectsRoot)) {
5740
+ const projectsRoot = join46(CLAUDE_HOME, "projects");
5741
+ if (!existsSync40(projectsRoot)) {
5557
5742
  fail(`${projectsRoot} does not exist`);
5558
5743
  process.exit(1);
5559
5744
  }
@@ -5567,8 +5752,8 @@ function resumeCmd(sessionId) {
5567
5752
  fail(`no cwd field found in ${jsonlPath}`);
5568
5753
  process.exit(1);
5569
5754
  }
5570
- const mapPath = join45(REPO_HOME, "path-map.json");
5571
- if (!existsSync39(mapPath)) {
5755
+ const mapPath = join46(REPO_HOME, "path-map.json");
5756
+ if (!existsSync40(mapPath)) {
5572
5757
  fail("path-map.json missing");
5573
5758
  process.exit(1);
5574
5759
  }
@@ -5591,8 +5776,8 @@ function resumeCmd(sessionId) {
5591
5776
  }
5592
5777
  function findTranscriptPath(projectsRoot, sessionId) {
5593
5778
  for (const dir of readdirSync12(projectsRoot)) {
5594
- const candidate = join45(projectsRoot, dir, `${sessionId}.jsonl`);
5595
- if (existsSync39(candidate)) return candidate;
5779
+ const candidate = join46(projectsRoot, dir, `${sessionId}.jsonl`);
5780
+ if (existsSync40(candidate)) return candidate;
5596
5781
  }
5597
5782
  return null;
5598
5783
  }
@@ -5726,6 +5911,15 @@ try {
5726
5911
  cmdAdopt(name, { dryRun: sub === "--dry-run" });
5727
5912
  break;
5728
5913
  }
5914
+ case "eject": {
5915
+ const ejectArgs = parseEjectArgs(process.argv);
5916
+ if (ejectArgs === null) {
5917
+ console.error("usage: nomad eject [--dry-run]");
5918
+ process.exit(1);
5919
+ }
5920
+ cmdEject({ dryRun: ejectArgs.dryRun });
5921
+ break;
5922
+ }
5729
5923
  case "doctor":
5730
5924
  if (process.argv[3] === void 0) {
5731
5925
  cmdDoctor();