claude-nomad 0.67.0 → 0.67.2

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
@@ -70,6 +70,9 @@ function regionKey(segment) {
70
70
  function isExtrasScoped(segments) {
71
71
  return segments[0] === "shared" && segments.length > 1 && regionKey(segments[1]) === "extras";
72
72
  }
73
+ function isLogicalNameScoped(segments) {
74
+ return segments[0] === "shared" && segments.length > 1 && UNFILTERED_SHARED_REGIONS.has(regionKey(segments[1]));
75
+ }
73
76
  function isSharedNameScoped(segments) {
74
77
  return segments[0] === "shared" && segments.length > 1 && !UNFILTERED_SHARED_REGIONS.has(regionKey(segments[1]));
75
78
  }
@@ -83,7 +86,7 @@ function blockSetFor(segments) {
83
86
  function deniedSegmentFor(path) {
84
87
  const segments = path.split("/");
85
88
  const blockSet = blockSetFor(segments);
86
- const scan = isExtrasScoped(segments) ? segments.slice(4) : segments;
89
+ const scan = isLogicalNameScoped(segments) && segments.length > 3 ? segments.slice(3) : segments;
87
90
  for (const segment of scan) {
88
91
  if (isDeniedName(blockSet, segment)) return segment;
89
92
  }
@@ -803,12 +806,12 @@ import {
803
806
  cpSync as cpSync3,
804
807
  existsSync as existsSync3,
805
808
  fsyncSync,
806
- lstatSync as lstatSync4,
809
+ lstatSync as lstatSync5,
807
810
  mkdirSync,
808
811
  openSync,
809
812
  renameSync,
810
813
  rmdirSync,
811
- statSync,
814
+ statSync as statSync2,
812
815
  symlinkSync,
813
816
  writeFileSync
814
817
  } from "node:fs";
@@ -837,7 +840,7 @@ function renameAtomicRetry(tmp, dst, renameFn = renameSync) {
837
840
  }
838
841
  }
839
842
  function writeJsonAtomic(path, data) {
840
- const mode = existsSync3(path) ? statSync(path).mode & 511 : 384;
843
+ const mode = existsSync3(path) ? statSync2(path).mode & 511 : 384;
841
844
  const tmp = `${path}.tmp.${process.pid}`;
842
845
  const fd = openSync(tmp, "w", mode);
843
846
  try {
@@ -876,7 +879,7 @@ function discardEmptyBackupDir(backupRoot) {
876
879
  }
877
880
  function ensureSymlink(linkPath, target) {
878
881
  if (existsSync3(linkPath)) {
879
- if (lstatSync4(linkPath).isSymbolicLink()) return;
882
+ if (lstatSync5(linkPath).isSymbolicLink()) return;
880
883
  die(`${linkPath} exists and is not a symlink. Move it aside first.`);
881
884
  }
882
885
  mkdirSync(dirname(linkPath), { recursive: true });
@@ -915,12 +918,12 @@ var init_utils_fs = __esm({
915
918
 
916
919
  // src/commands.pull.wedge.ts
917
920
  import { execFileSync as execFileSync3 } from "node:child_process";
918
- import { existsSync as existsSync16 } from "node:fs";
919
- import { join as join20 } from "node:path";
921
+ import { existsSync as existsSync15 } from "node:fs";
922
+ import { join as join21 } from "node:path";
920
923
  function detectWedge(repo) {
921
- const g = join20(repo, ".git");
922
- if (existsSync16(join20(g, "rebase-merge")) || existsSync16(join20(g, "rebase-apply"))) return "rebase";
923
- if (existsSync16(join20(g, "MERGE_HEAD"))) return "merge";
924
+ const g = join21(repo, ".git");
925
+ if (existsSync15(join21(g, "rebase-merge")) || existsSync15(join21(g, "rebase-apply"))) return "rebase";
926
+ if (existsSync15(join21(g, "MERGE_HEAD"))) return "merge";
924
927
  return null;
925
928
  }
926
929
  function probeUnmergedIndex(repo) {
@@ -990,15 +993,15 @@ var init_commands_pull_wedge = __esm({
990
993
  });
991
994
 
992
995
  // src/push-gitleaks.config.ts
993
- import { existsSync as existsSync17, mkdtempSync, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
996
+ import { existsSync as existsSync16, mkdtempSync, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
994
997
  import { tmpdir } from "node:os";
995
- import { join as join21 } from "node:path";
998
+ import { join as join22 } from "node:path";
996
999
  import { fileURLToPath } from "node:url";
997
1000
  function resolveTomlPath(repo = repoHome()) {
998
- const repoToml = join21(repo, ".gitleaks.toml");
999
- if (existsSync17(repoToml)) return repoToml;
1001
+ const repoToml = join22(repo, ".gitleaks.toml");
1002
+ if (existsSync16(repoToml)) return repoToml;
1000
1003
  const bundled = fileURLToPath(new URL("../.gitleaks.toml", import.meta.url));
1001
- return existsSync17(bundled) ? bundled : null;
1004
+ return existsSync16(bundled) ? bundled : null;
1002
1005
  }
1003
1006
  function assertOverlayAllowlistsScoped(overlayBody) {
1004
1007
  if (OVERLAY_INLINE_ALLOWLIST_RE.test(overlayBody)) {
@@ -1036,17 +1039,17 @@ function buildOverlayTempConfig(overlayBody, bundled) {
1036
1039
  path = ${JSON.stringify(bundled)}
1037
1040
 
1038
1041
  ${overlayBody}`;
1039
- const tempPath = mkdtempSync(join21(tmpdir(), "nomad-gitleaks-cfg-"));
1040
- const configPath = join21(tempPath, "config.toml");
1042
+ const tempPath = mkdtempSync(join22(tmpdir(), "nomad-gitleaks-cfg-"));
1043
+ const configPath = join22(tempPath, "config.toml");
1041
1044
  writeFileSync3(configPath, tempBody, { mode: 384, flag: "wx" });
1042
1045
  return { configPath, tempPath };
1043
1046
  }
1044
1047
  function resolveTomlConfig() {
1045
1048
  const repo = repoHome();
1046
- const overlayPath = join21(repo, ".gitleaks.overlay.toml");
1047
- const repoToml = join21(repo, ".gitleaks.toml");
1049
+ const overlayPath = join22(repo, ".gitleaks.overlay.toml");
1050
+ const repoToml = join22(repo, ".gitleaks.toml");
1048
1051
  const bundled = resolveTomlPath(repo);
1049
- if (!existsSync17(overlayPath)) {
1052
+ if (!existsSync16(overlayPath)) {
1050
1053
  return { path: bundled, tempPath: null };
1051
1054
  }
1052
1055
  if (bundled === repoToml) {
@@ -1134,7 +1137,7 @@ var init_autostash_guard = __esm({
1134
1137
  import { execFileSync as execFileSync4 } from "node:child_process";
1135
1138
  import { readdirSync as readdirSync8, rmSync as rmSync7 } from "node:fs";
1136
1139
  import { homedir as homedir2, platform } from "node:os";
1137
- import { delimiter, join as join22 } from "node:path";
1140
+ import { delimiter, join as join23 } from "node:path";
1138
1141
  function gitleaksInstallHint() {
1139
1142
  const head = "gitleaks not on PATH (required for nomad push). Install:";
1140
1143
  const plat = platform();
@@ -1182,7 +1185,7 @@ function findGitlinks(dir) {
1182
1185
  return;
1183
1186
  }
1184
1187
  for (const e of entries) {
1185
- const p = join22(current, e.name);
1188
+ const p = join23(current, e.name);
1186
1189
  if (e.name === ".git") {
1187
1190
  hits.push(p);
1188
1191
  continue;
@@ -1246,7 +1249,7 @@ var init_push_checks = __esm({
1246
1249
  import { execFileSync as execFileSync8 } from "node:child_process";
1247
1250
  import { mkdirSync as mkdirSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync8 } from "node:fs";
1248
1251
  import { homedir as homedir3 } from "node:os";
1249
- import { join as join26 } from "node:path";
1252
+ import { join as join27 } from "node:path";
1250
1253
  function toFinding(entry) {
1251
1254
  if (typeof entry !== "object" || entry === null) return null;
1252
1255
  const e = entry;
@@ -1294,9 +1297,9 @@ function resolveScanFailure(reportPath, e, forwardStreams) {
1294
1297
  return report;
1295
1298
  }
1296
1299
  function scanStagedTree(repoDir, forwardStreams = false) {
1297
- const cacheDir = join26(homedir3(), ".cache", "claude-nomad");
1300
+ const cacheDir = join27(homedir3(), ".cache", "claude-nomad");
1298
1301
  mkdirSync3(cacheDir, { recursive: true });
1299
- const reportPath = join26(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
1302
+ const reportPath = join27(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
1300
1303
  const { path: toml, tempPath } = resolveTomlConfig();
1301
1304
  const args = [
1302
1305
  "protect",
@@ -1324,14 +1327,14 @@ function scanStagedTree(repoDir, forwardStreams = false) {
1324
1327
  }
1325
1328
  }
1326
1329
  function scanFile(filePath, forwardStreams = false, timeoutMs = GITLEAKS_SCAN_TIMEOUT_MS) {
1327
- const cacheDir = join26(homedir3(), ".cache", "claude-nomad");
1330
+ const cacheDir = join27(homedir3(), ".cache", "claude-nomad");
1328
1331
  mkdirSync3(cacheDir, { recursive: true });
1329
1332
  const { path: toml, tempPath } = resolveTomlConfig();
1330
1333
  let reportDir;
1331
1334
  let reportPath;
1332
1335
  try {
1333
- reportDir = mkdtempSync2(join26(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}-`));
1334
- reportPath = join26(reportDir, "report.json");
1336
+ reportDir = mkdtempSync2(join27(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}-`));
1337
+ reportPath = join27(reportDir, "report.json");
1335
1338
  const args = [
1336
1339
  "detect",
1337
1340
  "--no-git",
@@ -1559,15 +1562,27 @@ import { existsSync as existsSync5, lstatSync as lstatSync7 } from "node:fs";
1559
1562
  import { join as join9 } from "node:path";
1560
1563
 
1561
1564
  // src/commands.adopt.recover.ts
1562
- import { lstatSync as lstatSync6, rmSync as rmSync4 } from "node:fs";
1565
+ import { rmSync as rmSync4 } from "node:fs";
1563
1566
  import { dirname as dirname2, join as join7, resolve as resolve2 } from "node:path";
1564
1567
 
1565
1568
  // src/commands.adopt.scan.ts
1566
1569
  init_config();
1567
- init_exit_codes();
1568
- init_utils();
1569
1570
  import { lstatSync, readdirSync } from "node:fs";
1570
1571
  import { join as join2, relative } from "node:path";
1572
+
1573
+ // src/error-text.ts
1574
+ function errorText(err) {
1575
+ try {
1576
+ const message = err?.message;
1577
+ return typeof message === "string" ? message : String(err);
1578
+ } catch {
1579
+ return "unprintable error value";
1580
+ }
1581
+ }
1582
+
1583
+ // src/commands.adopt.scan.ts
1584
+ init_exit_codes();
1585
+ init_utils();
1571
1586
  function toForwardSlash(p) {
1572
1587
  return p.replaceAll("\\", "/");
1573
1588
  }
@@ -1596,10 +1611,8 @@ function scanOrFatal(name, root, state) {
1596
1611
  try {
1597
1612
  return scanDeniedEntries(root);
1598
1613
  } catch (err) {
1599
- const message = err?.message;
1600
- const text = typeof message === "string" ? message : String(err);
1601
1614
  throw new NomadFatal(
1602
- `cannot adopt ${name}: could not scan ${root} for never-sync content (${text}). ${state()} Check that it is readable and not being written to, then run \`nomad adopt ${name}\` again.`,
1615
+ `cannot adopt ${name}: could not scan ${root} for never-sync content (${errorText(err)}). ${state()} Check that it is readable and not being written to, then run \`nomad adopt ${name}\` again.`,
1603
1616
  { code: EXIT.GENERIC_FAILURE }
1604
1617
  );
1605
1618
  }
@@ -1859,9 +1872,34 @@ function copyExtrasFilteredPreserving(src, dst, blockSet) {
1859
1872
  });
1860
1873
  }
1861
1874
 
1875
+ // src/fs-presence.ts
1876
+ import { lstatSync as lstatSync4, statSync } from "node:fs";
1877
+ var ABSENT_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR", "ENAMETOOLONG"]);
1878
+ function classifyPresence(p) {
1879
+ let stat;
1880
+ try {
1881
+ stat = lstatSync4(p, { throwIfNoEntry: false });
1882
+ } catch (err) {
1883
+ return ABSENT_CODES.has(String(err.code)) ? "absent" : "unknown";
1884
+ }
1885
+ if (stat === void 0) return "absent";
1886
+ try {
1887
+ statSync(p);
1888
+ } catch (err) {
1889
+ return ABSENT_CODES.has(String(err.code)) ? "dangling" : "unknown";
1890
+ }
1891
+ return "resolves";
1892
+ }
1893
+ function isUnusableTarget(state) {
1894
+ return state === "dangling" || state === "unknown";
1895
+ }
1896
+ function lexists(p) {
1897
+ return classifyPresence(p) !== "absent";
1898
+ }
1899
+
1862
1900
  // src/links.ts
1863
1901
  init_config();
1864
- import { existsSync as existsSync4, lstatSync as lstatSync5, rmSync as rmSync3 } from "node:fs";
1902
+ import { existsSync as existsSync4, lstatSync as lstatSync6, rmSync as rmSync3 } from "node:fs";
1865
1903
  import { join as join6 } from "node:path";
1866
1904
 
1867
1905
  // src/hooks-filter.ts
@@ -2177,14 +2215,14 @@ function emitCopy(onPreview, from, to) {
2177
2215
  }
2178
2216
  }
2179
2217
  function isAlreadySymlink(linkPath) {
2180
- return existsSync4(linkPath) && lstatSync5(linkPath).isSymbolicLink();
2218
+ return existsSync4(linkPath) && lstatSync6(linkPath).isSymbolicLink();
2181
2219
  }
2182
2220
  function runAutoMovePasses(linkNames, claude, repo, ts, dryRun, onPreview) {
2183
2221
  for (const name of linkNames) {
2184
2222
  const linkPath = join6(claude, name);
2185
2223
  const target = join6(repo, "shared", name);
2186
2224
  if (!existsSync4(linkPath)) continue;
2187
- if (lstatSync5(linkPath).isSymbolicLink()) continue;
2225
+ if (lstatSync6(linkPath).isSymbolicLink()) continue;
2188
2226
  if (!existsSync4(target)) continue;
2189
2227
  if (dryRun) {
2190
2228
  emitAutoMove(onPreview, linkPath, ts, name);
@@ -2199,7 +2237,7 @@ function copySharedLinkPull(src, dst) {
2199
2237
  }
2200
2238
  function stillOccupied(abs) {
2201
2239
  try {
2202
- return lstatSync5(abs, { throwIfNoEntry: false }) !== void 0;
2240
+ return lstatSync6(abs, { throwIfNoEntry: false }) !== void 0;
2203
2241
  } catch {
2204
2242
  return true;
2205
2243
  }
@@ -2224,7 +2262,7 @@ function warnWin32ApplyFailed(linkPath, ts, err, snapshotted) {
2224
2262
  function applyOneSharedLinkWin32(target, linkPath, ts) {
2225
2263
  let snapshotted = false;
2226
2264
  try {
2227
- const stat = lstatSync5(linkPath, { throwIfNoEntry: false });
2265
+ const stat = lstatSync6(linkPath, { throwIfNoEntry: false });
2228
2266
  if (stat !== void 0) {
2229
2267
  const snapshot = snapshotBeforeWin32Copy(linkPath, ts);
2230
2268
  if (snapshot === "failed") return;
@@ -2339,18 +2377,6 @@ function regenerateSettings(ts, opts = {}) {
2339
2377
 
2340
2378
  // src/commands.adopt.recover.ts
2341
2379
  init_utils();
2342
- function errorText(err) {
2343
- const message = err?.message;
2344
- return typeof message === "string" ? message : String(err);
2345
- }
2346
- function lexists(p) {
2347
- try {
2348
- lstatSync6(p);
2349
- return true;
2350
- } catch {
2351
- return false;
2352
- }
2353
- }
2354
2380
  function isDirectChildOf(root, abs) {
2355
2381
  return dirname2(resolve2(abs)) === resolve2(root);
2356
2382
  }
@@ -2595,11 +2621,56 @@ function isValidAdoptName(name) {
2595
2621
  if (SHARED_LINKS.includes(name)) return true;
2596
2622
  return isValidSharedDir(name);
2597
2623
  }
2624
+ function refuseUnusableSharedTarget(name) {
2625
+ throw new NomadFatal(
2626
+ `${name}: shared/${name} does not resolve to anything usable, so adopting would publish nothing. Remove shared/${name} from the repo, or restore what it points at, then re-run adopt.`,
2627
+ { code: EXIT.GENERIC_FAILURE }
2628
+ );
2629
+ }
2630
+ function clobberMessage(name, state) {
2631
+ if (state === "dangling") {
2632
+ return `${name}: shared/${name} is a pointer that does not resolve; would clobber. Remove it, or restore what it points at, first.`;
2633
+ }
2634
+ if (state === "unknown") {
2635
+ return `${name}: shared/${name} could not be read, so adopt cannot tell whether it would clobber existing content. Check its permissions in the sync repo.`;
2636
+ }
2637
+ return `${name}: shared/${name} already exists; would clobber. Remove it first.`;
2638
+ }
2639
+ function refuseClobber(name, sharedTarget) {
2640
+ const state = classifyPresence(sharedTarget);
2641
+ if (state === "absent") return;
2642
+ throw new NomadFatal(clobberMessage(name, state), { code: EXIT.GENERIC_FAILURE });
2643
+ }
2598
2644
  function reportWin32AlreadyAdopted(name, sharedTarget) {
2599
- if (process.platform !== "win32" || !lexists(sharedTarget)) return false;
2645
+ if (process.platform !== "win32") return false;
2646
+ const state = classifyPresence(sharedTarget);
2647
+ if (state === "absent") return false;
2648
+ if (isUnusableTarget(state)) refuseUnusableSharedTarget(name);
2600
2649
  log(`${name}: already adopted (win32 copy-sync); run \`nomad pull\` to refresh the local copy`);
2601
2650
  return true;
2602
2651
  }
2652
+ function alreadySymlinkMessage(name, sharedTarget) {
2653
+ const state = classifyPresence(sharedTarget);
2654
+ if (state === "dangling") {
2655
+ return {
2656
+ text: `${name}: already a symlink, but shared/${name} does not resolve, so the link is broken. Restore shared/${name} in the repo, or remove ~/.claude/${name} and re-run adopt`,
2657
+ healthy: false
2658
+ };
2659
+ }
2660
+ if (state === "unknown") {
2661
+ return {
2662
+ text: `${name}: already a symlink, but shared/${name} could not be read, so whether the link works could not be determined. Check its permissions in the sync repo`,
2663
+ healthy: false
2664
+ };
2665
+ }
2666
+ if (state === "absent") {
2667
+ return {
2668
+ text: `${name}: already a symlink, but there is no shared/${name} in the repo, so it is not adopted. Remove ~/.claude/${name} and re-run adopt, or run \`nomad pull\` if another host shares it`,
2669
+ healthy: false
2670
+ };
2671
+ }
2672
+ return { text: `${name}: already adopted (already a symlink)`, healthy: true };
2673
+ }
2603
2674
  function adoptStopsEarly(name, linkPath, sharedTarget) {
2604
2675
  if (!existsSync5(linkPath)) {
2605
2676
  if (reportWin32AlreadyAdopted(name, sharedTarget)) return true;
@@ -2607,14 +2678,13 @@ function adoptStopsEarly(name, linkPath, sharedTarget) {
2607
2678
  return true;
2608
2679
  }
2609
2680
  if (lstatSync7(linkPath).isSymbolicLink()) {
2610
- log(`${name}: already adopted (already a symlink)`);
2681
+ const { text, healthy } = alreadySymlinkMessage(name, sharedTarget);
2682
+ if (healthy) log(text);
2683
+ else warn(text);
2611
2684
  return true;
2612
2685
  }
2613
2686
  if (reportWin32AlreadyAdopted(name, sharedTarget)) return true;
2614
- if (lexists(sharedTarget)) {
2615
- fail(`${name}: shared/${name} already exists; would clobber. Remove it first.`);
2616
- process.exit(1);
2617
- }
2687
+ refuseClobber(name, sharedTarget);
2618
2688
  return false;
2619
2689
  }
2620
2690
  function performAdoptMove(name, linkPath, sharedTarget, repo, backup) {
@@ -2647,18 +2717,19 @@ function cmdAdopt(name, opts = {}) {
2647
2717
  );
2648
2718
  }
2649
2719
  if (!isValidAdoptName(name)) {
2650
- fail(`invalid name: ${JSON.stringify(name)}`);
2651
- process.exit(1);
2720
+ throw new NomadFatal(`invalid name: ${JSON.stringify(name)}`, {
2721
+ code: EXIT.GENERIC_FAILURE
2722
+ });
2652
2723
  }
2653
2724
  const repo = repoHome();
2654
2725
  const claude = claudeHome();
2655
2726
  const backup = backupBase();
2656
2727
  const map = readMapIfPresent(repo);
2657
2728
  if (!isConfiguredTarget(name, map)) {
2658
- fail(
2659
- `${name}: not a configured shared target. Add it to sharedDirs in path-map.json first, then re-run adopt.`
2729
+ throw new NomadFatal(
2730
+ `${name}: not a configured shared target. Add it to sharedDirs in path-map.json first, then re-run adopt.`,
2731
+ { code: EXIT.GENERIC_FAILURE }
2660
2732
  );
2661
- process.exit(1);
2662
2733
  }
2663
2734
  const linkPath = join9(claude, name);
2664
2735
  const sharedTarget = join9(repo, "shared", name);
@@ -2880,7 +2951,7 @@ async function cmdCaptureSettings(opts) {
2880
2951
  init_config();
2881
2952
  init_exit_codes();
2882
2953
  init_utils();
2883
- import { existsSync as existsSync8, lstatSync as lstatSync8, readdirSync as readdirSync4, rmSync as rmSync5, statSync as statSync2 } from "node:fs";
2954
+ import { existsSync as existsSync8, lstatSync as lstatSync8, readdirSync as readdirSync4, rmSync as rmSync5, statSync as statSync3 } from "node:fs";
2884
2955
  import { join as join12 } from "node:path";
2885
2956
  var TS_SHAPE = /^\d{8}-\d{6}(-\d+)?$/;
2886
2957
  var DURATION_RE = /^(\d+)([dhm])$/;
@@ -2899,7 +2970,7 @@ function parseDuration(s) {
2899
2970
  }
2900
2971
  function listBackupDirs(backupBase2) {
2901
2972
  if (!existsSync8(backupBase2)) return [];
2902
- return readdirSync4(backupBase2).filter(isTsDir).map((name) => ({ name, mtimeMs: statSync2(join12(backupBase2, name)).mtimeMs })).sort((a, b) => b.mtimeMs - a.mtimeMs);
2973
+ return readdirSync4(backupBase2).filter(isTsDir).map((name) => ({ name, mtimeMs: statSync3(join12(backupBase2, name)).mtimeMs })).sort((a, b) => b.mtimeMs - a.mtimeMs);
2903
2974
  }
2904
2975
  function holdsNoContent(dir) {
2905
2976
  let entries;
@@ -3180,14 +3251,14 @@ function cmdEject(opts = {}, roots = defaultEjectRoots()) {
3180
3251
  }
3181
3252
 
3182
3253
  // src/commands.doctor.ts
3183
- import { existsSync as existsSync36 } from "node:fs";
3184
- import { join as join48 } from "node:path";
3254
+ import { existsSync as existsSync35 } from "node:fs";
3255
+ import { join as join49 } from "node:path";
3185
3256
 
3186
3257
  // src/commands.doctor.checks.repo.ts
3187
3258
  init_color();
3188
3259
  init_config();
3189
- import { existsSync as existsSync12, lstatSync as lstatSync10, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
3190
- import { join as join16 } from "node:path";
3260
+ import { existsSync as existsSync11, lstatSync as lstatSync10, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
3261
+ import { join as join17 } from "node:path";
3191
3262
 
3192
3263
  // src/commands.doctor.format.ts
3193
3264
  init_color();
@@ -3265,7 +3336,6 @@ function readJsonSafe(path, label, section2) {
3265
3336
  // src/commands.doctor.checks.repo.win32.ts
3266
3337
  init_color();
3267
3338
  init_config();
3268
- import { existsSync as existsSync10 } from "node:fs";
3269
3339
  import { join as join14, win32 as win32Path } from "node:path";
3270
3340
 
3271
3341
  // src/extras-sync.diff.ts
@@ -3334,6 +3404,18 @@ function win32CopyUnpublishedRow(name) {
3334
3404
  fail: false
3335
3405
  };
3336
3406
  }
3407
+ function win32CopyUnusableRow(name, state) {
3408
+ if (state === "dangling") {
3409
+ return {
3410
+ line: `${yellow(warnGlyph)} ${name}: real local copy, but shared/${name} does not resolve in the repo (remove shared/${name}, or restore what it points at)`,
3411
+ fail: false
3412
+ };
3413
+ }
3414
+ return {
3415
+ line: `${yellow(warnGlyph)} ${name}: real local copy, but shared/${name} could not be read in the repo, so whether it is usable could not be determined (check its permissions in the sync repo)`,
3416
+ fail: false
3417
+ };
3418
+ }
3337
3419
  function relativeUnder(root, path) {
3338
3420
  const rel = win32Path.relative(root, path);
3339
3421
  const segments = rel.split(win32Path.sep);
@@ -3347,7 +3429,9 @@ function divergingRepoPath(line, name, local, shared) {
3347
3429
  }
3348
3430
  function classifyWin32Copy(name, p) {
3349
3431
  const sharedPath = join14(repoHome(), "shared", name);
3350
- if (!existsSync10(sharedPath)) return win32CopyUnpublishedRow(name);
3432
+ const sharedState = classifyPresence(sharedPath);
3433
+ if (sharedState === "absent") return win32CopyUnpublishedRow(name);
3434
+ if (isUnusableTarget(sharedState)) return win32CopyUnusableRow(name, sharedState);
3351
3435
  const compared = listDivergingFiles(p, sharedPath);
3352
3436
  const diverging = compared.filter(
3353
3437
  (line) => deniedSegmentFor(divergingRepoPath(line, name, p, sharedPath)) === null
@@ -3361,18 +3445,69 @@ function classifyWin32Copy(name, p) {
3361
3445
  };
3362
3446
  }
3363
3447
 
3448
+ // src/commands.doctor.checks.repo.source.ts
3449
+ init_color();
3450
+ init_config();
3451
+ import { join as join15 } from "node:path";
3452
+ function repoSourceState(name) {
3453
+ return classifyPresence(join15(repoHome(), "shared", name));
3454
+ }
3455
+ function adoptRefusalClause(name, state) {
3456
+ if (state === "dangling") {
3457
+ return `shared/${name} does not resolve, so \`nomad adopt ${name}\` would refuse (remove shared/${name}, or restore what it points at, first)`;
3458
+ }
3459
+ return `shared/${name} could not be read, so \`nomad adopt ${name}\` would refuse (check its permissions in the sync repo first)`;
3460
+ }
3461
+ function adoptWouldClobberRow(name) {
3462
+ return {
3463
+ line: `${red(failGlyph)} ${name}: NOT a symlink (blocks sync), and shared/${name} already holds content, so \`nomad adopt ${name}\` would refuse rather than choose between them (compare the two, then either remove ~/.claude/${name} and run \`nomad pull\`, or remove shared/${name} and run \`nomad adopt ${name}\`)`,
3464
+ fail: true
3465
+ };
3466
+ }
3467
+ function posixNonSymlinkRow(name) {
3468
+ const state = repoSourceState(name);
3469
+ if (isUnusableTarget(state)) {
3470
+ return {
3471
+ line: `${red(failGlyph)} ${name}: NOT a symlink (blocks sync), and ${adoptRefusalClause(name, state)}`,
3472
+ fail: true
3473
+ };
3474
+ }
3475
+ if (state === "resolves") return adoptWouldClobberRow(name);
3476
+ return {
3477
+ line: `${red(failGlyph)} ${name}: NOT a symlink (blocks sync); run \`nomad adopt ${name}\` to fix`,
3478
+ fail: true
3479
+ };
3480
+ }
3481
+ function repoSourceUnusableRow(name, state) {
3482
+ if (state === "dangling") {
3483
+ return {
3484
+ line: `${yellow(warnGlyph)} ${name}: shared/${name} in the repo does not resolve, so there is nothing to restore from (remove shared/${name}, or restore what it points at)`,
3485
+ fail: false
3486
+ };
3487
+ }
3488
+ return {
3489
+ line: `${yellow(warnGlyph)} ${name}: shared/${name} in the repo could not be read, so whether there is anything to restore from could not be determined (check its permissions in the sync repo)`,
3490
+ fail: false
3491
+ };
3492
+ }
3493
+ function repoSourceRow(name, present, absent) {
3494
+ const state = repoSourceState(name);
3495
+ if (isUnusableTarget(state)) return repoSourceUnusableRow(name, state);
3496
+ return state === "resolves" ? present : absent;
3497
+ }
3498
+
3364
3499
  // src/init.classify.ts
3365
3500
  init_config();
3366
3501
  init_utils_json();
3367
- import { existsSync as existsSync11 } from "node:fs";
3368
- import { join as join15 } from "node:path";
3502
+ import { existsSync as existsSync10 } from "node:fs";
3503
+ import { join as join16 } from "node:path";
3369
3504
  function classifyRepoState(repoHome2, host) {
3370
- const basePath = join15(repoHome2, "shared", "settings.base.json");
3371
- const mapPath = join15(repoHome2, "path-map.json");
3372
- const hostPath = join15(repoHome2, "hosts", `${host}.json`);
3373
- const hasBase = existsSync11(basePath);
3374
- const hasMap = existsSync11(mapPath);
3375
- const hasHost = existsSync11(hostPath);
3505
+ const basePath = join16(repoHome2, "shared", "settings.base.json");
3506
+ const mapPath = join16(repoHome2, "path-map.json");
3507
+ const hostPath = join16(repoHome2, "hosts", `${host}.json`);
3508
+ const hasBase = existsSync10(basePath);
3509
+ const hasMap = existsSync10(mapPath);
3510
+ const hasHost = existsSync10(hostPath);
3376
3511
  let mapEntryCount = 0;
3377
3512
  if (hasMap) {
3378
3513
  try {
@@ -3387,11 +3522,11 @@ function classifyRepoState(repoHome2, host) {
3387
3522
  return "partial";
3388
3523
  }
3389
3524
  function reasonForPartial(repoHome2, host) {
3390
- const basePath = join15(repoHome2, "shared", "settings.base.json");
3391
- const mapPath = join15(repoHome2, "path-map.json");
3392
- const hostPath = join15(repoHome2, "hosts", `${host}.json`);
3393
- if (!existsSync11(basePath)) return "- shared/settings.base.json missing";
3394
- if (!existsSync11(mapPath)) return "- path-map.json missing";
3525
+ const basePath = join16(repoHome2, "shared", "settings.base.json");
3526
+ const mapPath = join16(repoHome2, "path-map.json");
3527
+ const hostPath = join16(repoHome2, "hosts", `${host}.json`);
3528
+ if (!existsSync10(basePath)) return "- shared/settings.base.json missing";
3529
+ if (!existsSync10(mapPath)) return "- path-map.json missing";
3395
3530
  let mapEntryCount;
3396
3531
  try {
3397
3532
  const map = readJson(mapPath);
@@ -3400,7 +3535,7 @@ function reasonForPartial(repoHome2, host) {
3400
3535
  mapEntryCount = 0;
3401
3536
  }
3402
3537
  if (mapEntryCount === 0) return "- path-map.json.projects has no entries";
3403
- if (!existsSync11(hostPath)) return `- hosts/${host}.json missing`;
3538
+ if (!existsSync10(hostPath)) return `- hosts/${host}.json missing`;
3404
3539
  return "- partial state (unknown gap)";
3405
3540
  }
3406
3541
 
@@ -3417,15 +3552,15 @@ function reportHostAndPaths(section2) {
3417
3552
  if (isOverrideActive()) {
3418
3553
  addItem(section2, `${dim(infoGlyph)} NOMAD_REPO: ${blue(repo)}`);
3419
3554
  }
3420
- addItem(section2, `${existsSync12(repo) ? green(okGlyph) : yellow(warnGlyph)} repo: ${blue(repo)}`);
3555
+ addItem(section2, `${existsSync11(repo) ? green(okGlyph) : yellow(warnGlyph)} repo: ${blue(repo)}`);
3421
3556
  addItem(
3422
3557
  section2,
3423
- `${existsSync12(claude) ? green(okGlyph) : yellow(warnGlyph)} claude home: ${blue(claude)}`
3558
+ `${existsSync11(claude) ? green(okGlyph) : yellow(warnGlyph)} claude home: ${blue(claude)}`
3424
3559
  );
3425
3560
  }
3426
3561
  function pathMapHostKeys() {
3427
- const mapPath = join16(repoHome(), "path-map.json");
3428
- if (!existsSync12(mapPath)) return /* @__PURE__ */ new Set();
3562
+ const mapPath = join17(repoHome(), "path-map.json");
3563
+ if (!existsSync11(mapPath)) return /* @__PURE__ */ new Set();
3429
3564
  let raw;
3430
3565
  try {
3431
3566
  raw = readJson(mapPath);
@@ -3442,7 +3577,7 @@ function pathMapHostKeys() {
3442
3577
  function hostOverrideLabels() {
3443
3578
  let entries;
3444
3579
  try {
3445
- entries = readdirSync5(join16(repoHome(), "hosts"));
3580
+ entries = readdirSync5(join17(repoHome(), "hosts"));
3446
3581
  } catch {
3447
3582
  return /* @__PURE__ */ new Set();
3448
3583
  }
@@ -3482,9 +3617,6 @@ function reportRepoState(section2) {
3482
3617
  process.exitCode = 1;
3483
3618
  }
3484
3619
  }
3485
- function repoHasSharedSource(name) {
3486
- return existsSync12(join16(repoHome(), "shared", name));
3487
- }
3488
3620
  function classifySharedLink(name, p) {
3489
3621
  let stat;
3490
3622
  try {
@@ -3492,10 +3624,14 @@ function classifySharedLink(name, p) {
3492
3624
  } catch (err) {
3493
3625
  const code = err.code;
3494
3626
  if (code === "ENOENT") {
3495
- return repoHasSharedSource(name) ? {
3496
- line: `${yellow(warnGlyph)} ${name}: missing (run \`nomad pull\` to restore)`,
3497
- fail: false
3498
- } : { line: `${dim(infoGlyph)} ${name}: not synced (nothing in shared/)`, fail: false };
3627
+ return repoSourceRow(
3628
+ name,
3629
+ {
3630
+ line: `${yellow(warnGlyph)} ${name}: missing (run \`nomad pull\` to restore)`,
3631
+ fail: false
3632
+ },
3633
+ { line: `${dim(infoGlyph)} ${name}: not synced (nothing in shared/)`, fail: false }
3634
+ );
3499
3635
  }
3500
3636
  return { line: `${red(failGlyph)} ${name}: could not stat (${String(code)})`, fail: true };
3501
3637
  }
@@ -3503,27 +3639,28 @@ function classifySharedLink(name, p) {
3503
3639
  if (process.platform === "win32") {
3504
3640
  return classifyWin32Copy(name, p);
3505
3641
  }
3506
- return {
3507
- line: `${red(failGlyph)} ${name}: NOT a symlink (blocks sync); run \`nomad adopt ${name}\` to fix`,
3508
- fail: true
3509
- };
3642
+ return posixNonSymlinkRow(name);
3510
3643
  }
3511
3644
  return classifySymlinkTarget(name, p);
3512
3645
  }
3513
3646
  function classifySymlinkTarget(name, p) {
3514
3647
  try {
3515
- statSync3(p);
3648
+ statSync4(p);
3516
3649
  return { line: `${green(okGlyph)} ${name}: symlink`, fail: false };
3517
3650
  } catch (err) {
3518
3651
  const code = err.code;
3519
3652
  if (code === "ENOENT") {
3520
- return repoHasSharedSource(name) ? {
3521
- line: `${yellow(warnGlyph)} ${name}: broken symlink (target missing, run \`nomad pull\`)`,
3522
- fail: false
3523
- } : {
3524
- line: `${dim(infoGlyph)} ${name}: stale symlink (no longer in shared/, safe to remove)`,
3525
- fail: false
3526
- };
3653
+ return repoSourceRow(
3654
+ name,
3655
+ {
3656
+ line: `${yellow(warnGlyph)} ${name}: broken symlink (target missing, run \`nomad pull\`)`,
3657
+ fail: false
3658
+ },
3659
+ {
3660
+ line: `${dim(infoGlyph)} ${name}: stale symlink (no longer in shared/, safe to remove)`,
3661
+ fail: false
3662
+ }
3663
+ );
3527
3664
  }
3528
3665
  return {
3529
3666
  line: `${yellow(warnGlyph)} ${name}: symlink target unreadable (${String(code)})`,
@@ -3534,7 +3671,7 @@ function classifySymlinkTarget(name, p) {
3534
3671
  function reportSharedLinks(section2, map) {
3535
3672
  const claude = claudeHome();
3536
3673
  for (const name of allSharedLinks(map, { quiet: true })) {
3537
- const p = join16(claude, name);
3674
+ const p = join17(claude, name);
3538
3675
  const { line, fail: fail2, children } = classifySharedLink(name, p);
3539
3676
  addItem(section2, line);
3540
3677
  if (fail2) process.exitCode = 1;
@@ -3546,7 +3683,7 @@ function reportSharedLinks(section2, map) {
3546
3683
  function reportDroppedNamesMigration(section2) {
3547
3684
  const claude = claudeHome();
3548
3685
  for (const name of GSD_DROPPED_NAMES) {
3549
- const p = join16(claude, name);
3686
+ const p = join17(claude, name);
3550
3687
  let stat;
3551
3688
  try {
3552
3689
  stat = lstatSync10(p);
@@ -3564,11 +3701,11 @@ function reportDroppedNamesMigration(section2) {
3564
3701
  // src/commands.doctor.checks.settings.ts
3565
3702
  init_color();
3566
3703
  init_config();
3567
- import { existsSync as existsSync13, readdirSync as readdirSync6 } from "node:fs";
3568
- import { join as join17 } from "node:path";
3704
+ import { existsSync as existsSync12, readdirSync as readdirSync6 } from "node:fs";
3705
+ import { join as join18 } from "node:path";
3569
3706
  function loadBaseSettings(section2) {
3570
- const basePath = join17(repoHome(), "shared", "settings.base.json");
3571
- if (!existsSync13(basePath)) {
3707
+ const basePath = join18(repoHome(), "shared", "settings.base.json");
3708
+ if (!existsSync12(basePath)) {
3572
3709
  addItem(section2, `${red(failGlyph)} shared/settings.base.json missing at ${blue(basePath)}`);
3573
3710
  process.exitCode = 1;
3574
3711
  return null;
@@ -3576,8 +3713,8 @@ function loadBaseSettings(section2) {
3576
3713
  return readJsonSafe(basePath, basePath, section2);
3577
3714
  }
3578
3715
  function loadAndReportSettings(section2) {
3579
- const settingsPath = join17(claudeHome(), "settings.json");
3580
- if (!existsSync13(settingsPath)) return null;
3716
+ const settingsPath = join18(claudeHome(), "settings.json");
3717
+ if (!existsSync12(settingsPath)) return null;
3581
3718
  const settings = readJsonSafe(settingsPath, settingsPath, section2);
3582
3719
  if (settings === null) return null;
3583
3720
  const unknownKeys = Object.keys(settings).filter((k) => !KNOWN_SETTINGS_KEYS.has(k));
@@ -3593,13 +3730,13 @@ function loadAndReportSettings(section2) {
3593
3730
  }
3594
3731
  function reportHostOverrides(section2, base, settings) {
3595
3732
  const repo = repoHome();
3596
- const hostFile = join17(repo, "hosts", `${HOST}.json`);
3733
+ const hostFile = join18(repo, "hosts", `${HOST}.json`);
3597
3734
  let drift = [];
3598
3735
  if (base !== null && settings !== null) {
3599
3736
  const baseKeys = new Set(Object.keys(base));
3600
3737
  drift = Object.keys(settings).filter((k) => !baseKeys.has(k));
3601
3738
  }
3602
- if (existsSync13(hostFile)) {
3739
+ if (existsSync12(hostFile)) {
3603
3740
  if (readJsonSafe(hostFile, hostFile, section2) !== null) {
3604
3741
  addItem(section2, `${green(okGlyph)} host overrides: ${blue(hostFile)}`);
3605
3742
  }
@@ -3608,8 +3745,8 @@ function reportHostOverrides(section2, base, settings) {
3608
3745
  section2,
3609
3746
  `${red(failGlyph)} no hosts/${HOST}.json AND settings.json has unbased keys ${JSON.stringify(drift)}`
3610
3747
  );
3611
- const hostsDir = join17(repo, "hosts");
3612
- if (existsSync13(hostsDir)) {
3748
+ const hostsDir = join18(repo, "hosts");
3749
+ if (existsSync12(hostsDir)) {
3613
3750
  const cands = readdirSync6(hostsDir).filter((f) => f.endsWith(".json"));
3614
3751
  if (cands.length > 0) addItem(section2, `${dim(infoGlyph)} candidates: ${cands.join(", ")}`);
3615
3752
  }
@@ -3626,8 +3763,8 @@ function reportHostOverrides(section2, base, settings) {
3626
3763
  init_color();
3627
3764
  init_config();
3628
3765
  init_config_sharedDirs_guard();
3629
- import { existsSync as existsSync14, lstatSync as lstatSync11, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "node:fs";
3630
- import { join as join18, sep as sep4 } from "node:path";
3766
+ import { existsSync as existsSync13, lstatSync as lstatSync11, readdirSync as readdirSync7, realpathSync as realpathSync2 } from "node:fs";
3767
+ import { join as join19, sep as sep4 } from "node:path";
3631
3768
  init_utils_json();
3632
3769
  function reportMappedProjects(section2, map) {
3633
3770
  const mapped = Object.entries(map.projects).filter(([, hosts]) => hosts[HOST]);
@@ -3637,8 +3774,8 @@ function reportMappedProjects(section2, map) {
3637
3774
  }
3638
3775
  }
3639
3776
  function reportUnmappedProjects(section2, map) {
3640
- const localProjects = join18(claudeHome(), "projects");
3641
- if (!existsSync14(localProjects)) return;
3777
+ const localProjects = join19(claudeHome(), "projects");
3778
+ if (!existsSync13(localProjects)) return;
3642
3779
  let localDirs;
3643
3780
  try {
3644
3781
  localDirs = readdirSync7(localProjects);
@@ -3659,7 +3796,7 @@ function reportCurrentHostPathsMissing(section2, map) {
3659
3796
  for (const [name, hosts] of Object.entries(map.projects)) {
3660
3797
  const abspath = hosts[HOST];
3661
3798
  if (!abspath || abspath === "TBD") continue;
3662
- if (!existsSync14(abspath)) {
3799
+ if (!existsSync13(abspath)) {
3663
3800
  addItem(
3664
3801
  section2,
3665
3802
  `${yellow(warnGlyph)} path-map: ${name} local path missing on ${HOST}: ${blue(abspath)}`
@@ -3669,7 +3806,7 @@ function reportCurrentHostPathsMissing(section2, map) {
3669
3806
  }
3670
3807
  function hasSharedLeftover(entry) {
3671
3808
  try {
3672
- return lstatSync11(join18(repoHome(), "shared", entry), { throwIfNoEntry: false }) !== void 0;
3809
+ return lstatSync11(join19(repoHome(), "shared", entry), { throwIfNoEntry: false }) !== void 0;
3673
3810
  } catch {
3674
3811
  return false;
3675
3812
  }
@@ -3679,7 +3816,7 @@ var PROBEABLE_REASONS = /* @__PURE__ */ new Set([
3679
3816
  "secret-shaped"
3680
3817
  ]);
3681
3818
  function classifyLocalLink(entry) {
3682
- const linkPath = join18(claudeHome(), entry);
3819
+ const linkPath = join19(claudeHome(), entry);
3683
3820
  let stat;
3684
3821
  try {
3685
3822
  stat = lstatSync11(linkPath, { throwIfNoEntry: false });
@@ -3695,7 +3832,7 @@ function classifyLocalLink(entry) {
3695
3832
  }
3696
3833
  let root;
3697
3834
  try {
3698
- root = realpathSync2(join18(repoHome(), "shared"));
3835
+ root = realpathSync2(join19(repoHome(), "shared"));
3699
3836
  } catch {
3700
3837
  return "foreign";
3701
3838
  }
@@ -3779,8 +3916,8 @@ function reportPathCollisions(section2, map) {
3779
3916
  else addItem(section2, `${green(okGlyph)} path-encoding: no collisions`);
3780
3917
  }
3781
3918
  function reportPathMap(section2) {
3782
- const mapPath = join18(repoHome(), "path-map.json");
3783
- if (!existsSync14(mapPath)) {
3919
+ const mapPath = join19(repoHome(), "path-map.json");
3920
+ if (!existsSync13(mapPath)) {
3784
3921
  addItem(section2, `${red(failGlyph)} path-map.json missing at ${blue(mapPath)}`);
3785
3922
  process.exitCode = 1;
3786
3923
  return;
@@ -3810,8 +3947,8 @@ function reportNeverSync(section2) {
3810
3947
 
3811
3948
  // src/commands.doctor.checks.skills.ts
3812
3949
  init_color();
3813
- import { existsSync as existsSync15 } from "node:fs";
3814
- import { join as join19 } from "node:path";
3950
+ import { existsSync as existsSync14 } from "node:fs";
3951
+ import { join as join20 } from "node:path";
3815
3952
  init_config();
3816
3953
  function stripSideIndicator(line) {
3817
3954
  if (line.endsWith(" (local only)")) return line.slice(0, -" (local only)".length);
@@ -3831,13 +3968,13 @@ function isGsdDiffLine(line, localBase, sharedBase) {
3831
3968
  return relative12.split("/")[0].startsWith(GSD_PREFIX);
3832
3969
  }
3833
3970
  function reportSkillsDivergence(section2) {
3834
- const sharedSkills = join19(repoHome(), "shared", "skills");
3835
- const localSkills = join19(claudeHome(), "skills");
3836
- if (!existsSync15(sharedSkills)) {
3971
+ const sharedSkills = join20(repoHome(), "shared", "skills");
3972
+ const localSkills = join20(claudeHome(), "skills");
3973
+ if (!existsSync14(sharedSkills)) {
3837
3974
  addItem(section2, `${dim(infoGlyph)} skills: no shared/skills/ to compare`);
3838
3975
  return;
3839
3976
  }
3840
- if (!existsSync15(localSkills)) {
3977
+ if (!existsSync14(localSkills)) {
3841
3978
  addItem(section2, `${dim(infoGlyph)} skills: no local skills/ to compare`);
3842
3979
  return;
3843
3980
  }
@@ -3860,8 +3997,8 @@ function reportSkillsDivergence(section2) {
3860
3997
  init_color();
3861
3998
  init_config();
3862
3999
  import { execFileSync as execFileSync5 } from "node:child_process";
3863
- import { existsSync as existsSync18 } from "node:fs";
3864
- import { join as join23, relative as relative5 } from "node:path";
4000
+ import { existsSync as existsSync17 } from "node:fs";
4001
+ import { join as join24, relative as relative5 } from "node:path";
3865
4002
  init_commands_pull_wedge();
3866
4003
  init_push_checks();
3867
4004
  init_utils();
@@ -3884,8 +4021,8 @@ function reportGitleaksProbe(section2) {
3884
4021
  }
3885
4022
  function reportGitlinks(section2) {
3886
4023
  const repo = repoHome();
3887
- const sharedDir = join23(repo, "shared");
3888
- if (existsSync18(sharedDir)) {
4024
+ const sharedDir = join24(repo, "shared");
4025
+ if (existsSync17(sharedDir)) {
3889
4026
  const gitlinks = findGitlinks(sharedDir);
3890
4027
  for (const p of gitlinks) {
3891
4028
  const rel = relative5(repo, p).replaceAll("\\", "/");
@@ -3983,8 +4120,8 @@ function reportGitIdentity(section2) {
3983
4120
 
3984
4121
  // src/commands.doctor.checks.backups.ts
3985
4122
  init_color();
3986
- import { existsSync as existsSync19, lstatSync as lstatSync12, readdirSync as readdirSync9 } from "node:fs";
3987
- import { join as join24 } from "node:path";
4123
+ import { existsSync as existsSync18, lstatSync as lstatSync12, readdirSync as readdirSync9 } from "node:fs";
4124
+ import { join as join25 } from "node:path";
3988
4125
  init_config();
3989
4126
  var TS_SHAPE2 = /^\d{8}-\d{6}(-\d+)?$/;
3990
4127
  function safeReaddir(dir) {
@@ -4000,7 +4137,7 @@ var BYTES_PER_MB = 1024 * 1024;
4000
4137
  function dirSizeBytes(dir) {
4001
4138
  let bytes = 0;
4002
4139
  for (const entry of safeReaddir(dir)) {
4003
- const full = join24(dir, entry);
4140
+ const full = join25(dir, entry);
4004
4141
  const st = lstatSync12(full, { throwIfNoEntry: false });
4005
4142
  if (!st) continue;
4006
4143
  if (st.isSymbolicLink()) continue;
@@ -4011,11 +4148,11 @@ function dirSizeBytes(dir) {
4011
4148
  }
4012
4149
  function totalSizeMb(backupBase2, dirs) {
4013
4150
  let bytes = 0;
4014
- for (const name of dirs) bytes += dirSizeBytes(join24(backupBase2, name));
4151
+ for (const name of dirs) bytes += dirSizeBytes(join25(backupBase2, name));
4015
4152
  return bytes / BYTES_PER_MB;
4016
4153
  }
4017
4154
  function reportBackupsCheck(section2, backupBase2 = backupBase()) {
4018
- if (!existsSync19(backupBase2)) return;
4155
+ if (!existsSync18(backupBase2)) return;
4019
4156
  const dirs = safeReaddir(backupBase2).filter((n) => TS_SHAPE2.test(n));
4020
4157
  const count = dirs.length;
4021
4158
  const sizeMb = totalSizeMb(backupBase2, dirs);
@@ -4096,8 +4233,8 @@ function reportCheckRemote(section2) {
4096
4233
 
4097
4234
  // src/commands.doctor.check-schema.ts
4098
4235
  init_color();
4099
- import { existsSync as existsSync20 } from "node:fs";
4100
- import { join as join25 } from "node:path";
4236
+ import { existsSync as existsSync19 } from "node:fs";
4237
+ import { join as join26 } from "node:path";
4101
4238
  init_config();
4102
4239
 
4103
4240
  // src/http-fetch.ts
@@ -4134,8 +4271,8 @@ function fetchSchemaKeys() {
4134
4271
  }
4135
4272
  }
4136
4273
  function reportCheckSchema(section2) {
4137
- const settingsPath = join25(claudeHome(), "settings.json");
4138
- if (!existsSync20(settingsPath)) {
4274
+ const settingsPath = join26(claudeHome(), "settings.json");
4275
+ if (!existsSync19(settingsPath)) {
4139
4276
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json to check`);
4140
4277
  return;
4141
4278
  }
@@ -4165,9 +4302,9 @@ function reportCheckSchema(section2) {
4165
4302
  init_color();
4166
4303
  import { randomBytes as randomBytes3 } from "node:crypto";
4167
4304
  import { execFileSync as execFileSync11 } from "node:child_process";
4168
- import { existsSync as existsSync23, mkdirSync as mkdirSync8, readdirSync as readdirSync12, rmSync as rmSync12 } from "node:fs";
4305
+ import { existsSync as existsSync22, mkdirSync as mkdirSync8, readdirSync as readdirSync12, rmSync as rmSync12 } from "node:fs";
4169
4306
  import { homedir as homedir6 } from "node:os";
4170
- import { join as join32 } from "node:path";
4307
+ import { join as join33 } from "node:path";
4171
4308
 
4172
4309
  // src/commands.doctor.check-shared.memory.ts
4173
4310
  init_color();
@@ -4175,7 +4312,7 @@ import { execFileSync as execFileSync9 } from "node:child_process";
4175
4312
  import { randomBytes } from "node:crypto";
4176
4313
  import { mkdirSync as mkdirSync4, rmSync as rmSync9, writeFileSync as writeFileSync4 } from "node:fs";
4177
4314
  import { homedir as homedir4 } from "node:os";
4178
- import { dirname as dirname4, join as join27 } from "node:path";
4315
+ import { dirname as dirname4, join as join28 } from "node:path";
4179
4316
  init_config();
4180
4317
  init_push_gitleaks();
4181
4318
  init_utils_fs();
@@ -4208,7 +4345,7 @@ function buildMemoryScanTree(tmpRoot) {
4208
4345
  incomplete = true;
4209
4346
  continue;
4210
4347
  }
4211
- const dest = join27(tmpRoot, rel);
4348
+ const dest = join28(tmpRoot, rel);
4212
4349
  mkdirSync4(dirname4(dest), { recursive: true });
4213
4350
  writeFileSync4(dest, blob);
4214
4351
  logicals.add(m[1]);
@@ -4227,10 +4364,10 @@ function reportMemoryFindings(section2, findings) {
4227
4364
  function reportCommittedMemory(section2) {
4228
4365
  let tmpRoot;
4229
4366
  try {
4230
- const cacheDir = join27(homedir4(), ".cache", "claude-nomad");
4367
+ const cacheDir = join28(homedir4(), ".cache", "claude-nomad");
4231
4368
  mkdirSync4(cacheDir, { recursive: true });
4232
4369
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes(4).toString("hex")}`;
4233
- tmpRoot = join27(cacheDir, `check-shared-memory-tree-${stamp}`);
4370
+ tmpRoot = join28(cacheDir, `check-shared-memory-tree-${stamp}`);
4234
4371
  mkdirSync4(tmpRoot, { recursive: true, mode: 448 });
4235
4372
  const { staged, incomplete } = buildMemoryScanTree(tmpRoot);
4236
4373
  if (incomplete) {
@@ -4277,12 +4414,12 @@ function reportCommittedMemory(section2) {
4277
4414
 
4278
4415
  // src/commands.doctor.check-shared.scan.ts
4279
4416
  init_color();
4280
- import { join as join28 } from "node:path";
4417
+ import { join as join29 } from "node:path";
4281
4418
  init_config();
4282
4419
  init_push_gitleaks();
4283
4420
  function scrubPath(logical, sid, logicalToEncoded) {
4284
4421
  const encoded = logicalToEncoded.get(logical) ?? logical;
4285
- return join28(claudeHome(), "projects", encoded, `${sid}.jsonl`);
4422
+ return join29(claudeHome(), "projects", encoded, `${sid}.jsonl`);
4286
4423
  }
4287
4424
  function reportSessionFindings(section2, bySession) {
4288
4425
  for (const [sid, counts] of bySession) {
@@ -4371,7 +4508,7 @@ import { execFileSync as execFileSync10 } from "node:child_process";
4371
4508
  import { randomBytes as randomBytes2 } from "node:crypto";
4372
4509
  import { mkdirSync as mkdirSync5, rmSync as rmSync10, writeFileSync as writeFileSync5 } from "node:fs";
4373
4510
  import { homedir as homedir5 } from "node:os";
4374
- import { dirname as dirname5, join as join29 } from "node:path";
4511
+ import { dirname as dirname5, join as join30 } from "node:path";
4375
4512
  init_config();
4376
4513
  init_push_gitleaks();
4377
4514
  init_utils_fs();
@@ -4404,7 +4541,7 @@ function buildSkillScanTree(tmpRoot) {
4404
4541
  incomplete = true;
4405
4542
  continue;
4406
4543
  }
4407
- const dest = join29(tmpRoot, rel);
4544
+ const dest = join30(tmpRoot, rel);
4408
4545
  mkdirSync5(dirname5(dest), { recursive: true });
4409
4546
  writeFileSync5(dest, blob);
4410
4547
  names.add(m[1]);
@@ -4427,10 +4564,10 @@ function reportSkillFindings(section2, findings) {
4427
4564
  function reportCommittedSkills(section2) {
4428
4565
  let tmpRoot;
4429
4566
  try {
4430
- const cacheDir = join29(homedir5(), ".cache", "claude-nomad");
4567
+ const cacheDir = join30(homedir5(), ".cache", "claude-nomad");
4431
4568
  mkdirSync5(cacheDir, { recursive: true });
4432
4569
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes2(4).toString("hex")}`;
4433
- tmpRoot = join29(cacheDir, `check-shared-skills-tree-${stamp}`);
4570
+ tmpRoot = join30(cacheDir, `check-shared-skills-tree-${stamp}`);
4434
4571
  mkdirSync5(tmpRoot, { recursive: true, mode: 448 });
4435
4572
  const { staged, incomplete } = buildSkillScanTree(tmpRoot);
4436
4573
  if (incomplete) {
@@ -4480,8 +4617,8 @@ init_config();
4480
4617
 
4481
4618
  // src/remap.ts
4482
4619
  init_config_sharedDirs_guard();
4483
- import { cpSync as cpSync5, existsSync as existsSync22, lstatSync as lstatSync13, mkdirSync as mkdirSync7, readdirSync as readdirSync11, rmSync as rmSync11, statSync as statSync5 } from "node:fs";
4484
- import { dirname as dirname7, join as join31, relative as relative6, sep as sep5 } from "node:path";
4620
+ import { cpSync as cpSync5, existsSync as existsSync21, lstatSync as lstatSync13, mkdirSync as mkdirSync7, readdirSync as readdirSync11, rmSync as rmSync11, statSync as statSync6 } from "node:fs";
4621
+ import { dirname as dirname7, join as join32, relative as relative6, sep as sep5 } from "node:path";
4485
4622
  init_config();
4486
4623
 
4487
4624
  // src/push-manifest.ts
@@ -4489,8 +4626,8 @@ init_config();
4489
4626
  init_push_gitleaks_config();
4490
4627
  init_utils_fs();
4491
4628
  import { createHash } from "node:crypto";
4492
- import { existsSync as existsSync21, mkdirSync as mkdirSync6, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync4 } from "node:fs";
4493
- import { dirname as dirname6, join as join30 } from "node:path";
4629
+ import { existsSync as existsSync20, mkdirSync as mkdirSync6, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync5 } from "node:fs";
4630
+ import { dirname as dirname6, join as join31 } from "node:path";
4494
4631
  function isChanged(prev, cur, hash) {
4495
4632
  if (prev === void 0) return true;
4496
4633
  if (prev.size !== cur.size) return true;
@@ -4531,8 +4668,8 @@ function hashFile(absPath) {
4531
4668
  }
4532
4669
  function enumerateDir(dir, results) {
4533
4670
  for (const entry of readdirSync10(dir)) {
4534
- const fullPath = join30(dir, entry);
4535
- const st = statSync4(fullPath);
4671
+ const fullPath = join31(dir, entry);
4672
+ const st = statSync5(fullPath);
4536
4673
  if (st.isDirectory()) {
4537
4674
  enumerateDir(fullPath, results);
4538
4675
  } else {
@@ -4543,8 +4680,8 @@ function enumerateDir(dir, results) {
4543
4680
  function enumerateSourceFiles(projectDir) {
4544
4681
  const results = [];
4545
4682
  for (const entry of readdirSync10(projectDir)) {
4546
- const fullPath = join30(projectDir, entry);
4547
- const st = statSync4(fullPath);
4683
+ const fullPath = join31(projectDir, entry);
4684
+ const st = statSync5(fullPath);
4548
4685
  if (st.isDirectory()) {
4549
4686
  enumerateDir(fullPath, results);
4550
4687
  } else if (fullPath.endsWith(".jsonl")) {
@@ -4555,15 +4692,15 @@ function enumerateSourceFiles(projectDir) {
4555
4692
  }
4556
4693
  function fileIdentity(p) {
4557
4694
  if (p === null) return "none::absent";
4558
- if (!existsSync21(p)) return `${p}::absent`;
4695
+ if (!existsSync20(p)) return `${p}::absent`;
4559
4696
  return `${p}::${createHash("sha256").update(readFileSync7(p)).digest("hex")}`;
4560
4697
  }
4561
4698
  function computeConfigHash() {
4562
4699
  const repo = repoHome();
4563
4700
  const parts = [
4564
4701
  fileIdentity(resolveTomlPath(repo)),
4565
- fileIdentity(join30(repo, ".gitleaks.overlay.toml")),
4566
- fileIdentity(join30(repo, ".gitleaksignore"))
4702
+ fileIdentity(join31(repo, ".gitleaks.overlay.toml")),
4703
+ fileIdentity(join31(repo, ".gitleaksignore"))
4567
4704
  ];
4568
4705
  return createHash("sha256").update(parts.join("\n")).digest("hex");
4569
4706
  }
@@ -4625,12 +4762,12 @@ function applySelective(sel, localDir, repoDst) {
4625
4762
  const prefix = `${localDir}${sep5}`;
4626
4763
  for (const src of sel.changed) {
4627
4764
  if (!src.startsWith(prefix)) continue;
4628
- copyFileAtomic(src, join31(repoDst, relative6(localDir, src)));
4765
+ copyFileAtomic(src, join32(repoDst, relative6(localDir, src)));
4629
4766
  }
4630
4767
  for (const src of sel.deleted) {
4631
4768
  if (!src.startsWith(prefix)) continue;
4632
- const dst = join31(repoDst, relative6(localDir, src));
4633
- if (existsSync22(dst)) rmSync11(dst);
4769
+ const dst = join32(repoDst, relative6(localDir, src));
4770
+ if (existsSync21(dst)) rmSync11(dst);
4634
4771
  }
4635
4772
  }
4636
4773
  function copyDirJsonlOnly(src, dst) {
@@ -4641,7 +4778,7 @@ function copyDirJsonlOnly(src, dst) {
4641
4778
  const rel = relative6(src, srcPath);
4642
4779
  if (rel === "") return true;
4643
4780
  if (rel.split(sep5).length > 1) return true;
4644
- if (statSync5(srcPath).isDirectory()) return true;
4781
+ if (statSync6(srcPath).isDirectory()) return true;
4645
4782
  if (srcPath.endsWith(".jsonl")) return true;
4646
4783
  item(`skip ${rel}: extension not in allowlist`);
4647
4784
  return false;
@@ -4659,15 +4796,15 @@ function remapPull(ts, opts = {}) {
4659
4796
  const wouldPull = [];
4660
4797
  const repo = repoHome();
4661
4798
  const claude = claudeHome();
4662
- const mapPath = join31(repo, "path-map.json");
4663
- const repoProjects = join31(repo, "shared", "projects");
4664
- if (!existsSync22(mapPath) || !existsSync22(repoProjects)) {
4799
+ const mapPath = join32(repo, "path-map.json");
4800
+ const repoProjects = join32(repo, "shared", "projects");
4801
+ if (!existsSync21(mapPath) || !existsSync21(repoProjects)) {
4665
4802
  const text = "no path-map or repo projects dir; skipping session remap";
4666
4803
  emitPreview(opts.onPreview, { kind: "note", text }, text);
4667
4804
  return { unmapped: 0, pulled, wouldPull };
4668
4805
  }
4669
4806
  const map = readPathMap(mapPath);
4670
- const localProjects = join31(claude, "projects");
4807
+ const localProjects = join32(claude, "projects");
4671
4808
  if (!dryRun) mkdirSync7(localProjects, { recursive: true });
4672
4809
  for (const [logical, hosts] of Object.entries(map.projects)) {
4673
4810
  assertSafeLogical(logical);
@@ -4677,9 +4814,9 @@ function remapPull(ts, opts = {}) {
4677
4814
  continue;
4678
4815
  }
4679
4816
  assertSafeLocalRoot(localPath, logical);
4680
- const src = join31(repoProjects, logical);
4681
- if (!existsSync22(src)) continue;
4682
- const dst = join31(localProjects, encodePath(localPath));
4817
+ const src = join32(repoProjects, logical);
4818
+ if (!existsSync21(src)) continue;
4819
+ const dst = join32(localProjects, encodePath(localPath));
4683
4820
  if (dryRun) {
4684
4821
  wouldPull.push(logical);
4685
4822
  emitPreview(
@@ -4698,8 +4835,8 @@ function remapPull(ts, opts = {}) {
4698
4835
  function countLocalOnly(src, dst) {
4699
4836
  let count = 0;
4700
4837
  for (const name of readdirSync11(dst)) {
4701
- const dstPath = join31(dst, name);
4702
- const srcPath = join31(src, name);
4838
+ const dstPath = join32(dst, name);
4839
+ const srcPath = join32(src, name);
4703
4840
  if (lstatSync13(dstPath).isDirectory()) {
4704
4841
  count += countLocalOnly(srcPath, dstPath);
4705
4842
  } else if (lstatSync13(srcPath, { throwIfNoEntry: false }) === void 0) {
@@ -4711,20 +4848,20 @@ function countLocalOnly(src, dst) {
4711
4848
  function scanLocalOnly() {
4712
4849
  const repo = repoHome();
4713
4850
  const claude = claudeHome();
4714
- const mapPath = join31(repo, "path-map.json");
4715
- const repoProjects = join31(repo, "shared", "projects");
4716
- if (!existsSync22(mapPath) || !existsSync22(repoProjects)) return 0;
4851
+ const mapPath = join32(repo, "path-map.json");
4852
+ const repoProjects = join32(repo, "shared", "projects");
4853
+ if (!existsSync21(mapPath) || !existsSync21(repoProjects)) return 0;
4717
4854
  const map = readPathMap(mapPath);
4718
- const localProjects = join31(claude, "projects");
4855
+ const localProjects = join32(claude, "projects");
4719
4856
  let count = 0;
4720
4857
  for (const [logical, hosts] of Object.entries(map.projects)) {
4721
4858
  assertSafeLogical(logical);
4722
4859
  const localPath = hosts[HOST];
4723
4860
  if (!localPath || localPath === "TBD") continue;
4724
4861
  assertSafeLocalRoot(localPath, logical);
4725
- const dst = join31(localProjects, encodePath(localPath));
4726
- if (!existsSync22(dst)) continue;
4727
- count += countLocalOnly(join31(repoProjects, logical), dst);
4862
+ const dst = join32(localProjects, encodePath(localPath));
4863
+ if (!existsSync21(dst)) continue;
4864
+ count += countLocalOnly(join32(repoProjects, logical), dst);
4728
4865
  }
4729
4866
  return count;
4730
4867
  }
@@ -4759,16 +4896,16 @@ function remapPush(ts, opts = {}) {
4759
4896
  const wouldPush = [];
4760
4897
  const repo = repoHome();
4761
4898
  const claude = claudeHome();
4762
- const mapPath = join31(repo, "path-map.json");
4763
- if (!existsSync22(mapPath)) {
4899
+ const mapPath = join32(repo, "path-map.json");
4900
+ if (!existsSync21(mapPath)) {
4764
4901
  log("no path-map.json; skipping session export");
4765
4902
  return { unmapped: 0, collisions: 0, pushed, wouldPush };
4766
4903
  }
4767
4904
  const map = readPathMap(mapPath);
4768
- const localProjects = join31(claude, "projects");
4769
- const repoProjects = join31(repo, "shared", "projects");
4905
+ const localProjects = join32(claude, "projects");
4906
+ const repoProjects = join32(repo, "shared", "projects");
4770
4907
  const reverse = buildReverseMap(map);
4771
- if (!existsSync22(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
4908
+ if (!existsSync21(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
4772
4909
  if (!dryRun) mkdirSync7(repoProjects, { recursive: true });
4773
4910
  for (const dir of readdirSync11(localProjects)) {
4774
4911
  if (dir.endsWith(TMP_SUFFIX)) continue;
@@ -4777,8 +4914,8 @@ function remapPush(ts, opts = {}) {
4777
4914
  unmapped++;
4778
4915
  continue;
4779
4916
  }
4780
- const localDir = join31(localProjects, dir);
4781
- const repoDst = join31(repoProjects, logical);
4917
+ const localDir = join32(localProjects, dir);
4918
+ const repoDst = join32(repoProjects, logical);
4782
4919
  if (skipForSelection(opts.selection, localDir)) continue;
4783
4920
  if (dryRun) {
4784
4921
  wouldPush.push(logical);
@@ -4802,8 +4939,8 @@ function buildScanTree(tmpRoot) {
4802
4939
  const logicalToEncoded = /* @__PURE__ */ new Map();
4803
4940
  let staged = 0;
4804
4941
  const repo = repoHome();
4805
- const mapPath = join32(repo, "path-map.json");
4806
- if (!existsSync23(mapPath)) return { logicalToEncoded, staged, malformed: false };
4942
+ const mapPath = join33(repo, "path-map.json");
4943
+ if (!existsSync22(mapPath)) return { logicalToEncoded, staged, malformed: false };
4807
4944
  let map;
4808
4945
  try {
4809
4946
  map = readJson(mapPath);
@@ -4820,12 +4957,12 @@ function buildScanTree(tmpRoot) {
4820
4957
  if (!p || p === "TBD") continue;
4821
4958
  reverse.set(encodePath(p), logical);
4822
4959
  }
4823
- const localProjects = join32(claudeHome(), "projects");
4824
- if (!existsSync23(localProjects)) return { logicalToEncoded, staged, malformed: false };
4960
+ const localProjects = join33(claudeHome(), "projects");
4961
+ if (!existsSync22(localProjects)) return { logicalToEncoded, staged, malformed: false };
4825
4962
  for (const dir of readdirSync12(localProjects)) {
4826
4963
  const logical = reverse.get(dir);
4827
4964
  if (!logical) continue;
4828
- copyDirJsonlOnly(join32(localProjects, dir), join32(tmpRoot, "shared", "projects", logical));
4965
+ copyDirJsonlOnly(join33(localProjects, dir), join33(tmpRoot, "shared", "projects", logical));
4829
4966
  logicalToEncoded.set(logical, dir);
4830
4967
  staged++;
4831
4968
  }
@@ -4855,11 +4992,11 @@ function ensureGitleaksReady(section2, gitleaksReady) {
4855
4992
  return true;
4856
4993
  }
4857
4994
  function runLocalPreviewScan(section2) {
4858
- const cacheDir = join32(homedir6(), ".cache", "claude-nomad");
4995
+ const cacheDir = join33(homedir6(), ".cache", "claude-nomad");
4859
4996
  mkdirSync8(cacheDir, { recursive: true });
4860
4997
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes3(4).toString("hex")}`;
4861
- const reportPath = join32(cacheDir, `check-shared-${stamp}.json`);
4862
- const tmpRoot = join32(cacheDir, `check-shared-tree-${stamp}`);
4998
+ const reportPath = join33(cacheDir, `check-shared-${stamp}.json`);
4999
+ const tmpRoot = join33(cacheDir, `check-shared-tree-${stamp}`);
4863
5000
  try {
4864
5001
  const { logicalToEncoded, staged, malformed } = buildScanTree(tmpRoot);
4865
5002
  if (malformed) {
@@ -4892,8 +5029,8 @@ function reportCheckShared(section2, gitleaksReady) {
4892
5029
 
4893
5030
  // src/commands.doctor.checks.hooks.scope.ts
4894
5031
  init_color();
4895
- import { existsSync as existsSync24, readFileSync as readFileSync8, readdirSync as readdirSync13, realpathSync as realpathSync3 } from "node:fs";
4896
- import { dirname as dirname8, extname, join as join33 } from "node:path";
5032
+ import { existsSync as existsSync23, readFileSync as readFileSync8, readdirSync as readdirSync13, realpathSync as realpathSync3 } from "node:fs";
5033
+ import { dirname as dirname8, extname, join as join34 } from "node:path";
4897
5034
  init_config();
4898
5035
  function typeFromPackageJson(pkgPath) {
4899
5036
  try {
@@ -4915,8 +5052,8 @@ function effectiveType(hookPath) {
4915
5052
  }
4916
5053
  let dir = dirname8(real);
4917
5054
  for (; ; ) {
4918
- const pkg = join33(dir, "package.json");
4919
- if (existsSync24(pkg)) return typeFromPackageJson(pkg);
5055
+ const pkg = join34(dir, "package.json");
5056
+ if (existsSync23(pkg)) return typeFromPackageJson(pkg);
4920
5057
  const parent = dirname8(dir);
4921
5058
  if (parent === dir) return "cjs";
4922
5059
  dir = parent;
@@ -4958,15 +5095,15 @@ function safeRead(path) {
4958
5095
  }
4959
5096
  }
4960
5097
  function reportHookScopeCheck(section2) {
4961
- const hooksDir = join33(claudeHome(), "hooks");
4962
- if (!existsSync24(hooksDir)) {
5098
+ const hooksDir = join34(claudeHome(), "hooks");
5099
+ if (!existsSync23(hooksDir)) {
4963
5100
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/hooks; skipping module-scope check`);
4964
5101
  return;
4965
5102
  }
4966
5103
  let anyWarn = false;
4967
5104
  for (const name of safeReaddir2(hooksDir)) {
4968
5105
  if (extname(name) !== ".js") continue;
4969
- const abs = join33(hooksDir, name);
5106
+ const abs = join34(hooksDir, name);
4970
5107
  const eff = effectiveType(abs);
4971
5108
  if (eff === null) continue;
4972
5109
  const src = safeRead(abs);
@@ -4986,8 +5123,8 @@ function reportHookScopeCheck(section2) {
4986
5123
 
4987
5124
  // src/commands.doctor.checks.hooks.ts
4988
5125
  init_color();
4989
- import { existsSync as existsSync25 } from "node:fs";
4990
- import { join as join34 } from "node:path";
5126
+ import { existsSync as existsSync24 } from "node:fs";
5127
+ import { join as join35 } from "node:path";
4991
5128
  init_config();
4992
5129
  function expandHome(token) {
4993
5130
  const h2 = home();
@@ -5030,7 +5167,7 @@ function checkEventGroups(section2, event, groups) {
5030
5167
  for (const group of groups) {
5031
5168
  for (const cmd of commandsFromGroup(group)) {
5032
5169
  for (const resolved of claudePathsIn(cmd)) {
5033
- if (existsSync25(resolved)) continue;
5170
+ if (existsSync24(resolved)) continue;
5034
5171
  addItem(
5035
5172
  section2,
5036
5173
  `${red(failGlyph)} hooks/${event}: command target missing: ${resolved} (run nomad pull)`
@@ -5043,8 +5180,8 @@ function checkEventGroups(section2, event, groups) {
5043
5180
  return anyFail;
5044
5181
  }
5045
5182
  function reportHooksTargetCheck(section2) {
5046
- const settingsPath = join34(claudeHome(), "settings.json");
5047
- if (!existsSync25(settingsPath)) {
5183
+ const settingsPath = join35(claudeHome(), "settings.json");
5184
+ if (!existsSync24(settingsPath)) {
5048
5185
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping hook target check`);
5049
5186
  return;
5050
5187
  }
@@ -5067,12 +5204,12 @@ function reportHooksTargetCheck(section2) {
5067
5204
 
5068
5205
  // src/commands.doctor.checks.hooks.preserve-symlinks.ts
5069
5206
  init_color();
5070
- import { existsSync as existsSync27, readFileSync as readFileSync9 } from "node:fs";
5071
- import { join as join36 } from "node:path";
5207
+ import { existsSync as existsSync26, readFileSync as readFileSync9 } from "node:fs";
5208
+ import { join as join37 } from "node:path";
5072
5209
 
5073
5210
  // src/commands.doctor.checks.hooks.preserve-symlinks.probe.ts
5074
- import { closeSync as closeSync3, existsSync as existsSync26, openSync as openSync3, readSync, realpathSync as realpathSync4 } from "node:fs";
5075
- import { dirname as dirname9, join as join35, resolve as resolve3 } from "node:path";
5211
+ import { closeSync as closeSync3, existsSync as existsSync25, openSync as openSync3, readSync, realpathSync as realpathSync4 } from "node:fs";
5212
+ import { dirname as dirname9, join as join36, resolve as resolve3 } from "node:path";
5076
5213
  function suppressedRanges(src) {
5077
5214
  const ranges = [];
5078
5215
  const re = /\/\*[\s\S]*?\*\/|\/\/[^\n]*|'[^']*'|"[^"]*"|`[^`]*`/g;
@@ -5104,12 +5241,12 @@ function topRelativeSpecifiers(src) {
5104
5241
  }
5105
5242
  function specifierIsMissing(specifier, baseDir) {
5106
5243
  const base = resolve3(baseDir, specifier);
5107
- if (existsSync26(base)) return false;
5244
+ if (existsSync25(base)) return false;
5108
5245
  for (const ext of [".js", ".cjs", ".mjs"]) {
5109
- if (existsSync26(base + ext)) return false;
5246
+ if (existsSync25(base + ext)) return false;
5110
5247
  }
5111
5248
  for (const idx of ["index.js", "index.cjs", "index.mjs"]) {
5112
- if (existsSync26(join35(base, idx))) return false;
5249
+ if (existsSync25(join36(base, idx))) return false;
5113
5250
  }
5114
5251
  return true;
5115
5252
  }
@@ -5164,8 +5301,8 @@ function commandTokens(command) {
5164
5301
  return tokens;
5165
5302
  }
5166
5303
  function readPathMapSafe() {
5167
- const mapPath = join36(repoHome(), "path-map.json");
5168
- if (!existsSync27(mapPath)) return { projects: {} };
5304
+ const mapPath = join37(repoHome(), "path-map.json");
5305
+ if (!existsSync26(mapPath)) return { projects: {} };
5169
5306
  try {
5170
5307
  return JSON.parse(readFileSync9(mapPath, "utf8"));
5171
5308
  } catch {
@@ -5239,8 +5376,8 @@ function checkEventForPreserveSymlinks(section2, event, groups, sharedLinkNames)
5239
5376
  return anyWarn;
5240
5377
  }
5241
5378
  function reportPreserveSymlinksCheck(section2) {
5242
- const settingsPath = join36(claudeHome(), "settings.json");
5243
- if (!existsSync27(settingsPath)) {
5379
+ const settingsPath = join37(claudeHome(), "settings.json");
5380
+ if (!existsSync26(settingsPath)) {
5244
5381
  addItem(
5245
5382
  section2,
5246
5383
  `${dim(infoGlyph)} no ~/.claude/settings.json; skipping preserve-symlinks-main check`
@@ -5273,8 +5410,8 @@ function reportPreserveSymlinksCheck(section2) {
5273
5410
 
5274
5411
  // src/commands.doctor.checks.settings-drift.ts
5275
5412
  init_color();
5276
- import { existsSync as existsSync28, readFileSync as readFileSync10 } from "node:fs";
5277
- import { join as join37 } from "node:path";
5413
+ import { existsSync as existsSync27, readFileSync as readFileSync10 } from "node:fs";
5414
+ import { join as join38 } from "node:path";
5278
5415
  init_config();
5279
5416
  init_utils_json();
5280
5417
  function diffMergedSettings(merged, settings) {
@@ -5292,7 +5429,7 @@ function tryReadJson(filePath) {
5292
5429
  }
5293
5430
  }
5294
5431
  function reportHooksBaseSelfCleanNote(section2) {
5295
- const basePath = join37(repoHome(), "shared", "settings.base.json");
5432
+ const basePath = join38(repoHome(), "shared", "settings.base.json");
5296
5433
  const base = tryReadJson(basePath);
5297
5434
  if (base === null) return;
5298
5435
  if (!baseHasGsdHookEntries(base)) return;
@@ -5305,14 +5442,14 @@ function reportSettingsDriftCheck(section2) {
5305
5442
  const claude = claudeHome();
5306
5443
  const repo = repoHome();
5307
5444
  const host = HOST;
5308
- const settingsPath = join37(claude, "settings.json");
5309
- const basePath = join37(repo, "shared", "settings.base.json");
5310
- const hostPath = join37(repo, "hosts", `${host}.json`);
5311
- if (!existsSync28(settingsPath)) {
5445
+ const settingsPath = join38(claude, "settings.json");
5446
+ const basePath = join38(repo, "shared", "settings.base.json");
5447
+ const hostPath = join38(repo, "hosts", `${host}.json`);
5448
+ if (!existsSync27(settingsPath)) {
5312
5449
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping merge-drift check`);
5313
5450
  return;
5314
5451
  }
5315
- if (!existsSync28(basePath)) {
5452
+ if (!existsSync27(basePath)) {
5316
5453
  addItem(
5317
5454
  section2,
5318
5455
  `${dim(infoGlyph)} shared/settings.base.json missing; skipping merge-drift check`
@@ -5331,7 +5468,7 @@ function reportSettingsDriftCheck(section2) {
5331
5468
  if (settings === null) {
5332
5469
  return;
5333
5470
  }
5334
- const hostExists = existsSync28(hostPath);
5471
+ const hostExists = existsSync27(hostPath);
5335
5472
  const hostObj = hostExists ? tryReadJson(hostPath) : null;
5336
5473
  if (hostExists && hostObj === null) {
5337
5474
  addItem(
@@ -5548,15 +5685,15 @@ function reportSyncModality(section2) {
5548
5685
  // src/commands.doctor.checks.crlf.ts
5549
5686
  init_color();
5550
5687
  import { execFileSync as execFileSync13 } from "node:child_process";
5551
- import { existsSync as existsSync29, readFileSync as readFileSync13 } from "node:fs";
5552
- import { join as join38 } from "node:path";
5688
+ import { existsSync as existsSync28, readFileSync as readFileSync13 } from "node:fs";
5689
+ import { join as join39 } from "node:path";
5553
5690
  init_config();
5554
5691
  var PROBE_TIMEOUT_MS2 = 3e3;
5555
5692
  var GUARD_LINE = /^\*\s+-text\b/;
5556
5693
  function hasGitattributesGuard(repo) {
5557
5694
  try {
5558
- const path = join38(repo, ".gitattributes");
5559
- if (!existsSync29(path)) return false;
5695
+ const path = join39(repo, ".gitattributes");
5696
+ if (!existsSync28(path)) return false;
5560
5697
  const content = readFileSync13(path, "utf8");
5561
5698
  return content.split("\n").map((line) => line.trim()).some((line) => line !== "" && !line.startsWith("#") && GUARD_LINE.test(line));
5562
5699
  } catch {
@@ -5597,14 +5734,14 @@ function reportCrlfGuardCheck(section2, run = execFileSync13) {
5597
5734
 
5598
5735
  // src/spinner.ts
5599
5736
  init_color();
5600
- import { existsSync as existsSync34 } from "node:fs";
5737
+ import { existsSync as existsSync33 } from "node:fs";
5601
5738
  import { fileURLToPath as fileURLToPath4 } from "node:url";
5602
5739
  import { Worker } from "node:worker_threads";
5603
5740
 
5604
5741
  // src/commands.push.recovery.ts
5605
5742
  init_config();
5606
5743
  import { readFileSync as readFileSync18, rmSync as rmSync15, writeFileSync as writeFileSync9 } from "node:fs";
5607
- import { join as join46 } from "node:path";
5744
+ import { join as join47 } from "node:path";
5608
5745
  import { createInterface as createInterface2 } from "node:readline/promises";
5609
5746
 
5610
5747
  // src/commands.push.recovery.actions.ts
@@ -5621,10 +5758,10 @@ import {
5621
5758
  mkdirSync as mkdirSync9,
5622
5759
  readFileSync as readFileSync14,
5623
5760
  realpathSync as realpathSync5,
5624
- statSync as statSync6,
5761
+ statSync as statSync7,
5625
5762
  writeFileSync as writeFileSync6
5626
5763
  } from "node:fs";
5627
- import { dirname as dirname10, join as join39, sep as sep6 } from "node:path";
5764
+ import { dirname as dirname10, join as join40, sep as sep6 } from "node:path";
5628
5765
  init_push_gitleaks_scan();
5629
5766
 
5630
5767
  // src/rel-path-guard.ts
@@ -5653,15 +5790,15 @@ function resolveMemoryLocalPath(logical, relPath, map) {
5653
5790
  if (!isSafeRelPath(relPath)) return null;
5654
5791
  const abs = map.projects[logical]?.[HOST];
5655
5792
  if (abs === void 0) return null;
5656
- const memoryRoot = join39(claudeHome(), "projects", encodePath(abs), "memory");
5657
- const localPath = join39(memoryRoot, ...relPath.split("/"));
5793
+ const memoryRoot = join40(claudeHome(), "projects", encodePath(abs), "memory");
5794
+ const localPath = join40(memoryRoot, ...relPath.split("/"));
5658
5795
  if (localPath !== memoryRoot && !localPath.startsWith(memoryRoot + sep6)) return null;
5659
5796
  try {
5660
5797
  if (lstatSync14(localPath).isSymbolicLink()) return null;
5661
5798
  const realLocal = realpathSync5(localPath);
5662
5799
  const realRoot = realpathSync5(memoryRoot);
5663
5800
  if (!realLocal.startsWith(realRoot + sep6)) return null;
5664
- if (!statSync6(realLocal).isFile()) return null;
5801
+ if (!statSync7(realLocal).isFile()) return null;
5665
5802
  } catch {
5666
5803
  return null;
5667
5804
  }
@@ -5708,7 +5845,7 @@ function applyMemoryRedact(f, ts, map, scan = scanFile) {
5708
5845
  );
5709
5846
  }
5710
5847
  writeFileSync6(localPath, after, "utf8");
5711
- const dest = join39(repoHome(), "shared", "projects", logical, "memory", ...relPath.split("/"));
5848
+ const dest = join40(repoHome(), "shared", "projects", logical, "memory", ...relPath.split("/"));
5712
5849
  mkdirSync9(dirname10(dest), { recursive: true });
5713
5850
  cpSync6(localPath, dest, { force: true });
5714
5851
  return true;
@@ -5722,15 +5859,15 @@ import {
5722
5859
  mkdirSync as mkdirSync11,
5723
5860
  readFileSync as readFileSync15,
5724
5861
  realpathSync as realpathSync6,
5725
- statSync as statSync7,
5862
+ statSync as statSync8,
5726
5863
  writeFileSync as writeFileSync7
5727
5864
  } from "node:fs";
5728
- import { dirname as dirname11, join as join41, sep as sep7 } from "node:path";
5865
+ import { dirname as dirname11, join as join42, sep as sep7 } from "node:path";
5729
5866
 
5730
5867
  // src/skills-sync.ts
5731
5868
  init_config();
5732
- import { existsSync as existsSync30, lstatSync as lstatSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync14, rmSync as rmSync13 } from "node:fs";
5733
- import { join as join40 } from "node:path";
5869
+ import { existsSync as existsSync29, lstatSync as lstatSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync14, rmSync as rmSync13 } from "node:fs";
5870
+ import { join as join41 } from "node:path";
5734
5871
 
5735
5872
  // src/skills-sync.tracked.ts
5736
5873
  init_utils();
@@ -5765,9 +5902,9 @@ function copySkillsPull(src, dst, isRootPreserved) {
5765
5902
  copyExtrasFilteredPreservingBy(src, dst, isSkillExcluded, isRootPreserved);
5766
5903
  }
5767
5904
  function syncSkillsPull(ts, prePostHeads) {
5768
- const sharedSkills = join40(repoHome(), "shared", "skills");
5769
- if (!existsSync30(sharedSkills)) return;
5770
- const localSkills = join40(claudeHome(), "skills");
5905
+ const sharedSkills = join41(repoHome(), "shared", "skills");
5906
+ if (!existsSync29(sharedSkills)) return;
5907
+ const localSkills = join41(claudeHome(), "skills");
5771
5908
  backupBeforeWrite(localSkills, ts);
5772
5909
  const dstStat = lstatSync15(localSkills, { throwIfNoEntry: false });
5773
5910
  if (dstStat?.isSymbolicLink() === true) {
@@ -5778,11 +5915,11 @@ function syncSkillsPull(ts, prePostHeads) {
5778
5915
  copySkillsPull(sharedSkills, localSkills, (name) => !tracked.has(name));
5779
5916
  }
5780
5917
  function syncSkillsPush() {
5781
- const localSkills = join40(claudeHome(), "skills");
5918
+ const localSkills = join41(claudeHome(), "skills");
5782
5919
  const stat = lstatSync15(localSkills, { throwIfNoEntry: false });
5783
5920
  if (stat === void 0) return;
5784
5921
  if (stat.isSymbolicLink()) return;
5785
- const sharedSkills = join40(repoHome(), "shared", "skills");
5922
+ const sharedSkills = join41(repoHome(), "shared", "skills");
5786
5923
  copySkillsPush(localSkills, sharedSkills);
5787
5924
  }
5788
5925
 
@@ -5805,16 +5942,16 @@ function resolveSkillLocalPath(name, relPath) {
5805
5942
  if (!SAFE_SKILL_NAME.test(name) || name === "." || name === "..") return null;
5806
5943
  if (isGsdOwned(name)) return null;
5807
5944
  if (!isSafeRelPath(relPath)) return null;
5808
- const skillsRoot = join41(claudeHome(), "skills");
5809
- const skillRoot = join41(skillsRoot, name);
5810
- const localPath = join41(skillRoot, ...relPath.split("/"));
5945
+ const skillsRoot = join42(claudeHome(), "skills");
5946
+ const skillRoot = join42(skillsRoot, name);
5947
+ const localPath = join42(skillRoot, ...relPath.split("/"));
5811
5948
  if (localPath !== skillRoot && !localPath.startsWith(skillRoot + sep7)) return null;
5812
5949
  try {
5813
5950
  if (lstatSync16(localPath).isSymbolicLink()) return null;
5814
5951
  const realLocal = realpathSync6(localPath);
5815
5952
  const realRoot = realpathSync6(skillsRoot);
5816
5953
  if (!realLocal.startsWith(realRoot + sep7)) return null;
5817
- if (!statSync7(realLocal).isFile()) return null;
5954
+ if (!statSync8(realLocal).isFile()) return null;
5818
5955
  } catch {
5819
5956
  return null;
5820
5957
  }
@@ -5859,7 +5996,7 @@ function applySkillRedact(f, ts, scan = scanFile) {
5859
5996
  );
5860
5997
  }
5861
5998
  writeFileSync7(localPath, after, "utf8");
5862
- const dest = join41(repoHome(), "shared", "skills", name, ...relPath.split("/"));
5999
+ const dest = join42(repoHome(), "shared", "skills", name, ...relPath.split("/"));
5863
6000
  mkdirSync11(dirname11(dest), { recursive: true });
5864
6001
  cpSync7(localPath, dest, { force: true });
5865
6002
  return true;
@@ -5937,25 +6074,25 @@ function applyDeferredAllows(findings, state, repo) {
5937
6074
  // src/commands.push.recovery.redact.ts
5938
6075
  init_config();
5939
6076
  init_config_sharedDirs_guard();
5940
- import { cpSync as cpSync8, existsSync as existsSync33, mkdirSync as mkdirSync12 } from "node:fs";
5941
- import { dirname as dirname13, join as join44, sep as sep8 } from "node:path";
6077
+ import { cpSync as cpSync8, existsSync as existsSync32, mkdirSync as mkdirSync12 } from "node:fs";
6078
+ import { dirname as dirname13, join as join45, sep as sep8 } from "node:path";
5942
6079
 
5943
6080
  // src/commands.redact.ts
5944
6081
  init_config();
5945
- import { existsSync as existsSync32 } from "node:fs";
5946
- import { dirname as dirname12, join as join43 } from "node:path";
6082
+ import { existsSync as existsSync31 } from "node:fs";
6083
+ import { dirname as dirname12, join as join44 } from "node:path";
5947
6084
 
5948
6085
  // src/commands.redact.subtree.ts
5949
- import { existsSync as existsSync31, lstatSync as lstatSync17, readFileSync as readFileSync16, readdirSync as readdirSync15, statSync as statSync8, writeFileSync as writeFileSync8 } from "node:fs";
5950
- import { join as join42 } from "node:path";
6086
+ import { existsSync as existsSync30, lstatSync as lstatSync17, readFileSync as readFileSync16, readdirSync as readdirSync15, statSync as statSync9, writeFileSync as writeFileSync8 } from "node:fs";
6087
+ import { join as join43 } from "node:path";
5951
6088
  init_utils_fs();
5952
6089
  init_utils();
5953
6090
  function collectFiles(dir, out) {
5954
- if (!existsSync31(dir)) return;
6091
+ if (!existsSync30(dir)) return;
5955
6092
  const st = lstatSync17(dir);
5956
6093
  if (!st.isDirectory()) return;
5957
6094
  for (const entry of readdirSync15(dir)) {
5958
- const abs = join42(dir, entry);
6095
+ const abs = join43(dir, entry);
5959
6096
  const lst = lstatSync17(abs);
5960
6097
  if (lst.isSymbolicLink()) continue;
5961
6098
  if (lst.isDirectory()) {
@@ -5970,7 +6107,7 @@ function listSubtreeFiles(sessionDir) {
5970
6107
  collectFiles(sessionDir, out);
5971
6108
  return out.sort((a, b) => a.localeCompare(b));
5972
6109
  }
5973
- function newestSubtreeMtimeMs(mainPath, subtreeFiles, statMtime = (p) => statSync8(p).mtimeMs) {
6110
+ function newestSubtreeMtimeMs(mainPath, subtreeFiles, statMtime = (p) => statSync9(p).mtimeMs) {
5974
6111
  let newest = statMtime(mainPath);
5975
6112
  for (const filePath of subtreeFiles) {
5976
6113
  const t = statMtime(filePath);
@@ -5979,7 +6116,7 @@ function newestSubtreeMtimeMs(mainPath, subtreeFiles, statMtime = (p) => statSyn
5979
6116
  return newest;
5980
6117
  }
5981
6118
  function isSubtreeActive(mainPath, subtreeFiles, now) {
5982
- const subtreeMtime = newestSubtreeMtimeMs(mainPath, subtreeFiles, (p) => statSync8(p).mtimeMs);
6119
+ const subtreeMtime = newestSubtreeMtimeMs(mainPath, subtreeFiles, (p) => statSync9(p).mtimeMs);
5983
6120
  return isRecentlyModified(subtreeMtime, now);
5984
6121
  }
5985
6122
  function applySubtreeRedactions(mainPath, mainFindings, subtreeFiles, rule, ts, scan, dryRun) {
@@ -6065,15 +6202,15 @@ init_utils_json();
6065
6202
  init_utils();
6066
6203
  function resolveLiveTranscript(id) {
6067
6204
  try {
6068
- const mapPath = join43(repoHome(), "path-map.json");
6069
- if (!existsSync32(mapPath)) return null;
6205
+ const mapPath = join44(repoHome(), "path-map.json");
6206
+ if (!existsSync31(mapPath)) return null;
6070
6207
  const projects = readJson(mapPath).projects;
6071
6208
  const claude = claudeHome();
6072
6209
  for (const hostMap of Object.values(projects)) {
6073
6210
  const abs = hostMap[HOST];
6074
6211
  if (abs === void 0) continue;
6075
- const live = join43(claude, "projects", encodePath(abs), `${id}.jsonl`);
6076
- if (existsSync32(live)) return live;
6212
+ const live = join44(claude, "projects", encodePath(abs), `${id}.jsonl`);
6213
+ if (existsSync31(live)) return live;
6077
6214
  }
6078
6215
  return null;
6079
6216
  } catch {
@@ -6093,17 +6230,17 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
6093
6230
  }
6094
6231
  const repo = repoHome();
6095
6232
  const backup = backupBase();
6096
- if (!existsSync32(repo)) die(`repo not cloned at ${repo}`);
6233
+ if (!existsSync31(repo)) die(`repo not cloned at ${repo}`);
6097
6234
  const handle = acquireLock("redact");
6098
6235
  if (handle === null) process.exit(0);
6099
6236
  try {
6100
6237
  const localPath = resolveLiveTranscript(id);
6101
- if (localPath === null || !existsSync32(localPath)) {
6238
+ if (localPath === null || !existsSync31(localPath)) {
6102
6239
  fail(`could not resolve local transcript for session ${id} on this host`);
6103
6240
  process.exitCode = 1;
6104
6241
  return;
6105
6242
  }
6106
- const sessionDir = join43(dirname12(localPath), id);
6243
+ const sessionDir = join44(dirname12(localPath), id);
6107
6244
  const subtreeFiles = listSubtreeFiles(sessionDir);
6108
6245
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6109
6246
  log(
@@ -6164,8 +6301,8 @@ function resolveStagedDir(localPath, map, claude, repo) {
6164
6301
  assertSafeLogical(logical);
6165
6302
  const abs = hostMap[HOST];
6166
6303
  if (abs === void 0) continue;
6167
- if (localPath.startsWith(join44(claude, "projects", encodePath(abs)) + sep8)) {
6168
- return join44(repo, "shared", "projects", logical);
6304
+ if (localPath.startsWith(join45(claude, "projects", encodePath(abs)) + sep8)) {
6305
+ return join45(repo, "shared", "projects", logical);
6169
6306
  }
6170
6307
  }
6171
6308
  return null;
@@ -6175,7 +6312,7 @@ function preflightRedactable(f, map, nowMs) {
6175
6312
  if (sid === null) return "a finding has no resolvable session id (not a session transcript)";
6176
6313
  const localPath = resolveLiveTranscript(sid);
6177
6314
  if (localPath === null) return `session ${sid}: local transcript not found`;
6178
- const sessionDir = join44(dirname13(localPath), sid);
6315
+ const sessionDir = join45(dirname13(localPath), sid);
6179
6316
  const subtreeFiles = listSubtreeFiles(sessionDir);
6180
6317
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6181
6318
  return `session ${sid}: looks active (modified within the last 5 minutes)`;
@@ -6204,7 +6341,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
6204
6341
  `could not locate the local transcript for session ${sid}; choose Skip or Drop session.`
6205
6342
  );
6206
6343
  }
6207
- const sessionDir = join44(dirname13(localPath), sid);
6344
+ const sessionDir = join45(dirname13(localPath), sid);
6208
6345
  const subtreeFiles = listSubtreeFiles(sessionDir);
6209
6346
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6210
6347
  return refuse(
@@ -6237,9 +6374,9 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
6237
6374
  );
6238
6375
  }
6239
6376
  mkdirSync12(stagedProjectDir, { recursive: true });
6240
- cpSync8(localPath, join44(stagedProjectDir, `${sid}.jsonl`), { force: true });
6241
- if (existsSync33(sessionDir)) {
6242
- cpSync8(sessionDir, join44(stagedProjectDir, sid), { force: true, recursive: true });
6377
+ cpSync8(localPath, join45(stagedProjectDir, `${sid}.jsonl`), { force: true });
6378
+ if (existsSync32(sessionDir)) {
6379
+ cpSync8(sessionDir, join45(stagedProjectDir, sid), { force: true, recursive: true });
6243
6380
  }
6244
6381
  return true;
6245
6382
  }
@@ -6247,14 +6384,14 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
6247
6384
  // src/commands.push.recovery.drop.ts
6248
6385
  init_config();
6249
6386
  import { rmSync as rmSync14 } from "node:fs";
6250
- import { join as join45 } from "node:path";
6387
+ import { join as join46 } from "node:path";
6251
6388
  function dropSessionFromStaged(sid, map) {
6252
6389
  const logicals = Object.keys(map.projects);
6253
6390
  if (logicals.length === 0) return false;
6254
6391
  const repo = repoHome();
6255
6392
  for (const logical of logicals) {
6256
- const jsonl = join45(repo, "shared", "projects", logical, `${sid}.jsonl`);
6257
- const dir = join45(repo, "shared", "projects", logical, sid);
6393
+ const jsonl = join46(repo, "shared", "projects", logical, `${sid}.jsonl`);
6394
+ const dir = join46(repo, "shared", "projects", logical, sid);
6258
6395
  rmSync14(jsonl, { force: true });
6259
6396
  rmSync14(dir, { recursive: true, force: true });
6260
6397
  }
@@ -6739,7 +6876,7 @@ function applyThenRescan(scanVerdict, repoHome2) {
6739
6876
  return next;
6740
6877
  }
6741
6878
  function allowThenRescan(append, scanVerdict, repoHome2) {
6742
- const ignPath = join46(repoHome2, ".gitleaksignore");
6879
+ const ignPath = join47(repoHome2, ".gitleaksignore");
6743
6880
  let before;
6744
6881
  try {
6745
6882
  before = readFileSync18(ignPath, "utf8");
@@ -6845,7 +6982,7 @@ function writeAnimatedDone(out, label, ms, useTTY) {
6845
6982
  `);
6846
6983
  }
6847
6984
  function resolveWorkerPath(deps = {}) {
6848
- const check = deps.existsSyncFn ?? existsSync34;
6985
+ const check = deps.existsSyncFn ?? existsSync33;
6849
6986
  const base = deps.baseUrl ?? import.meta.url;
6850
6987
  const mjs = fileURLToPath4(new URL("./nomad.worker.mjs", base));
6851
6988
  if (check(mjs)) return mjs;
@@ -6912,8 +7049,8 @@ function withSpinner(label, fn, deps) {
6912
7049
  // src/commands.doctor.gitleaks-version.ts
6913
7050
  init_color();
6914
7051
  import { execFileSync as execFileSync15 } from "node:child_process";
6915
- import { existsSync as existsSync35 } from "node:fs";
6916
- import { join as join47 } from "node:path";
7052
+ import { existsSync as existsSync34 } from "node:fs";
7053
+ import { join as join48 } from "node:path";
6917
7054
  init_config();
6918
7055
  var SEMVER_MAJOR_MINOR = /^(\d+)\.(\d+)\.\d+$/;
6919
7056
  var GITLEAKS_TIMEOUT_MS = 5e3;
@@ -6922,7 +7059,7 @@ function majorMinorOf(value) {
6922
7059
  return m === null ? null : [m[1], m[2]];
6923
7060
  }
6924
7061
  function readGitleaksVersion(run, tomlExists) {
6925
- const tomlPath = join47(repoHome(), ".gitleaks.toml");
7062
+ const tomlPath = join48(repoHome(), ".gitleaks.toml");
6926
7063
  const args = ["version"];
6927
7064
  if (tomlExists(tomlPath)) args.push("--config", tomlPath);
6928
7065
  try {
@@ -6934,7 +7071,7 @@ function readGitleaksVersion(run, tomlExists) {
6934
7071
  return null;
6935
7072
  }
6936
7073
  }
6937
- function reportGitleaksVersionCheck(section2, run = execFileSync15, tomlExists = existsSync35) {
7074
+ function reportGitleaksVersionCheck(section2, run = execFileSync15, tomlExists = existsSync34) {
6938
7075
  const raw = readGitleaksVersion(run, tomlExists);
6939
7076
  if (raw === null) return;
6940
7077
  const local = majorMinorOf(raw);
@@ -7191,8 +7328,8 @@ function gatherDoctorSections(opts) {
7191
7328
  reportLongPathsCheck(host);
7192
7329
  reportCrlfGuardCheck(host);
7193
7330
  const links = section("Shared links");
7194
- const mapPath = join48(repoHome(), "path-map.json");
7195
- const rawMap = existsSync36(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
7331
+ const mapPath = join49(repoHome(), "path-map.json");
7332
+ const rawMap = existsSync35(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
7196
7333
  const map = rawMap ?? { projects: {} };
7197
7334
  reportSharedLinks(links, map);
7198
7335
  reportDroppedNamesMigration(links);
@@ -7290,8 +7427,8 @@ function parseDoctorArgs(args) {
7290
7427
  // src/commands.drop-session.ts
7291
7428
  init_config();
7292
7429
  import { execFileSync as execFileSync20 } from "node:child_process";
7293
- import { existsSync as existsSync38, readdirSync as readdirSync16, statSync as statSync9 } from "node:fs";
7294
- import { join as join50, relative as relative7 } from "node:path";
7430
+ import { existsSync as existsSync37, readdirSync as readdirSync16, statSync as statSync10 } from "node:fs";
7431
+ import { join as join51, relative as relative7 } from "node:path";
7295
7432
 
7296
7433
  // src/commands.drop-session.git.ts
7297
7434
  import { execFileSync as execFileSync19 } from "node:child_process";
@@ -7334,8 +7471,8 @@ function isInIndex(rel, repo) {
7334
7471
  init_config();
7335
7472
  init_utils();
7336
7473
  init_utils_json();
7337
- import { existsSync as existsSync37 } from "node:fs";
7338
- import { join as join49 } from "node:path";
7474
+ import { existsSync as existsSync36 } from "node:fs";
7475
+ import { join as join50 } from "node:path";
7339
7476
  var SHARED_PROJECT_LOGICAL = /^shared\/projects\/([^/]+)\//;
7340
7477
  function reportScrubHint(id, matches) {
7341
7478
  const live = resolveLiveTranscript2(id, matches);
@@ -7351,8 +7488,8 @@ function reportScrubHint(id, matches) {
7351
7488
  }
7352
7489
  function resolveLiveTranscript2(id, matches) {
7353
7490
  try {
7354
- const mapPath = join49(repoHome(), "path-map.json");
7355
- if (!existsSync37(mapPath)) return null;
7491
+ const mapPath = join50(repoHome(), "path-map.json");
7492
+ if (!existsSync36(mapPath)) return null;
7356
7493
  const projects = readJson(mapPath).projects;
7357
7494
  const claude = claudeHome();
7358
7495
  for (const rel of matches) {
@@ -7360,8 +7497,8 @@ function resolveLiveTranscript2(id, matches) {
7360
7497
  if (logical === void 0) continue;
7361
7498
  const abs = projects[logical]?.[HOST];
7362
7499
  if (abs === void 0) continue;
7363
- const live = join49(claude, "projects", encodePath(abs), `${id}.jsonl`);
7364
- if (existsSync37(live)) return live;
7500
+ const live = join50(claude, "projects", encodePath(abs), `${id}.jsonl`);
7501
+ if (existsSync36(live)) return live;
7365
7502
  }
7366
7503
  return null;
7367
7504
  } catch {
@@ -7377,12 +7514,12 @@ function cmdDropSession(id) {
7377
7514
  process.exit(1);
7378
7515
  }
7379
7516
  const repo = repoHome();
7380
- if (!existsSync38(repo)) die(`repo not cloned at ${repo}`);
7517
+ if (!existsSync37(repo)) die(`repo not cloned at ${repo}`);
7381
7518
  const handle = acquireLock("drop-session");
7382
7519
  if (handle === null) process.exit(0);
7383
7520
  try {
7384
- const repoProjects = join50(repo, "shared", "projects");
7385
- if (!existsSync38(repoProjects)) {
7521
+ const repoProjects = join51(repo, "shared", "projects");
7522
+ if (!existsSync37(repoProjects)) {
7386
7523
  throw new NomadFatal(`no staged session matches ${id}`);
7387
7524
  }
7388
7525
  const matches = collectMatches(repoProjects, id, repo);
@@ -7405,12 +7542,12 @@ function cmdDropSession(id) {
7405
7542
  function collectMatches(repoProjects, id, repo) {
7406
7543
  const matches = [];
7407
7544
  for (const logical of readdirSync16(repoProjects)) {
7408
- const candidate = join50(repoProjects, logical, `${id}.jsonl`);
7409
- if (existsSync38(candidate)) {
7545
+ const candidate = join51(repoProjects, logical, `${id}.jsonl`);
7546
+ if (existsSync37(candidate)) {
7410
7547
  matches.push(relative7(repo, candidate));
7411
7548
  }
7412
- const dir = join50(repoProjects, logical, id);
7413
- if (existsSync38(dir) && statSync9(dir).isDirectory()) {
7549
+ const dir = join51(repoProjects, logical, id);
7550
+ if (existsSync37(dir) && statSync10(dir).isDirectory()) {
7414
7551
  const dirRel = relative7(repo, dir);
7415
7552
  const staged = expandStagedDir(dirRel, repo);
7416
7553
  if (staged.length > 0) matches.push(...staged);
@@ -7446,8 +7583,8 @@ function unstageOne(rel, repo) {
7446
7583
 
7447
7584
  // src/commands.pull.ts
7448
7585
  init_autostash_guard();
7449
- import { existsSync as existsSync47, mkdirSync as mkdirSync14 } from "node:fs";
7450
- import { join as join61 } from "node:path";
7586
+ import { existsSync as existsSync46, mkdirSync as mkdirSync14 } from "node:fs";
7587
+ import { join as join62 } from "node:path";
7451
7588
 
7452
7589
  // src/commands.push.sections.ts
7453
7590
  init_color();
@@ -7555,18 +7692,18 @@ init_config();
7555
7692
 
7556
7693
  // src/extras-sync.ts
7557
7694
  init_config();
7558
- import { existsSync as existsSync40, statSync as statSync10 } from "node:fs";
7559
- import { join as join53 } from "node:path";
7695
+ import { existsSync as existsSync39, statSync as statSync11 } from "node:fs";
7696
+ import { join as join54 } from "node:path";
7560
7697
  init_utils();
7561
7698
  init_utils_json();
7562
7699
 
7563
7700
  // src/extras-sync.remap.ts
7564
7701
  init_config();
7565
- import { existsSync as existsSync39, mkdirSync as mkdirSync13, readdirSync as readdirSync17, readFileSync as readFileSync19, realpathSync as realpathSync7, rmSync as rmSync16 } from "node:fs";
7566
- import { dirname as dirname14, join as join52, sep as sep11 } from "node:path";
7702
+ import { existsSync as existsSync38, mkdirSync as mkdirSync13, readdirSync as readdirSync17, readFileSync as readFileSync19, realpathSync as realpathSync7, rmSync as rmSync16 } from "node:fs";
7703
+ import { dirname as dirname14, join as join53, sep as sep11 } from "node:path";
7567
7704
 
7568
7705
  // src/extras-sync.planning-diff.ts
7569
- import { join as join51, normalize as normalize2, sep as sep10 } from "node:path";
7706
+ import { join as join52, normalize as normalize2, sep as sep10 } from "node:path";
7570
7707
  init_utils();
7571
7708
  function processRecord(fields, i, changed, deleted) {
7572
7709
  const status = fields[i];
@@ -7618,7 +7755,7 @@ function planningDeleteTargets(opts) {
7618
7755
  const { deleted } = parsePlanningDiff(raw);
7619
7756
  const logicalPrefix = "shared/extras/" + logical + "/";
7620
7757
  const prefix = logicalPrefix + ".planning/";
7621
- const planningRoot = join51(localRoot, ".planning");
7758
+ const planningRoot = join52(localRoot, ".planning");
7622
7759
  const planningRootBoundary = planningRoot + sep10;
7623
7760
  const targets = [];
7624
7761
  for (const repoPath of deleted) {
@@ -7626,7 +7763,7 @@ function planningDeleteTargets(opts) {
7626
7763
  continue;
7627
7764
  }
7628
7765
  const remainder = repoPath.slice(logicalPrefix.length);
7629
- const candidate = join51(localRoot, remainder);
7766
+ const candidate = join52(localRoot, remainder);
7630
7767
  const resolved = normalize2(candidate);
7631
7768
  if (!resolved.startsWith(planningRootBoundary)) {
7632
7769
  throw new NomadFatal(
@@ -7647,7 +7784,7 @@ function runExtrasOp(v, dryRun, paths, backup, copy) {
7647
7784
  const would = [];
7648
7785
  for (const t of eachExtrasTarget(v, counts)) {
7649
7786
  const { src, dst } = paths(t);
7650
- if (!existsSync39(src)) continue;
7787
+ if (!existsSync38(src)) continue;
7651
7788
  const item2 = `${t.logical}/${t.dirname}`;
7652
7789
  if (dryRun) {
7653
7790
  would.push(item2);
@@ -7682,7 +7819,7 @@ function isInsidePlanningRoot(parentReal, rootReal) {
7682
7819
  return parentReal === rootReal || parentReal.startsWith(rootReal + sep11);
7683
7820
  }
7684
7821
  function deletePlanningTarget(target, planningRoot, repoCounterpart) {
7685
- if (existsSync39(repoCounterpart)) return;
7822
+ if (existsSync38(repoCounterpart)) return;
7686
7823
  const parentReal = tryRealpath(dirname14(target));
7687
7824
  if (parentReal === void 0) return;
7688
7825
  const rootReal = tryRealpath(planningRoot);
@@ -7692,7 +7829,7 @@ function deletePlanningTarget(target, planningRoot, repoCounterpart) {
7692
7829
  pruneEmptyAncestors(target, planningRoot);
7693
7830
  }
7694
7831
  function localDivergesFromPreDelete(target, pre, repoRel, repo) {
7695
- if (!existsSync39(target)) return false;
7832
+ if (!existsSync38(target)) return false;
7696
7833
  try {
7697
7834
  const preBlob = gitCaptureBuffer(["show", `${pre}:${repoRel}`], repo);
7698
7835
  return !readFileSync19(target).equals(preBlob);
@@ -7737,7 +7874,7 @@ function keptDeletePreview(v, prePostHeads, repo) {
7737
7874
  return kept;
7738
7875
  }
7739
7876
  function propagatePlanningDeletes(v, ts, prePostHeads, repo) {
7740
- const repoExtras = join52(repo, "shared", "extras");
7877
+ const repoExtras = join53(repo, "shared", "extras");
7741
7878
  for (const t of eachExtrasTarget(v, { unmapped: 0, skipped: 0 })) {
7742
7879
  if (t.dirname !== ".planning") continue;
7743
7880
  let raw;
@@ -7752,14 +7889,14 @@ function propagatePlanningDeletes(v, ts, prePostHeads, repo) {
7752
7889
  }
7753
7890
  const pairs = deletePairsFor(t, raw);
7754
7891
  if (pairs.length === 0) continue;
7755
- backupExtrasWrite(join52(t.localRoot, t.dirname), ts, t.localRoot);
7756
- const planningRoot = join52(t.localRoot, ".planning");
7892
+ backupExtrasWrite(join53(t.localRoot, t.dirname), ts, t.localRoot);
7893
+ const planningRoot = join53(t.localRoot, ".planning");
7757
7894
  for (const { target, relToLocal, repoRel } of pairs) {
7758
7895
  if (localDivergesFromPreDelete(target, prePostHeads.pre, repoRel, repo)) {
7759
7896
  warn(keptDeleteWarnLine(t.logical, relToLocal));
7760
7897
  continue;
7761
7898
  }
7762
- deletePlanningTarget(target, planningRoot, join52(repoExtras, t.logical, relToLocal));
7899
+ deletePlanningTarget(target, planningRoot, join53(repoExtras, t.logical, relToLocal));
7763
7900
  }
7764
7901
  }
7765
7902
  }
@@ -7768,14 +7905,14 @@ function remapExtrasPush(ts, opts = {}) {
7768
7905
  const v = loadValidatedExtras({ missingMsg: "no path-map.json; skipping extras push" });
7769
7906
  if (v === null) return { unmapped: 0, skipped: 0, pushed: [], wouldPush: [] };
7770
7907
  const repo = repoHome();
7771
- const repoExtras = join52(repo, "shared", "extras");
7908
+ const repoExtras = join53(repo, "shared", "extras");
7772
7909
  if (!dryRun) mkdirSync13(repoExtras, { recursive: true });
7773
7910
  const { unmapped, skipped, done, would } = runExtrasOp(
7774
7911
  v,
7775
7912
  dryRun,
7776
7913
  ({ localRoot, logical, dirname: dirname15 }) => ({
7777
- src: join52(localRoot, dirname15),
7778
- dst: join52(repoExtras, logical, dirname15)
7914
+ src: join53(localRoot, dirname15),
7915
+ dst: join53(repoExtras, logical, dirname15)
7779
7916
  }),
7780
7917
  (dst) => backupRepoWrite(dst, ts, repo),
7781
7918
  // Push copy routing per extra type:
@@ -7805,8 +7942,8 @@ function remapExtrasPull(ts, opts = {}) {
7805
7942
  v,
7806
7943
  dryRun,
7807
7944
  ({ localRoot, logical, dirname: dirname15 }) => ({
7808
- src: join52(repo, "shared", "extras", logical, dirname15),
7809
- dst: join52(localRoot, dirname15)
7945
+ src: join53(repo, "shared", "extras", logical, dirname15),
7946
+ dst: join53(localRoot, dirname15)
7810
7947
  }),
7811
7948
  // Snapshot the host-side dst BEFORE the copy step touches it. Anchor on
7812
7949
  // localRoot so the backup tree mirrors the project layout.
@@ -7853,22 +7990,22 @@ function divergenceCheckExtras(ts, prePostHeads) {
7853
7990
  const v = loadValidatedExtras({});
7854
7991
  if (v === null) return 0;
7855
7992
  const counts = { unmapped: 0, skipped: 0 };
7856
- const backupRoot = join53(backupBase(), ts, "extras");
7993
+ const backupRoot = join54(backupBase(), ts, "extras");
7857
7994
  const repo = repoHome();
7858
7995
  let divergedCount = 0;
7859
7996
  for (const { logical, localRoot, dirname: dirname15 } of eachExtrasTarget(v, counts)) {
7860
- const local = join53(localRoot, dirname15);
7861
- const repoEntry = join53(repo, "shared", "extras", logical, dirname15);
7862
- if (!existsSync40(local) || !existsSync40(repoEntry)) continue;
7997
+ const local = join54(localRoot, dirname15);
7998
+ const repoEntry = join54(repo, "shared", "extras", logical, dirname15);
7999
+ if (!existsSync39(local) || !existsSync39(repoEntry)) continue;
7863
8000
  const modified = listDivergingModified(local, repoEntry);
7864
8001
  if (modified.length === 0) continue;
7865
8002
  divergedCount += modified.length;
7866
- const projectBackupRoot = join53(backupRoot, encodePath(localRoot));
8003
+ const projectBackupRoot = join54(backupRoot, encodePath(localRoot));
7867
8004
  warn(
7868
8005
  divergenceWarnLine({
7869
8006
  dirname: dirname15,
7870
8007
  logical,
7871
- isDir: statSync10(local).isDirectory(),
8008
+ isDir: statSync11(local).isDirectory(),
7872
8009
  count: modified.length,
7873
8010
  projectBackupRoot
7874
8011
  })
@@ -7886,7 +8023,7 @@ function divergenceCheckExtras(ts, prePostHeads) {
7886
8023
  // src/links.baseline.ts
7887
8024
  init_config();
7888
8025
  import { lstatSync as lstatSync18, readdirSync as readdirSync18 } from "node:fs";
7889
- import { join as join54, relative as relative8, sep as sep12 } from "node:path";
8026
+ import { join as join55, relative as relative8, sep as sep12 } from "node:path";
7890
8027
  init_utils();
7891
8028
  var SHARED_BASELINE_KIND = "shared-links-baseline/1";
7892
8029
  var SHARED_BASELINE_CONFIG_HASH = "not-applicable";
@@ -7928,7 +8065,7 @@ function collectSharedFiles(dir, claude, scan) {
7928
8065
  return;
7929
8066
  }
7930
8067
  for (const entry of entries) {
7931
- const abs = join54(dir, entry);
8068
+ const abs = join55(dir, entry);
7932
8069
  if (isDeniedName(ALWAYS_NEVER_SYNC, entry)) {
7933
8070
  scan.declined.push(baselineKey(claude, abs));
7934
8071
  continue;
@@ -7944,7 +8081,7 @@ function enumerateLocalSharedScan(map, opts = {}) {
7944
8081
  scan.declined.push(name);
7945
8082
  continue;
7946
8083
  }
7947
- addLocalPath(join54(claude, name), claude, scan);
8084
+ addLocalPath(join55(claude, name), claude, scan);
7948
8085
  }
7949
8086
  return scan;
7950
8087
  }
@@ -7956,7 +8093,7 @@ function buildSharedBaseline(map, opts = {}) {
7956
8093
  const files = {};
7957
8094
  for (const [key, st] of Object.entries(enumerateLocalSharedFiles(map, opts))) {
7958
8095
  try {
7959
- files[key] = { size: st.size, mtime: st.mtime, hash: hashFile(join54(claude, key)) };
8096
+ files[key] = { size: st.size, mtime: st.mtime, hash: hashFile(join55(claude, key)) };
7960
8097
  } catch {
7961
8098
  }
7962
8099
  }
@@ -7973,8 +8110,8 @@ function writeSharedBaseline(map, opts = {}) {
7973
8110
 
7974
8111
  // src/commands.pull.win32.ts
7975
8112
  init_color();
7976
- import { existsSync as existsSync45 } from "node:fs";
7977
- import { join as join59 } from "node:path";
8113
+ import { existsSync as existsSync44 } from "node:fs";
8114
+ import { join as join60 } from "node:path";
7978
8115
 
7979
8116
  // src/commands.pull.recovery.git.ts
7980
8117
  init_utils();
@@ -8037,8 +8174,8 @@ function gitProbe(args, repo) {
8037
8174
 
8038
8175
  // src/links.deletions.ts
8039
8176
  init_config();
8040
- import { existsSync as existsSync41, lstatSync as lstatSync19, rmSync as rmSync17 } from "node:fs";
8041
- import { join as join55, relative as relative9, resolve as resolve5, sep as sep13 } from "node:path";
8177
+ import { existsSync as existsSync40, lstatSync as lstatSync19, rmSync as rmSync17 } from "node:fs";
8178
+ import { join as join56, relative as relative9, resolve as resolve5, sep as sep13 } from "node:path";
8042
8179
  init_utils();
8043
8180
  init_utils_fs();
8044
8181
  function isUnknown(declined, key) {
@@ -8048,15 +8185,15 @@ function deletionFor(key, names, claude, sharedRoot) {
8048
8185
  const segments = key.split("/");
8049
8186
  const name = segments[0];
8050
8187
  if (!names.has(name)) return null;
8051
- if (!existsSync41(join55(claude, name))) return null;
8188
+ if (!existsSync40(join56(claude, name))) return null;
8052
8189
  if (segments.some((segment) => isDeniedName(ALWAYS_NEVER_SYNC, segment))) return null;
8053
8190
  const repoPath = resolve5(sharedRoot, key);
8054
- const rel = relative9(join55(sharedRoot, name), repoPath);
8191
+ const rel = relative9(join56(sharedRoot, name), repoPath);
8055
8192
  if (rel === "" || rel === ".." || rel.startsWith(`..${sep13}`)) return null;
8056
8193
  if (segments.some((segment) => segment === "" || segment === "." || segment === ".."))
8057
8194
  return null;
8058
- if (!existsSync41(repoPath)) return null;
8059
- return { kind: "deletion", name, localPath: join55(claude, key), repoPath };
8195
+ if (!existsSync40(repoPath)) return null;
8196
+ return { kind: "deletion", name, localPath: join56(claude, key), repoPath };
8060
8197
  }
8061
8198
  function planSharedLinkDeletions(map, opts = {}) {
8062
8199
  if (process.platform !== "win32") return [];
@@ -8064,7 +8201,7 @@ function planSharedLinkDeletions(map, opts = {}) {
8064
8201
  const baseline = readSharedBaseline();
8065
8202
  if (baseline === null) return [];
8066
8203
  const claude = claudeHome();
8067
- const sharedRoot = join55(repoHome(), "shared");
8204
+ const sharedRoot = join56(repoHome(), "shared");
8068
8205
  const linkNames = opts.linkNames ?? allSharedLinks(map);
8069
8206
  const scan = enumerateLocalSharedScan(map, { linkNames });
8070
8207
  const present = new Set(Object.keys(scan.files).map((key) => key.toLowerCase()));
@@ -8098,8 +8235,8 @@ function applySharedLinkDeletions(map, ts, opts = {}) {
8098
8235
 
8099
8236
  // src/links.mirror.ts
8100
8237
  init_config();
8101
- import { existsSync as existsSync42, lstatSync as lstatSync20, rmSync as rmSync18 } from "node:fs";
8102
- import { join as join56 } from "node:path";
8238
+ import { existsSync as existsSync41, lstatSync as lstatSync20, rmSync as rmSync18, statSync as statSync12 } from "node:fs";
8239
+ import { join as join57 } from "node:path";
8103
8240
  init_utils();
8104
8241
  init_utils_fs();
8105
8242
  function emitMirror(onPreview, name, localPath, repoPath) {
@@ -8112,31 +8249,52 @@ function emitMirror(onPreview, name, localPath, repoPath) {
8112
8249
  function emitMirrorWet(onPreview, name, localPath, repoPath) {
8113
8250
  if (onPreview) onPreview({ kind: "mirror", name, localPath, repoPath });
8114
8251
  }
8115
- function notShared(policy, target) {
8116
- return !policy.adoptNew && !existsSync42(target);
8252
+ function notShared(target) {
8253
+ return !existsSync41(target);
8254
+ }
8255
+ function warnUnusableSharedTarget(name, dryRun, state) {
8256
+ const reason = state === "dangling" ? `shared/${name} does not resolve to anything usable in the sync repo. Remove it, or restore what it points at` : `shared/${name} could not be read in the sync repo, so whether it is usable could not be determined. Check its permissions there`;
8257
+ if (dryRun) {
8258
+ warn(`${name} would not be captured into shared/: ${reason}`);
8259
+ return;
8260
+ }
8261
+ warn(`${name} was not captured into shared/ this run: ${reason}, then run \`nomad push\` again`);
8262
+ }
8263
+ function warnUnreadableLocalName(name, target, err, dryRun) {
8264
+ const compoundState = classifyPresence(target);
8265
+ if (isUnusableTarget(compoundState)) {
8266
+ warnUnusableSharedTarget(name, dryRun, compoundState);
8267
+ return;
8268
+ }
8269
+ if (notShared(target)) return;
8270
+ if (dryRun) {
8271
+ warn(
8272
+ `${name} could not be read (${errorText(err)}), so nothing was captured for it and nothing was written. A pull that captures shared edits would skip it too. Check its permissions, or whether another program has it open`
8273
+ );
8274
+ return;
8275
+ }
8276
+ warn(
8277
+ `${name} could not be read (${errorText(err)}), so it was left out of shared/ this run. Check its permissions, or whether another program has it open`
8278
+ );
8117
8279
  }
8118
8280
  function mirrorOneSharedName(name, claude, repo, policy, opts) {
8119
- const localPath = join56(claude, name);
8120
- const target = join56(repo, "shared", name);
8281
+ const localPath = join57(claude, name);
8282
+ const target = join57(repo, "shared", name);
8121
8283
  let stat;
8122
8284
  try {
8123
8285
  stat = lstatSync20(localPath, { throwIfNoEntry: false });
8124
8286
  } catch (err) {
8125
- if (notShared(policy, target)) return;
8126
- if (opts.dryRun === true) {
8127
- warn(
8128
- `${name} could not be read (${err.message}), so nothing was captured for it and nothing was written. A pull that captures shared edits would skip it too. Check its permissions, or whether another program has it open`
8129
- );
8130
- return;
8131
- }
8132
- warn(
8133
- `${name} could not be read (${err.message}), so it was left out of shared/ this run. Check its permissions, or whether another program has it open`
8134
- );
8287
+ warnUnreadableLocalName(name, target, err, opts.dryRun === true);
8135
8288
  return;
8136
8289
  }
8137
8290
  if (stat === void 0) return;
8138
8291
  if (stat.isSymbolicLink()) return;
8139
- if (notShared(policy, target)) return;
8292
+ const targetState = classifyPresence(target);
8293
+ if (isUnusableTarget(targetState)) {
8294
+ warnUnusableSharedTarget(name, opts.dryRun === true, targetState);
8295
+ return;
8296
+ }
8297
+ if (notShared(target)) return;
8140
8298
  if (opts.dryRun === true) {
8141
8299
  emitMirror(opts.onPreview, name, localPath, target);
8142
8300
  return;
@@ -8149,21 +8307,58 @@ function mirrorOneSharedName(name, claude, repo, policy, opts) {
8149
8307
  }
8150
8308
  emitMirrorWet(opts.onPreview, name, localPath, target);
8151
8309
  }
8310
+ function warnUnusableSharedDir(dryRun, state) {
8311
+ const reason = state === "dangling" ? "shared/ does not resolve to anything usable in the sync repo. Remove it, or restore what it points at" : "shared/ could not be read in the sync repo, so whether it is usable could not be determined. Check its permissions there";
8312
+ if (dryRun) {
8313
+ warn(`no shared name would be captured into shared/: ${reason}`);
8314
+ return;
8315
+ }
8316
+ warn(
8317
+ `no shared name was captured into shared/ this run: ${reason}, then run \`nomad push\` again`
8318
+ );
8319
+ }
8320
+ function resolvesToDirectory(p) {
8321
+ try {
8322
+ return statSync12(p).isDirectory();
8323
+ } catch {
8324
+ return false;
8325
+ }
8326
+ }
8327
+ function warnSharedNotADirectory(dryRun) {
8328
+ const reason = "shared/ in the sync repo is not a directory, so there is nowhere to capture names into. Replace it with the shared/ directory the repo expects";
8329
+ if (dryRun) {
8330
+ warn(`no shared name would be captured into shared/: ${reason}`);
8331
+ return;
8332
+ }
8333
+ warn(
8334
+ `no shared name was captured into shared/ this run: ${reason}, then run \`nomad push\` again`
8335
+ );
8336
+ }
8152
8337
  function mirrorSharedNames(map, policy, opts = {}) {
8153
8338
  if (process.platform !== "win32") return;
8154
8339
  if (map === null) return;
8155
8340
  const claude = claudeHome();
8156
8341
  const repo = repoHome();
8342
+ const sharedPath = join57(repo, "shared");
8343
+ const sharedState = classifyPresence(sharedPath);
8344
+ if (isUnusableTarget(sharedState)) {
8345
+ warnUnusableSharedDir(opts.dryRun === true, sharedState);
8346
+ return;
8347
+ }
8348
+ if (sharedState === "resolves" && !resolvesToDirectory(sharedPath)) {
8349
+ warnSharedNotADirectory(opts.dryRun === true);
8350
+ return;
8351
+ }
8157
8352
  const linkNames = opts.linkNames ?? allSharedLinks(map);
8158
8353
  for (const name of linkNames) {
8159
8354
  mirrorOneSharedName(name, claude, repo, policy, opts);
8160
8355
  }
8161
8356
  }
8162
8357
  function syncSharedLinksPush(map, opts = {}) {
8163
- mirrorSharedNames(map, { adoptNew: false, overlay: false }, opts);
8358
+ mirrorSharedNames(map, { overlay: false }, opts);
8164
8359
  }
8165
8360
  function stageLocalSharedEdits(map, ts, opts = {}) {
8166
- mirrorSharedNames(map, { adoptNew: false, overlay: true, backupTs: ts }, opts);
8361
+ mirrorSharedNames(map, { overlay: true, backupTs: ts }, opts);
8167
8362
  }
8168
8363
  function presentAt(abs) {
8169
8364
  try {
@@ -8173,7 +8368,7 @@ function presentAt(abs) {
8173
8368
  }
8174
8369
  }
8175
8370
  function removeUntrackedDenied(repo, path, segment, ts) {
8176
- const abs = join56(repo, path);
8371
+ const abs = join57(repo, path);
8177
8372
  const denied = `the path segment "${segment}" is on the never-sync list`;
8178
8373
  if (!presentAt(abs)) {
8179
8374
  warn(
@@ -8181,12 +8376,12 @@ function removeUntrackedDenied(repo, path, segment, ts) {
8181
8376
  );
8182
8377
  return;
8183
8378
  }
8184
- const snapshotted = existsSync42(abs);
8379
+ const snapshotted = existsSync41(abs);
8185
8380
  try {
8186
8381
  backupRepoWrite(abs, ts, repo);
8187
8382
  } catch (err) {
8188
8383
  warn(
8189
- `could not snapshot ${abs} before removing it (${err.message}), so it was left in place: ${denied}, so remove it by hand`
8384
+ `could not snapshot ${abs} before removing it (${errorText(err)}), so it was left in place: ${denied}, so remove it by hand`
8190
8385
  );
8191
8386
  return;
8192
8387
  }
@@ -8199,7 +8394,7 @@ function removeUntrackedDenied(repo, path, segment, ts) {
8199
8394
  const where = snapshotted ? `. A copy was snapshotted under backup/${ts}/repo/ first` : "";
8200
8395
  warn(`removed ${path} from the sync repo working tree: ${denied}${where}`);
8201
8396
  } catch (err) {
8202
- warn(`could not remove ${abs}: ${err.message}`);
8397
+ warn(`could not remove ${abs}: ${errorText(err)}`);
8203
8398
  }
8204
8399
  }
8205
8400
  function reportTrackedDenied(repo, path, segment) {
@@ -8217,7 +8412,7 @@ function reportTrackedDenied(repo, path, segment) {
8217
8412
  );
8218
8413
  return;
8219
8414
  }
8220
- if (!existsSync42(join56(repo, path))) return;
8415
+ if (!existsSync41(join57(repo, path))) return;
8221
8416
  warn(
8222
8417
  `${path} is tracked and has changes against HEAD: ${denied}. Nothing was changed. Run "git checkout HEAD -- ${path}" to put the committed content back, or move the file outside shared/ if you want to keep it. Neither of those takes the committed copy out of the repo: "git rm -- ${path}" and a commit does that going forward, and if it holds a real secret, rotate it and rewrite history, because nomad only changes your local worktree and index and cannot scrub what a previous push already sent to the remote`
8223
8418
  );
@@ -8235,8 +8430,8 @@ function revertDeniedMirrorPaths(repo, status, ts) {
8235
8430
 
8236
8431
  // src/preview.ts
8237
8432
  init_config();
8238
- import { existsSync as existsSync44 } from "node:fs";
8239
- import { join as join58 } from "node:path";
8433
+ import { existsSync as existsSync43 } from "node:fs";
8434
+ import { join as join59 } from "node:path";
8240
8435
 
8241
8436
  // node_modules/diff/libesm/diff/base.js
8242
8437
  var Diff = class {
@@ -8511,16 +8706,16 @@ function diffLinesToUnified(oldStr, newStr) {
8511
8706
 
8512
8707
  // src/preview.skills.ts
8513
8708
  init_config();
8514
- import { existsSync as existsSync43, readdirSync as readdirSync19 } from "node:fs";
8515
- import { join as join57 } from "node:path";
8709
+ import { existsSync as existsSync42, readdirSync as readdirSync19 } from "node:fs";
8710
+ import { join as join58 } from "node:path";
8516
8711
  function buildSkillsPreviewSection() {
8517
8712
  const s = section("Skills");
8518
- const sharedSkills = join57(repoHome(), "shared", "skills");
8519
- if (!existsSync43(sharedSkills)) return s;
8713
+ const sharedSkills = join58(repoHome(), "shared", "skills");
8714
+ if (!existsSync42(sharedSkills)) return s;
8520
8715
  const sharedNames = readdirSync19(sharedSkills, { encoding: "utf8" }).filter((name) => !isSkillExcluded(name)).sort((a, b) => a.localeCompare(b, "en"));
8521
8716
  for (const name of sharedNames) addItem(s, name);
8522
- const localSkills = join57(claudeHome(), "skills");
8523
- const localOnly = existsSync43(localSkills) ? readdirSync19(localSkills, { encoding: "utf8" }).filter(
8717
+ const localSkills = join58(claudeHome(), "skills");
8718
+ const localOnly = existsSync42(localSkills) ? readdirSync19(localSkills, { encoding: "utf8" }).filter(
8524
8719
  (name) => !isSkillExcluded(name) && !sharedNames.includes(name)
8525
8720
  ).length : 0;
8526
8721
  if (localOnly > 0) {
@@ -8542,7 +8737,7 @@ function diffJsonStrings(currentJsonText, newJsonText) {
8542
8737
  return lines.join("\n");
8543
8738
  }
8544
8739
  function readJsonOrNull(path) {
8545
- if (!existsSync44(path)) return null;
8740
+ if (!existsSync43(path)) return null;
8546
8741
  try {
8547
8742
  return readJson(path);
8548
8743
  } catch {
@@ -8556,12 +8751,12 @@ function previewSettings(basePath, hostPath, settingsPath) {
8556
8751
  }
8557
8752
  const notes = [];
8558
8753
  const hostOverrides = readJsonOrNull(hostPath);
8559
- if (hostOverrides === null && existsSync44(hostPath)) {
8754
+ if (hostOverrides === null && existsSync43(hostPath)) {
8560
8755
  notes.push(`malformed hosts/${HOST}.json; ignoring overrides`);
8561
8756
  }
8562
8757
  const merged = stripGsdHookEntries(deepMerge(base, hostOverrides ?? {}));
8563
8758
  const current = readJsonOrNull(settingsPath);
8564
- if (current === null && existsSync44(settingsPath)) {
8759
+ if (current === null && existsSync43(settingsPath)) {
8565
8760
  return { diff: "", notes: [...notes, "malformed; skipping diff"] };
8566
8761
  }
8567
8762
  const strippedCurrent = stripGsdHookEntries(current ?? {});
@@ -8628,9 +8823,9 @@ function computePreview(ts, map, verb = "pull", plans) {
8628
8823
  onPreview: (e) => addItem(links, formatLinkRow(e))
8629
8824
  });
8630
8825
  const settingsResult = previewSettings(
8631
- join58(repo, "shared", "settings.base.json"),
8632
- join58(repo, "hosts", `${HOST}.json`),
8633
- join58(claude, "settings.json")
8826
+ join59(repo, "shared", "settings.base.json"),
8827
+ join59(repo, "hosts", `${HOST}.json`),
8828
+ join59(claude, "settings.json")
8634
8829
  );
8635
8830
  const settingsSection = buildSettingsSectionForPreview(settingsResult);
8636
8831
  const sessions = section("Sessions");
@@ -8646,7 +8841,7 @@ function computePreview(ts, map, verb = "pull", plans) {
8646
8841
  const extras = section("Extras");
8647
8842
  let extrasSkipped = 0;
8648
8843
  let extrasUnmapped = 0;
8649
- if (existsSync44(join58(repo, "path-map.json")) && existsSync44(join58(repo, "shared", "extras"))) {
8844
+ if (existsSync43(join59(repo, "path-map.json")) && existsSync43(join59(repo, "shared", "extras"))) {
8650
8845
  const extrasResult = remapExtrasPull(ts, { dryRun: true });
8651
8846
  for (const entry of extrasResult.wouldPull) {
8652
8847
  addItem(extras, entry);
@@ -8667,7 +8862,7 @@ function computePreview(ts, map, verb = "pull", plans) {
8667
8862
  init_utils();
8668
8863
  init_utils_json();
8669
8864
  function readMapForMirror(mapPath) {
8670
- if (!existsSync45(mapPath)) return { projects: {} };
8865
+ if (!existsSync44(mapPath)) return { projects: {} };
8671
8866
  try {
8672
8867
  return readPathMap(mapPath);
8673
8868
  } catch {
@@ -8714,7 +8909,7 @@ function reconcileSharedLinksBeforePull(repo, ts) {
8714
8909
  let namesDerived = false;
8715
8910
  let derivedSharedDirs;
8716
8911
  try {
8717
- const map = readMapForMirror(join59(repo, "path-map.json"));
8912
+ const map = readMapForMirror(join60(repo, "path-map.json"));
8718
8913
  if (map !== null) {
8719
8914
  linkNames = allSharedLinks(map);
8720
8915
  namesDerived = true;
@@ -8753,7 +8948,7 @@ function buildMirrorSection(events, discard) {
8753
8948
  function describeSkippedMirrorDiscard(repo, ts) {
8754
8949
  if (process.platform !== "win32") return null;
8755
8950
  try {
8756
- const map = readMapForMirror(join59(repo, "path-map.json"));
8951
+ const map = readMapForMirror(join60(repo, "path-map.json"));
8757
8952
  const linkNames = map !== null ? allSharedLinks(map, { quiet: true }) : void 0;
8758
8953
  const captures = [];
8759
8954
  stageLocalSharedEdits(map, ts, {
@@ -8762,13 +8957,13 @@ function describeSkippedMirrorDiscard(repo, ts) {
8762
8957
  linkNames
8763
8958
  });
8764
8959
  if (captures.length === 0) return null;
8765
- return { count: captures.length, backupPath: join59(backupBase(), ts) };
8960
+ return { count: captures.length, backupPath: join60(backupBase(), ts) };
8766
8961
  } catch {
8767
8962
  return null;
8768
8963
  }
8769
8964
  }
8770
8965
  function planSharedReconcileBeforePull(repo, ts) {
8771
- const map = readMapForMirror(join59(repo, "path-map.json"));
8966
+ const map = readMapForMirror(join60(repo, "path-map.json"));
8772
8967
  const captures = [];
8773
8968
  const linkNames = process.platform === "win32" && map !== null ? allSharedLinks(map) : void 0;
8774
8969
  stageLocalSharedEdits(map, ts, { dryRun: true, onPreview: (e) => captures.push(e), linkNames });
@@ -8783,8 +8978,8 @@ function planSharedReconcileBeforePull(repo, ts) {
8783
8978
  // src/commands.pull.collision.ts
8784
8979
  init_config();
8785
8980
  init_exit_codes();
8786
- import { existsSync as existsSync46, lstatSync as lstatSync21, readFileSync as readFileSync20, rmSync as rmSync19 } from "node:fs";
8787
- import { join as join60 } from "node:path";
8981
+ import { existsSync as existsSync45, lstatSync as lstatSync21, readFileSync as readFileSync20, rmSync as rmSync19 } from "node:fs";
8982
+ import { join as join61 } from "node:path";
8788
8983
  init_utils();
8789
8984
  var SHARED_PREFIX = /^shared\//;
8790
8985
  var EXTENSION = /(\.[^.]+)?$/;
@@ -8840,15 +9035,15 @@ function isContainedMirrorPath(rel) {
8840
9035
  }
8841
9036
  function matchesLocalOriginal(repo, rel) {
8842
9037
  try {
8843
- const local = join60(claudeHome(), rel.replace(SHARED_PREFIX, ""));
8844
- return readFileSync20(join60(repo, rel)).equals(readFileSync20(local));
9038
+ const local = join61(claudeHome(), rel.replace(SHARED_PREFIX, ""));
9039
+ return readFileSync20(join61(repo, rel)).equals(readFileSync20(local));
8845
9040
  } catch {
8846
9041
  return false;
8847
9042
  }
8848
9043
  }
8849
9044
  function removeMirroredCopies(repo, repoRelPaths) {
8850
9045
  for (const rel of repoRelPaths.filter(isContainedMirrorPath)) {
8851
- const abs = join60(repo, rel);
9046
+ const abs = join61(repo, rel);
8852
9047
  try {
8853
9048
  if (lstatSync21(abs, { throwIfNoEntry: false })?.isFile() !== true) continue;
8854
9049
  if (!matchesLocalOriginal(repo, rel)) continue;
@@ -8857,7 +9052,7 @@ function removeMirroredCopies(repo, repoRelPaths) {
8857
9052
  warn(`could not remove nomad's copy at ${abs}: ${err.message}`);
8858
9053
  }
8859
9054
  }
8860
- return repoRelPaths.every((rel) => !existsSync46(join60(repo, rel)));
9055
+ return repoRelPaths.every((rel) => !existsSync45(join61(repo, rel)));
8861
9056
  }
8862
9057
  function pullWithCollisionRunbook(repo, mirrored) {
8863
9058
  try {
@@ -9064,7 +9259,7 @@ function runPullCore(opts = {}) {
9064
9259
  try {
9065
9260
  return runPullWithBackupTs(ts, opts);
9066
9261
  } finally {
9067
- discardEmptyBackupDir(join61(backup, ts));
9262
+ discardEmptyBackupDir(join62(backup, ts));
9068
9263
  }
9069
9264
  }
9070
9265
  function runPullWithBackupTs(ts, opts) {
@@ -9075,7 +9270,7 @@ function runPullWithBackupTs(ts, opts) {
9075
9270
  const backup = backupBase();
9076
9271
  const recovered = handleWedge(repo, forceRemote);
9077
9272
  if (!dryRun) {
9078
- const backupRoot = join61(backup, ts);
9273
+ const backupRoot = join62(backup, ts);
9079
9274
  try {
9080
9275
  mkdirSync14(backupRoot, { recursive: true });
9081
9276
  } catch (err) {
@@ -9098,8 +9293,8 @@ function runPullWithBackupTs(ts, opts) {
9098
9293
  pullWithCollisionRunbook(repo, mirrored);
9099
9294
  });
9100
9295
  assertNoAutostashConflict(repo, "nomad pull");
9101
- const mapPath = join61(repo, "path-map.json");
9102
- const map = existsSync47(mapPath) ? readPathMap(mapPath) : { projects: {} };
9296
+ const mapPath = join62(repo, "path-map.json");
9297
+ const map = existsSync46(mapPath) ? readPathMap(mapPath) : { projects: {} };
9103
9298
  const divergedKeptLocal = divergenceCheckExtras(ts, dryRun ? prePostHeads : void 0);
9104
9299
  if (dryRun) {
9105
9300
  computePreview(ts, map, "pull", plansAgainst(sharedPlans, map));
@@ -9126,8 +9321,8 @@ function runPullWithBackupTs(ts, opts) {
9126
9321
  }
9127
9322
  function cmdPull(opts = {}) {
9128
9323
  const repo = repoHome();
9129
- if (!existsSync47(repo)) die(`repo not cloned at ${repo}`);
9130
- if (!existsSync47(join61(repo, "shared", "settings.base.json"))) {
9324
+ if (!existsSync46(repo)) die(`repo not cloned at ${repo}`);
9325
+ if (!existsSync46(join62(repo, "shared", "settings.base.json"))) {
9131
9326
  die("repo not initialized; run 'nomad init' to scaffold");
9132
9327
  }
9133
9328
  const handle = acquireLock("pull");
@@ -9150,13 +9345,13 @@ function cmdPull(opts = {}) {
9150
9345
 
9151
9346
  // src/commands.push.ts
9152
9347
  init_config();
9153
- import { existsSync as existsSync51 } from "node:fs";
9154
- import { join as join66 } from "node:path";
9348
+ import { existsSync as existsSync50 } from "node:fs";
9349
+ import { join as join67 } from "node:path";
9155
9350
 
9156
9351
  // src/commands.push.selection.ts
9157
9352
  init_config();
9158
- import { existsSync as existsSync48, statSync as statSync11 } from "node:fs";
9159
- import { join as join62 } from "node:path";
9353
+ import { existsSync as existsSync47, statSync as statSync13 } from "node:fs";
9354
+ import { join as join63 } from "node:path";
9160
9355
  init_utils_json();
9161
9356
  function buildCurrentMap(map) {
9162
9357
  const current = {};
@@ -9165,10 +9360,10 @@ function buildCurrentMap(map) {
9165
9360
  for (const [, hostMap] of Object.entries(map.projects)) {
9166
9361
  const localPath = hostMap[HOST];
9167
9362
  if (!localPath) continue;
9168
- const localDir = join62(claude, "projects", encodePath(localPath));
9169
- if (!existsSync48(localDir)) continue;
9363
+ const localDir = join63(claude, "projects", encodePath(localPath));
9364
+ if (!existsSync47(localDir)) continue;
9170
9365
  for (const f of enumerateSourceFiles(localDir)) {
9171
- const st = statSync11(f);
9366
+ const st = statSync13(f);
9172
9367
  current[f] = { size: st.size, mtime: st.mtimeMs };
9173
9368
  }
9174
9369
  }
@@ -9197,7 +9392,7 @@ function computePushSelection(map, old, scannerVersion, configHash, fullScan) {
9197
9392
  };
9198
9393
  }
9199
9394
  function loadSelectionForPush(mapPath, old, scannerVersion, configHash, fullScan) {
9200
- const map = existsSync48(mapPath) ? readPathMap(mapPath) : null;
9395
+ const map = existsSync47(mapPath) ? readPathMap(mapPath) : null;
9201
9396
  const { selection, newManifest } = computePushSelection(
9202
9397
  map,
9203
9398
  old,
@@ -9290,14 +9485,14 @@ function enforceAllowList(statusPorcelain, map) {
9290
9485
 
9291
9486
  // src/commands.push.settings.ts
9292
9487
  init_config();
9293
- import { existsSync as existsSync49 } from "node:fs";
9294
- import { join as join63 } from "node:path";
9488
+ import { existsSync as existsSync48 } from "node:fs";
9489
+ import { join as join64 } from "node:path";
9295
9490
  init_utils();
9296
9491
  init_utils_fs();
9297
9492
  init_utils_json();
9298
9493
  function stripGsdHooksFromBase(repo, backup) {
9299
- const basePath = join63(repo, "shared", "settings.base.json");
9300
- if (!existsSync49(basePath)) return;
9494
+ const basePath = join64(repo, "shared", "settings.base.json");
9495
+ if (!existsSync48(basePath)) return;
9301
9496
  let base;
9302
9497
  try {
9303
9498
  base = readJson(basePath);
@@ -9311,14 +9506,14 @@ function stripGsdHooksFromBase(repo, backup) {
9311
9506
  writeJsonAtomic(basePath, stripped);
9312
9507
  }
9313
9508
  function reportSettingsAheadDrift(repo) {
9314
- const basePath = join63(repo, "shared", "settings.base.json");
9315
- if (!existsSync49(basePath)) return;
9316
- const settingsPath = join63(claudeHome(), "settings.json");
9317
- if (!existsSync49(settingsPath)) return;
9509
+ const basePath = join64(repo, "shared", "settings.base.json");
9510
+ if (!existsSync48(basePath)) return;
9511
+ const settingsPath = join64(claudeHome(), "settings.json");
9512
+ if (!existsSync48(settingsPath)) return;
9318
9513
  try {
9319
9514
  const base = readJson(basePath);
9320
- const hostPath = join63(repo, "hosts", `${HOST}.json`);
9321
- const overrides = existsSync49(hostPath) ? readJson(hostPath) : {};
9515
+ const hostPath = join64(repo, "hosts", `${HOST}.json`);
9516
+ const overrides = existsSync48(hostPath) ? readJson(hostPath) : {};
9322
9517
  const merged = deepMerge(base, overrides);
9323
9518
  const settings = readJson(settingsPath);
9324
9519
  const { ahead } = classifySettingsDrift(merged, settings);
@@ -9335,9 +9530,9 @@ function reportSettingsAheadDrift(repo) {
9335
9530
  // src/commands.push.guards.ts
9336
9531
  init_push_checks();
9337
9532
  init_utils();
9338
- import { join as join64, relative as relative10 } from "node:path";
9533
+ import { join as join65, relative as relative10 } from "node:path";
9339
9534
  function guardGitlinks(repo) {
9340
- const gitlinks = findGitlinks(join64(repo, "shared"));
9535
+ const gitlinks = findGitlinks(join65(repo, "shared"));
9341
9536
  if (gitlinks.length === 0) return;
9342
9537
  for (const p of gitlinks) {
9343
9538
  const rel = relative10(repo, p).replaceAll("\\", "/");
@@ -9447,9 +9642,9 @@ init_color();
9447
9642
  init_config();
9448
9643
  init_config_sharedDirs_guard();
9449
9644
  import { randomBytes as randomBytes4 } from "node:crypto";
9450
- import { copyFileSync, existsSync as existsSync50, lstatSync as lstatSync22, mkdirSync as mkdirSync15, readdirSync as readdirSync20, rmSync as rmSync20 } from "node:fs";
9645
+ import { copyFileSync, existsSync as existsSync49, lstatSync as lstatSync22, mkdirSync as mkdirSync15, readdirSync as readdirSync20, rmSync as rmSync20 } from "node:fs";
9451
9646
  import { homedir as homedir7 } from "node:os";
9452
- import { join as join65, relative as relative11, sep as sep14 } from "node:path";
9647
+ import { join as join66, relative as relative11, sep as sep14 } from "node:path";
9453
9648
  init_push_leak_verdict();
9454
9649
  init_push_gitleaks();
9455
9650
  init_utils_fs();
@@ -9461,7 +9656,7 @@ function stageSessionDir(localDir, dstDir, changed) {
9461
9656
  const matching = [...changed].filter((p) => p.startsWith(prefix));
9462
9657
  if (matching.length === 0) return false;
9463
9658
  for (const src of matching) {
9464
- copyFileAtomic(src, join65(dstDir, relative11(localDir, src)));
9659
+ copyFileAtomic(src, join66(dstDir, relative11(localDir, src)));
9465
9660
  }
9466
9661
  return true;
9467
9662
  }
@@ -9477,14 +9672,14 @@ function stageSessions(tmpRoot, map, changed) {
9477
9672
  if (!p || p === "TBD") continue;
9478
9673
  reverse.set(encodePath(p), logical);
9479
9674
  }
9480
- const localProjects = join65(claudeHome(), "projects");
9481
- if (!existsSync50(localProjects)) return 0;
9675
+ const localProjects = join66(claudeHome(), "projects");
9676
+ if (!existsSync49(localProjects)) return 0;
9482
9677
  let staged = 0;
9483
9678
  for (const dir of readdirSync20(localProjects)) {
9484
9679
  const logical = reverse.get(dir);
9485
9680
  if (!logical) continue;
9486
- const localDir = join65(localProjects, dir);
9487
- const dstDir = join65(tmpRoot, "shared", "projects", logical);
9681
+ const localDir = join66(localProjects, dir);
9682
+ const dstDir = join66(tmpRoot, "shared", "projects", logical);
9488
9683
  if (stageSessionDir(localDir, dstDir, changed)) staged++;
9489
9684
  }
9490
9685
  return staged;
@@ -9500,9 +9695,9 @@ function stageExtras(tmpRoot, map) {
9500
9695
  if (!localRoot || localRoot === "TBD") continue;
9501
9696
  for (const dirname15 of dirnames) {
9502
9697
  if (!whitelist.includes(dirname15)) continue;
9503
- const src = join65(localRoot, dirname15);
9504
- if (!existsSync50(src)) continue;
9505
- const dst = join65(tmpRoot, "shared", "extras", logical, dirname15);
9698
+ const src = join66(localRoot, dirname15);
9699
+ if (!existsSync49(src)) continue;
9700
+ const dst = join66(tmpRoot, "shared", "extras", logical, dirname15);
9506
9701
  copyExtras(src, dst);
9507
9702
  staged++;
9508
9703
  }
@@ -9510,19 +9705,19 @@ function stageExtras(tmpRoot, map) {
9510
9705
  return staged;
9511
9706
  }
9512
9707
  function stageSkills(tmpRoot) {
9513
- const localSkills = join65(claudeHome(), "skills");
9708
+ const localSkills = join66(claudeHome(), "skills");
9514
9709
  const stat = lstatSync22(localSkills, { throwIfNoEntry: false });
9515
9710
  if (stat === void 0 || stat.isSymbolicLink()) return 0;
9516
9711
  const names = readdirSync20(localSkills, { encoding: "utf8" }).filter((n) => !isSkillExcluded(n));
9517
9712
  if (names.length === 0) return 0;
9518
- copySkillsPush(localSkills, join65(tmpRoot, "shared", "skills"));
9713
+ copySkillsPush(localSkills, join66(tmpRoot, "shared", "skills"));
9519
9714
  return names.length;
9520
9715
  }
9521
9716
  function previewPushLeaks(map, opts = {}) {
9522
- const cacheDir = join65(homedir7(), ".cache", "claude-nomad");
9717
+ const cacheDir = join66(homedir7(), ".cache", "claude-nomad");
9523
9718
  mkdirSync15(cacheDir, { recursive: true });
9524
9719
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes4(4).toString("hex")}`;
9525
- const tmpRoot = join65(cacheDir, `push-preview-tree-${stamp}`);
9720
+ const tmpRoot = join66(cacheDir, `push-preview-tree-${stamp}`);
9526
9721
  try {
9527
9722
  const sessionCount = stageSessions(tmpRoot, map, opts.selection?.changed);
9528
9723
  const extrasCount = stageExtras(tmpRoot, map);
@@ -9530,9 +9725,9 @@ function previewPushLeaks(map, opts = {}) {
9530
9725
  if (sessionCount + extrasCount + skillCount === 0) {
9531
9726
  return { leak: false, verdictRow: NOTHING_TO_SCAN_ROW, recovery: null, findings: [] };
9532
9727
  }
9533
- const ignoreFile = join65(repoHome(), ".gitleaksignore");
9534
- if (existsSync50(ignoreFile)) {
9535
- copyFileSync(ignoreFile, join65(tmpRoot, ".gitleaksignore"));
9728
+ const ignoreFile = join66(repoHome(), ".gitleaksignore");
9729
+ if (existsSync49(ignoreFile)) {
9730
+ copyFileSync(ignoreFile, join66(tmpRoot, ".gitleaksignore"));
9536
9731
  }
9537
9732
  let findings;
9538
9733
  try {
@@ -9660,7 +9855,7 @@ async function runPushCore(opts = {}) {
9660
9855
  const scannerVersion = probeGitleaks();
9661
9856
  const configHash = computeConfigHash();
9662
9857
  const old = readManifest(manifestPath());
9663
- const mapPath = join66(repo, "path-map.json");
9858
+ const mapPath = join67(repo, "path-map.json");
9664
9859
  const { map, selection, newManifest } = loadSelectionForPush(
9665
9860
  mapPath,
9666
9861
  old,
@@ -9713,7 +9908,7 @@ async function cmdPush(opts = {}) {
9713
9908
  opts.allowRule
9714
9909
  );
9715
9910
  const repo = repoHome();
9716
- if (!existsSync51(repo)) die(`repo not cloned at ${repo}`);
9911
+ if (!existsSync50(repo)) die(`repo not cloned at ${repo}`);
9717
9912
  const handle = acquireLock("push");
9718
9913
  if (handle === null) process.exit(0);
9719
9914
  try {
@@ -9731,8 +9926,8 @@ async function cmdPush(opts = {}) {
9731
9926
  }
9732
9927
 
9733
9928
  // src/commands.sync.ts
9734
- import { existsSync as existsSync52 } from "node:fs";
9735
- import { join as join67 } from "node:path";
9929
+ import { existsSync as existsSync51 } from "node:fs";
9930
+ import { join as join68 } from "node:path";
9736
9931
  init_config();
9737
9932
  init_color();
9738
9933
  init_utils();
@@ -9873,8 +10068,8 @@ async function cmdSync(opts = {}) {
9873
10068
  const dryRun = opts.dryRun === true;
9874
10069
  const verbose = opts.verbose === true;
9875
10070
  const repo = repoHome();
9876
- if (!existsSync52(repo)) die(`repo not cloned at ${repo}`);
9877
- if (!existsSync52(join67(repo, "shared", "settings.base.json"))) {
10071
+ if (!existsSync51(repo)) die(`repo not cloned at ${repo}`);
10072
+ if (!existsSync51(join68(repo, "shared", "settings.base.json"))) {
9878
10073
  die("repo not initialized; run 'nomad init' to scaffold");
9879
10074
  }
9880
10075
  const handle = acquireLock("sync");
@@ -9950,8 +10145,8 @@ init_config();
9950
10145
  // src/crash-report.write.ts
9951
10146
  init_config();
9952
10147
  import { randomBytes as randomBytes5 } from "node:crypto";
9953
- import { mkdirSync as mkdirSync16, readdirSync as readdirSync21, statSync as statSync12, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
9954
- import { join as join69 } from "node:path";
10148
+ import { mkdirSync as mkdirSync16, readdirSync as readdirSync21, statSync as statSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
10149
+ import { join as join70 } from "node:path";
9955
10150
 
9956
10151
  // src/crash-report.ts
9957
10152
  var CRASH_MAX_STACK_LINES = 50;
@@ -10036,15 +10231,15 @@ function buildCrashReport(input) {
10036
10231
  // src/crash-report.redact.ts
10037
10232
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync21, writeFileSync as writeFileSync10 } from "node:fs";
10038
10233
  import { tmpdir as tmpdir2 } from "node:os";
10039
- import { join as join68 } from "node:path";
10234
+ import { join as join69 } from "node:path";
10040
10235
  init_push_gitleaks_scan();
10041
10236
  var CRASH_SCAN_TIMEOUT_MS = 3e3;
10042
10237
  var SCAN_UNAVAILABLE_ADVISORY = "\n\n[gitleaks value-based scan unavailable; only structural redaction applied. Review before sharing this file publicly.]\n";
10043
10238
  function redactWithGitleaks(text, scan = scanFile) {
10044
10239
  let dir;
10045
10240
  try {
10046
- dir = mkdtempSync3(join68(tmpdir2(), "nomad-crash-scan-"));
10047
- const tmp = join68(dir, "crash.txt");
10241
+ dir = mkdtempSync3(join69(tmpdir2(), "nomad-crash-scan-"));
10242
+ const tmp = join69(dir, "crash.txt");
10048
10243
  writeFileSync10(tmp, text, { mode: 384 });
10049
10244
  const findings = scan(tmp, false, CRASH_SCAN_TIMEOUT_MS);
10050
10245
  if (findings === null) return text + SCAN_UNAVAILABLE_ADVISORY;
@@ -10069,7 +10264,7 @@ function listCrashFiles(dir = crashDir()) {
10069
10264
  try {
10070
10265
  return readdirSync21(dir).flatMap((name) => {
10071
10266
  try {
10072
- return [{ name, mtimeMs: statSync12(join69(dir, name)).mtimeMs }];
10267
+ return [{ name, mtimeMs: statSync14(join70(dir, name)).mtimeMs }];
10073
10268
  } catch {
10074
10269
  return [];
10075
10270
  }
@@ -10083,7 +10278,7 @@ function pruneCrashDir(dir, keep = CRASH_RETENTION_KEEP) {
10083
10278
  const targets = prunableByCount(files, keep);
10084
10279
  for (const name of targets) {
10085
10280
  try {
10086
- unlinkSync2(join69(dir, name));
10281
+ unlinkSync2(join70(dir, name));
10087
10282
  } catch {
10088
10283
  }
10089
10284
  }
@@ -10091,7 +10286,7 @@ function pruneCrashDir(dir, keep = CRASH_RETENTION_KEEP) {
10091
10286
  function writeCrashReport(text, dir = crashDir()) {
10092
10287
  mkdirSync16(dir, { recursive: true, mode: 448 });
10093
10288
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes5(4).toString("hex")}`;
10094
- const path = join69(dir, `crash-${stamp}.txt`);
10289
+ const path = join70(dir, `crash-${stamp}.txt`);
10095
10290
  writeFileSync11(path, text, { mode: 384 });
10096
10291
  pruneCrashDir(dir);
10097
10292
  return path;
@@ -10123,18 +10318,18 @@ function handleCrash(err, argv, opts) {
10123
10318
 
10124
10319
  // src/diff.ts
10125
10320
  init_config();
10126
- import { existsSync as existsSync53 } from "node:fs";
10127
- import { join as join70 } from "node:path";
10321
+ import { existsSync as existsSync52 } from "node:fs";
10322
+ import { join as join71 } from "node:path";
10128
10323
  init_utils();
10129
10324
  init_utils_fs();
10130
10325
  init_utils_json();
10131
10326
  function cmdDiff() {
10132
10327
  try {
10133
10328
  const repo = repoHome();
10134
- if (!existsSync53(repo)) die(`repo not cloned at ${repo}`);
10329
+ if (!existsSync52(repo)) die(`repo not cloned at ${repo}`);
10135
10330
  const ts = freshBackupTs(backupBase());
10136
- const mapPath = join70(repo, "path-map.json");
10137
- const map = existsSync53(mapPath) ? readPathMap(mapPath) : { projects: {} };
10331
+ const mapPath = join71(repo, "path-map.json");
10332
+ const map = existsSync52(mapPath) ? readPathMap(mapPath) : { projects: {} };
10138
10333
  divergenceCheckExtras(ts);
10139
10334
  computePreview(ts, map, "diff");
10140
10335
  } catch (err) {
@@ -10149,8 +10344,8 @@ function cmdDiff() {
10149
10344
 
10150
10345
  // src/init.ts
10151
10346
  init_config();
10152
- import { existsSync as existsSync55, mkdirSync as mkdirSync17, writeFileSync as writeFileSync12 } from "node:fs";
10153
- import { join as join72 } from "node:path";
10347
+ import { existsSync as existsSync54, mkdirSync as mkdirSync17, writeFileSync as writeFileSync12 } from "node:fs";
10348
+ import { join as join73 } from "node:path";
10154
10349
 
10155
10350
  // src/init.gh-onboard.ts
10156
10351
  init_config();
@@ -10232,33 +10427,33 @@ init_config();
10232
10427
  init_utils();
10233
10428
  init_utils_fs();
10234
10429
  init_utils_json();
10235
- import { copyFileSync as copyFileSync2, cpSync as cpSync9, existsSync as existsSync54, rmSync as rmSync22, statSync as statSync13 } from "node:fs";
10236
- import { join as join71 } from "node:path";
10430
+ import { copyFileSync as copyFileSync2, cpSync as cpSync9, existsSync as existsSync53, rmSync as rmSync22, statSync as statSync15 } from "node:fs";
10431
+ import { join as join72 } from "node:path";
10237
10432
  function snapshotIntoShared(map) {
10238
10433
  const repo = repoHome();
10239
10434
  const claude = claudeHome();
10240
10435
  for (const name of allSharedLinks(map)) {
10241
- const src = join71(claude, name);
10242
- if (!existsSync54(src)) continue;
10243
- const dst = join71(repo, "shared", name);
10244
- if (statSync13(src).isDirectory()) {
10245
- const gk = join71(dst, ".gitkeep");
10246
- if (existsSync54(gk)) rmSync22(gk);
10436
+ const src = join72(claude, name);
10437
+ if (!existsSync53(src)) continue;
10438
+ const dst = join72(repo, "shared", name);
10439
+ if (statSync15(src).isDirectory()) {
10440
+ const gk = join72(dst, ".gitkeep");
10441
+ if (existsSync53(gk)) rmSync22(gk);
10247
10442
  cpSync9(src, dst, { recursive: true, force: false, errorOnExist: true });
10248
10443
  } else {
10249
10444
  copyFileSync2(src, dst);
10250
10445
  }
10251
10446
  log(`snapshotted shared/${name} from ${src}`);
10252
10447
  }
10253
- const userSettings = join71(claude, "settings.json");
10254
- if (existsSync54(userSettings)) {
10448
+ const userSettings = join72(claude, "settings.json");
10449
+ if (existsSync53(userSettings)) {
10255
10450
  let parsed;
10256
10451
  try {
10257
10452
  parsed = readJson(userSettings);
10258
10453
  } catch (err) {
10259
10454
  return die(`malformed ${userSettings}: ${err.message}`);
10260
10455
  }
10261
- const hostFile = join71(repo, "hosts", `${HOST}.json`);
10456
+ const hostFile = join72(repo, "hosts", `${HOST}.json`);
10262
10457
  writeJsonAtomic(hostFile, parsed);
10263
10458
  log(`snapshotted hosts/${HOST}.json from ${userSettings}`);
10264
10459
  }
@@ -10272,14 +10467,14 @@ var GITATTRIBUTES = "# nomad: sync content is byte-managed, disable all line-end
10272
10467
  var SHARED_KEEP_DIRS = ["agents", "skills", "commands", "rules", "hooks"];
10273
10468
  function preflightConflict(repoHome2) {
10274
10469
  const candidates = [
10275
- join72(repoHome2, "shared", "settings.base.json"),
10276
- join72(repoHome2, "shared", "CLAUDE.md"),
10277
- join72(repoHome2, "path-map.json"),
10278
- join72(repoHome2, "hosts"),
10279
- join72(repoHome2, "shared")
10470
+ join73(repoHome2, "shared", "settings.base.json"),
10471
+ join73(repoHome2, "shared", "CLAUDE.md"),
10472
+ join73(repoHome2, "path-map.json"),
10473
+ join73(repoHome2, "hosts"),
10474
+ join73(repoHome2, "shared")
10280
10475
  ];
10281
10476
  for (const c of candidates) {
10282
- if (existsSync55(c)) return c;
10477
+ if (existsSync54(c)) return c;
10283
10478
  }
10284
10479
  return null;
10285
10480
  }
@@ -10297,27 +10492,27 @@ function cmdInit(opts = {}) {
10297
10492
  die(`already initialized; refusing to clobber ${conflict}`);
10298
10493
  }
10299
10494
  ensureOriginRepo(opts.repoName ?? DEFAULT_REPO_NAME, opts.run);
10300
- mkdirSync17(join72(repo, "shared"), { recursive: true });
10301
- mkdirSync17(join72(repo, "hosts"), { recursive: true });
10495
+ mkdirSync17(join73(repo, "shared"), { recursive: true });
10496
+ mkdirSync17(join73(repo, "hosts"), { recursive: true });
10302
10497
  for (const name of SHARED_KEEP_DIRS) {
10303
- mkdirSync17(join72(repo, "shared", name), { recursive: true });
10498
+ mkdirSync17(join73(repo, "shared", name), { recursive: true });
10304
10499
  }
10305
- const userClaudeMd = join72(claude, "CLAUDE.md");
10306
- if (!snapshot || !existsSync55(userClaudeMd)) {
10307
- writeFileSync12(join72(repo, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
10500
+ const userClaudeMd = join73(claude, "CLAUDE.md");
10501
+ if (!snapshot || !existsSync54(userClaudeMd)) {
10502
+ writeFileSync12(join73(repo, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
10308
10503
  item("created shared/CLAUDE.md");
10309
10504
  }
10310
10505
  for (const name of SHARED_KEEP_DIRS) {
10311
- writeFileSync12(join72(repo, "shared", name, ".gitkeep"), "");
10506
+ writeFileSync12(join73(repo, "shared", name, ".gitkeep"), "");
10312
10507
  item(`created shared/${name}/.gitkeep`);
10313
10508
  }
10314
- writeFileSync12(join72(repo, "hosts", ".gitkeep"), "");
10509
+ writeFileSync12(join73(repo, "hosts", ".gitkeep"), "");
10315
10510
  item("created hosts/.gitkeep");
10316
- writeJsonAtomic(join72(repo, "shared", "settings.base.json"), {});
10511
+ writeJsonAtomic(join73(repo, "shared", "settings.base.json"), {});
10317
10512
  item("created shared/settings.base.json");
10318
- writeJsonAtomic(join72(repo, "path-map.json"), { projects: {} });
10513
+ writeJsonAtomic(join73(repo, "path-map.json"), { projects: {} });
10319
10514
  item("created path-map.json");
10320
- writeFileSync12(join72(repo, ".gitattributes"), GITATTRIBUTES);
10515
+ writeFileSync12(join73(repo, ".gitattributes"), GITATTRIBUTES);
10321
10516
  item("created .gitattributes");
10322
10517
  if (snapshot) {
10323
10518
  snapshotIntoShared({ projects: {} });
@@ -10383,21 +10578,21 @@ function maybeDisableRepoActions(repoHome2, run) {
10383
10578
  // src/init.prompt.ts
10384
10579
  init_config();
10385
10580
  init_utils();
10386
- import { existsSync as existsSync56, readdirSync as readdirSync22, statSync as statSync14 } from "node:fs";
10387
- import { join as join73 } from "node:path";
10581
+ import { existsSync as existsSync55, readdirSync as readdirSync22, statSync as statSync16 } from "node:fs";
10582
+ import { join as join74 } from "node:path";
10388
10583
  import { createInterface as createInterface3 } from "node:readline/promises";
10389
10584
  function nonEmptyExists(path) {
10390
- if (!existsSync56(path)) return false;
10585
+ if (!existsSync55(path)) return false;
10391
10586
  try {
10392
- if (statSync14(path).isDirectory()) return readdirSync22(path).length > 0;
10587
+ if (statSync16(path).isDirectory()) return readdirSync22(path).length > 0;
10393
10588
  return true;
10394
10589
  } catch {
10395
10590
  return false;
10396
10591
  }
10397
10592
  }
10398
10593
  function hasExistingClaudeConfig(claudeHome2) {
10399
- if (existsSync56(join73(claudeHome2, "settings.json"))) return true;
10400
- return SHARED_LINKS.some((name) => nonEmptyExists(join73(claudeHome2, name)));
10594
+ if (existsSync55(join74(claudeHome2, "settings.json"))) return true;
10595
+ return SHARED_LINKS.some((name) => nonEmptyExists(join74(claudeHome2, name)));
10401
10596
  }
10402
10597
  async function confirmSnapshotDefault(claudeHome2) {
10403
10598
  if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
@@ -10704,7 +10899,7 @@ function parseSyncArgs(argv) {
10704
10899
  // package.json
10705
10900
  var package_default = {
10706
10901
  name: "claude-nomad",
10707
- version: "0.67.0",
10902
+ version: "0.67.2",
10708
10903
  type: "module",
10709
10904
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
10710
10905
  keywords: [
@@ -10777,10 +10972,11 @@ var package_default = {
10777
10972
  "@commitlint/cli": "^21.0.1",
10778
10973
  "@commitlint/config-conventional": "^21.0.1",
10779
10974
  "@eslint/js": "^10.0.1",
10780
- "@stryker-mutator/core": "9.6.1",
10781
- "@stryker-mutator/vitest-runner": "9.6.1",
10975
+ "@stryker-mutator/core": "10.0.0",
10976
+ "@stryker-mutator/vitest-runner": "10.0.0",
10782
10977
  "@types/node": "^22.0.0",
10783
10978
  "@vitest/coverage-v8": "^4.1.6",
10979
+ "conventional-changelog-conventionalcommits": "^10.2.1",
10784
10980
  diff: "^9.0.0",
10785
10981
  esbuild: "^0.28.0",
10786
10982
  eslint: "^10.4.0",
@@ -10951,15 +11147,15 @@ var DEFAULT_HELP = [
10951
11147
  init_config();
10952
11148
  init_utils();
10953
11149
  init_utils_json();
10954
- import { existsSync as existsSync57, readFileSync as readFileSync21, readdirSync as readdirSync23 } from "node:fs";
10955
- import { join as join74 } from "node:path";
11150
+ import { existsSync as existsSync56, readFileSync as readFileSync21, readdirSync as readdirSync23 } from "node:fs";
11151
+ import { join as join75 } from "node:path";
10956
11152
  function resumeCmd(sessionId) {
10957
11153
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId) || sessionId.length > 128) {
10958
11154
  fail(`invalid session id: ${sessionId}`);
10959
11155
  process.exit(1);
10960
11156
  }
10961
- const projectsRoot = join74(claudeHome(), "projects");
10962
- if (!existsSync57(projectsRoot)) {
11157
+ const projectsRoot = join75(claudeHome(), "projects");
11158
+ if (!existsSync56(projectsRoot)) {
10963
11159
  fail(`${projectsRoot} does not exist`);
10964
11160
  process.exit(1);
10965
11161
  }
@@ -10973,8 +11169,8 @@ function resumeCmd(sessionId) {
10973
11169
  fail(`no cwd field found in ${jsonlPath}`);
10974
11170
  process.exit(1);
10975
11171
  }
10976
- const mapPath = join74(repoHome(), "path-map.json");
10977
- if (!existsSync57(mapPath)) {
11172
+ const mapPath = join75(repoHome(), "path-map.json");
11173
+ if (!existsSync56(mapPath)) {
10978
11174
  fail("path-map.json missing");
10979
11175
  process.exit(1);
10980
11176
  }
@@ -10997,8 +11193,8 @@ function resumeCmd(sessionId) {
10997
11193
  }
10998
11194
  function findTranscriptPath(projectsRoot, sessionId) {
10999
11195
  for (const dir of readdirSync23(projectsRoot)) {
11000
- const candidate = join74(projectsRoot, dir, `${sessionId}.jsonl`);
11001
- if (existsSync57(candidate)) return candidate;
11196
+ const candidate = join75(projectsRoot, dir, `${sessionId}.jsonl`);
11197
+ if (existsSync56(candidate)) return candidate;
11002
11198
  }
11003
11199
  return null;
11004
11200
  }