claude-nomad 0.38.0 → 0.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/nomad.mjs +239 -233
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.38.1](https://github.com/funkadelic/claude-nomad/compare/v0.38.0...v0.38.1) (2026-06-02)
4
+
5
+
6
+ ### Fixed
7
+
8
+ * **docs:** base-qualify internal links so they resolve under /claude-nomad ([#222](https://github.com/funkadelic/claude-nomad/issues/222)) ([8cff369](https://github.com/funkadelic/claude-nomad/commit/8cff3691687d07eb4c0f54f9f7fdbf680342c2e4))
9
+
10
+
11
+ ### Changed
12
+
13
+ * adopt fallow analyzer config ([#227](https://github.com/funkadelic/claude-nomad/issues/227)) ([ebf7ca0](https://github.com/funkadelic/claude-nomad/commit/ebf7ca0aa05510fa9edde5f408e951b7bfec05ab))
14
+ * break import cycles and trim unused exports ([#225](https://github.com/funkadelic/claude-nomad/issues/225)) ([1808539](https://github.com/funkadelic/claude-nomad/commit/180853964c1d09153b3c9e1272255e2a753bd6d3))
15
+ * **tests:** don't cancel in-progress push:main coverage runs ([#226](https://github.com/funkadelic/claude-nomad/issues/226)) ([3164283](https://github.com/funkadelic/claude-nomad/commit/31642839a5be85e3e9a966411bf5b839226616e8))
16
+
17
+
18
+ ### Documentation
19
+
20
+ * document ALWAYS_NEVER_SYNC credential hard-block in docs-site ([#224](https://github.com/funkadelic/claude-nomad/issues/224)) ([8904a4a](https://github.com/funkadelic/claude-nomad/commit/8904a4a8685f555e399dd394b825018e2055d373))
21
+
3
22
  ## [0.38.0](https://github.com/funkadelic/claude-nomad/compare/v0.37.0...v0.38.0) (2026-06-02)
4
23
 
5
24
 
package/dist/nomad.mjs CHANGED
@@ -32,6 +32,39 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  mod
33
33
  ));
34
34
 
35
+ // src/config.never-sync.ts
36
+ var NEVER_SYNC;
37
+ var init_config_never_sync = __esm({
38
+ "src/config.never-sync.ts"() {
39
+ "use strict";
40
+ NEVER_SYNC = /* @__PURE__ */ new Set([
41
+ ".claude.json",
42
+ ".credentials.json",
43
+ "history.jsonl",
44
+ "settings.local.json",
45
+ "stats-cache.json",
46
+ "todos",
47
+ "shell-snapshots",
48
+ "debug",
49
+ "file-history",
50
+ "plans",
51
+ "session-env",
52
+ "statsig",
53
+ "telemetry",
54
+ "ide",
55
+ // Host-local caches and runtime state (sharedDirs guard also rejects these).
56
+ "cache",
57
+ "backups",
58
+ "paste-cache",
59
+ "daemon",
60
+ "jobs",
61
+ "tasks",
62
+ "security",
63
+ "sessions"
64
+ ]);
65
+ }
66
+ });
67
+
35
68
  // node_modules/picocolors/picocolors.js
36
69
  var require_picocolors = __commonJS({
37
70
  "node_modules/picocolors/picocolors.js"(exports, module) {
@@ -189,7 +222,7 @@ var SAFE_LOGICAL, SAFE_SEGMENT, RESERVED_SHARED;
189
222
  var init_config_sharedDirs_guard = __esm({
190
223
  "src/config.sharedDirs.guard.ts"() {
191
224
  "use strict";
192
- init_config();
225
+ init_config_never_sync();
193
226
  init_utils();
194
227
  SAFE_LOGICAL = /^[A-Za-z0-9._-]+$/;
195
228
  SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/;
@@ -341,12 +374,13 @@ function allSharedLinks(map) {
341
374
  }
342
375
  return [...SHARED_LINKS, ...extras];
343
376
  }
344
- var HOME, CLAUDE_HOME, BACKUP_BASE, REPO_HOME, SETTINGS_SCHEMA_URL, NPM_REGISTRY_LATEST_URL, GITLEAKS_PINNED_VERSION, HOST, SHARED_LINKS, SUPPORTED_EXTRAS, ALWAYS_NEVER_SYNC, NEVER_SYNC, PUSH_ALLOWED_STATIC;
377
+ var HOME, CLAUDE_HOME, BACKUP_BASE, REPO_HOME, SETTINGS_SCHEMA_URL, NPM_REGISTRY_LATEST_URL, GITLEAKS_PINNED_VERSION, HOST, SHARED_LINKS, SUPPORTED_EXTRAS, ALWAYS_NEVER_SYNC, PUSH_ALLOWED_STATIC;
345
378
  var init_config = __esm({
346
379
  "src/config.ts"() {
347
380
  "use strict";
348
381
  init_config_sharedDirs_guard();
349
382
  init_utils();
383
+ init_config_never_sync();
350
384
  init_settings_keys();
351
385
  HOME = homedir();
352
386
  CLAUDE_HOME = resolve(HOME, ".claude");
@@ -373,31 +407,6 @@ var init_config = __esm({
373
407
  "history.jsonl",
374
408
  "stats-cache.json"
375
409
  ]);
376
- NEVER_SYNC = /* @__PURE__ */ new Set([
377
- ".claude.json",
378
- ".credentials.json",
379
- "history.jsonl",
380
- "settings.local.json",
381
- "stats-cache.json",
382
- "todos",
383
- "shell-snapshots",
384
- "debug",
385
- "file-history",
386
- "plans",
387
- "session-env",
388
- "statsig",
389
- "telemetry",
390
- "ide",
391
- // Host-local caches and runtime state (sharedDirs guard also rejects these).
392
- "cache",
393
- "backups",
394
- "paste-cache",
395
- "daemon",
396
- "jobs",
397
- "tasks",
398
- "security",
399
- "sessions"
400
- ]);
401
410
  PUSH_ALLOWED_STATIC = [
402
411
  "shared/CLAUDE.md",
403
412
  "shared/my-statusline.cjs",
@@ -541,10 +550,9 @@ var init_utils_fs = __esm({
541
550
  }
542
551
  });
543
552
 
544
- // src/push-gitleaks.scan.ts
545
- import { execFileSync as execFileSync2 } from "node:child_process";
546
- import { existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync3, rmSync as rmSync3 } from "node:fs";
547
- import { homedir as homedir2 } from "node:os";
553
+ // src/push-gitleaks.config.ts
554
+ import { existsSync as existsSync9, mkdtempSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
555
+ import { tmpdir } from "node:os";
548
556
  import { join as join10 } from "node:path";
549
557
  import { fileURLToPath } from "node:url";
550
558
  function resolveTomlPath() {
@@ -553,110 +561,21 @@ function resolveTomlPath() {
553
561
  const bundled = fileURLToPath(new URL("../.gitleaks.toml", import.meta.url));
554
562
  return existsSync9(bundled) ? bundled : null;
555
563
  }
556
- function readGitleaksReport(reportPath) {
557
- try {
558
- const raw = readFileSync3(reportPath, "utf8");
559
- const parsed = JSON.parse(raw);
560
- if (!Array.isArray(parsed)) return null;
561
- return parsed;
562
- } catch {
563
- return null;
564
- }
565
- }
566
- function scanStagedTree(repoDir, forwardStreams = false) {
567
- const cacheDir = join10(homedir2(), ".cache", "claude-nomad");
568
- mkdirSync2(cacheDir, { recursive: true });
569
- const reportPath = join10(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
570
- const { path: toml, tempPath } = resolveTomlConfig();
571
- const args = [
572
- "protect",
573
- "--staged",
574
- "--redact",
575
- "-v",
576
- "--report-format=json",
577
- `--report-path=${reportPath}`
578
- ];
579
- if (toml !== null) args.push("--config", toml);
580
- const opts = { cwd: repoDir, stdio: ["ignore", "pipe", "pipe"] };
581
- try {
582
- execFileSync2("git", ["init", "-q"], opts);
583
- execFileSync2("git", ["add", "-A"], opts);
584
- execFileSync2("gitleaks", args, opts);
585
- return [];
586
- } catch (err) {
587
- const e = err;
588
- if (e.code === "ENOENT") throw err;
589
- const report = readGitleaksReport(reportPath);
590
- if (forwardStreams && report === null) {
591
- if (e.stderr) process.stderr.write(e.stderr);
592
- if (e.stdout) process.stdout.write(e.stdout);
593
- }
594
- return report;
595
- } finally {
596
- if (tempPath !== null) rmSync3(tempPath, { recursive: true, force: true });
597
- rmSync3(reportPath, { force: true });
598
- }
599
- }
600
- function scanFile(filePath, forwardStreams = false) {
601
- const cacheDir = join10(homedir2(), ".cache", "claude-nomad");
602
- mkdirSync2(cacheDir, { recursive: true });
603
- const reportPath = join10(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}.json`);
604
- const { path: toml, tempPath } = resolveTomlConfig();
605
- const args = [
606
- "detect",
607
- "--no-git",
608
- "--source",
609
- filePath,
610
- "--report-format=json",
611
- `--report-path=${reportPath}`
612
- ];
613
- if (toml !== null) args.push("--config", toml);
614
- const opts = { stdio: ["ignore", "pipe", "pipe"] };
615
- try {
616
- execFileSync2("gitleaks", args, opts);
617
- return [];
618
- } catch (err) {
619
- const e = err;
620
- if (e.code === "ENOENT") return null;
621
- const report = readGitleaksReport(reportPath);
622
- if (forwardStreams && report === null) {
623
- if (e.stderr) process.stderr.write(e.stderr);
624
- if (e.stdout) process.stdout.write(e.stdout);
625
- }
626
- return report;
627
- } finally {
628
- if (tempPath !== null) rmSync3(tempPath, { recursive: true, force: true });
629
- rmSync3(reportPath, { force: true });
630
- }
631
- }
632
- var init_push_gitleaks_scan = __esm({
633
- "src/push-gitleaks.scan.ts"() {
634
- "use strict";
635
- init_config();
636
- init_push_gitleaks_config();
637
- init_utils_fs();
638
- }
639
- });
640
-
641
- // src/push-gitleaks.config.ts
642
- import { existsSync as existsSync10, mkdtempSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
643
- import { tmpdir } from "node:os";
644
- import { join as join11 } from "node:path";
645
564
  function buildOverlayTempConfig(overlayBody, bundled) {
646
565
  const tempBody = `[extend]
647
566
  path = ${JSON.stringify(bundled)}
648
567
 
649
568
  ${overlayBody}`;
650
- const tempPath = mkdtempSync(join11(tmpdir(), "nomad-gitleaks-cfg-"));
651
- const configPath = join11(tempPath, "config.toml");
569
+ const tempPath = mkdtempSync(join10(tmpdir(), "nomad-gitleaks-cfg-"));
570
+ const configPath = join10(tempPath, "config.toml");
652
571
  writeFileSync2(configPath, tempBody, { mode: 384, flag: "wx" });
653
572
  return { configPath, tempPath };
654
573
  }
655
574
  function resolveTomlConfig() {
656
- const overlayPath = join11(REPO_HOME, ".gitleaks.overlay.toml");
657
- const repoToml = join11(REPO_HOME, ".gitleaks.toml");
575
+ const overlayPath = join10(REPO_HOME, ".gitleaks.overlay.toml");
576
+ const repoToml = join10(REPO_HOME, ".gitleaks.toml");
658
577
  const bundled = resolveTomlPath();
659
- if (!existsSync10(overlayPath)) {
578
+ if (!existsSync9(overlayPath)) {
660
579
  return { path: bundled, tempPath: null };
661
580
  }
662
581
  if (bundled === repoToml) {
@@ -669,7 +588,7 @@ function resolveTomlConfig() {
669
588
  return { path: null, tempPath: null };
670
589
  }
671
590
  try {
672
- const overlayBody = readFileSync4(overlayPath, "utf8");
591
+ const overlayBody = readFileSync3(overlayPath, "utf8");
673
592
  if (OVERLAY_EXTEND_RE.test(overlayBody)) {
674
593
  throw new NomadFatal(
675
594
  ".gitleaks.overlay.toml must not contain an [extend] block; it is generated automatically. Remove the [extend] section and retry."
@@ -690,17 +609,16 @@ var init_push_gitleaks_config = __esm({
690
609
  "src/push-gitleaks.config.ts"() {
691
610
  "use strict";
692
611
  init_config();
693
- init_push_gitleaks_scan();
694
612
  init_utils();
695
613
  OVERLAY_EXTEND_RE = /^\s*(?:\[\s*extend\s*\]|extend\s*[.=])/m;
696
614
  }
697
615
  });
698
616
 
699
617
  // src/push-checks.ts
700
- import { execFileSync as execFileSync3 } from "node:child_process";
701
- import { readdirSync as readdirSync3, rmSync as rmSync4 } from "node:fs";
702
- import { homedir as homedir3, platform } from "node:os";
703
- import { join as join12 } from "node:path";
618
+ import { execFileSync as execFileSync2 } from "node:child_process";
619
+ import { readdirSync as readdirSync3, rmSync as rmSync3 } from "node:fs";
620
+ import { homedir as homedir2, platform } from "node:os";
621
+ import { join as join11 } from "node:path";
704
622
  function gitleaksInstallHint() {
705
623
  const head = "gitleaks not on PATH (required for nomad push). Install:";
706
624
  const plat = platform();
@@ -720,7 +638,7 @@ function gitleaksInstallHint() {
720
638
  " chmod +x ~/.local/bin/gitleaks",
721
639
  " ~/.local/bin/gitleaks version # verify"
722
640
  ];
723
- const localBin = `${homedir3()}/.local/bin`;
641
+ const localBin = `${homedir2()}/.local/bin`;
724
642
  const paths = (process.env.PATH ?? "").split(":");
725
643
  if (!paths.includes(localBin)) {
726
644
  lines.push(
@@ -743,7 +661,7 @@ function findGitlinks(dir) {
743
661
  return;
744
662
  }
745
663
  for (const e of entries) {
746
- const p = join12(current, e.name);
664
+ const p = join11(current, e.name);
747
665
  if (e.name === ".git") {
748
666
  hits.push(p);
749
667
  continue;
@@ -759,18 +677,18 @@ function probeGitleaks() {
759
677
  const args = ["version"];
760
678
  if (toml !== null) args.push("--config", toml);
761
679
  try {
762
- return execFileSync3("gitleaks", args, { stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
680
+ return execFileSync2("gitleaks", args, { stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
763
681
  } catch (err) {
764
682
  const e = err;
765
683
  if (e.code === "ENOENT") throw new NomadFatal(gitleaksInstallHint());
766
684
  throw new NomadFatal(`gitleaks --version failed: ${e.message}`);
767
685
  } finally {
768
- if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
686
+ if (tempPath !== null) rmSync3(tempPath, { recursive: true, force: true });
769
687
  }
770
688
  }
771
689
  function rebaseBeforePush() {
772
690
  try {
773
- execFileSync3("git", ["pull", "--rebase", "--autostash"], {
691
+ execFileSync2("git", ["pull", "--rebase", "--autostash"], {
774
692
  cwd: REPO_HOME,
775
693
  stdio: ["ignore", "pipe", "pipe"]
776
694
  });
@@ -791,6 +709,95 @@ var init_push_checks = __esm({
791
709
  }
792
710
  });
793
711
 
712
+ // src/push-gitleaks.scan.ts
713
+ import { execFileSync as execFileSync5 } from "node:child_process";
714
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync as rmSync4 } from "node:fs";
715
+ import { homedir as homedir3 } from "node:os";
716
+ import { join as join15 } from "node:path";
717
+ function readGitleaksReport(reportPath) {
718
+ try {
719
+ const raw = readFileSync4(reportPath, "utf8");
720
+ const parsed = JSON.parse(raw);
721
+ if (!Array.isArray(parsed)) return null;
722
+ return parsed;
723
+ } catch {
724
+ return null;
725
+ }
726
+ }
727
+ function scanStagedTree(repoDir, forwardStreams = false) {
728
+ const cacheDir = join15(homedir3(), ".cache", "claude-nomad");
729
+ mkdirSync2(cacheDir, { recursive: true });
730
+ const reportPath = join15(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
731
+ const { path: toml, tempPath } = resolveTomlConfig();
732
+ const args = [
733
+ "protect",
734
+ "--staged",
735
+ "--redact",
736
+ "-v",
737
+ "--report-format=json",
738
+ `--report-path=${reportPath}`
739
+ ];
740
+ if (toml !== null) args.push("--config", toml);
741
+ const opts = { cwd: repoDir, stdio: ["ignore", "pipe", "pipe"] };
742
+ try {
743
+ execFileSync5("git", ["init", "-q"], opts);
744
+ execFileSync5("git", ["add", "-A"], opts);
745
+ execFileSync5("gitleaks", args, opts);
746
+ return [];
747
+ } catch (err) {
748
+ const e = err;
749
+ if (e.code === "ENOENT") throw err;
750
+ const report = readGitleaksReport(reportPath);
751
+ if (forwardStreams && report === null) {
752
+ if (e.stderr) process.stderr.write(e.stderr);
753
+ if (e.stdout) process.stdout.write(e.stdout);
754
+ }
755
+ return report;
756
+ } finally {
757
+ if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
758
+ rmSync4(reportPath, { force: true });
759
+ }
760
+ }
761
+ function scanFile(filePath, forwardStreams = false) {
762
+ const cacheDir = join15(homedir3(), ".cache", "claude-nomad");
763
+ mkdirSync2(cacheDir, { recursive: true });
764
+ const reportPath = join15(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}.json`);
765
+ const { path: toml, tempPath } = resolveTomlConfig();
766
+ const args = [
767
+ "detect",
768
+ "--no-git",
769
+ "--source",
770
+ filePath,
771
+ "--report-format=json",
772
+ `--report-path=${reportPath}`
773
+ ];
774
+ if (toml !== null) args.push("--config", toml);
775
+ const opts = { stdio: ["ignore", "pipe", "pipe"] };
776
+ try {
777
+ execFileSync5("gitleaks", args, opts);
778
+ return [];
779
+ } catch (err) {
780
+ const e = err;
781
+ if (e.code === "ENOENT") return null;
782
+ const report = readGitleaksReport(reportPath);
783
+ if (forwardStreams && report === null) {
784
+ if (e.stderr) process.stderr.write(e.stderr);
785
+ if (e.stdout) process.stdout.write(e.stdout);
786
+ }
787
+ return report;
788
+ } finally {
789
+ if (tempPath !== null) rmSync4(tempPath, { recursive: true, force: true });
790
+ rmSync4(reportPath, { force: true });
791
+ }
792
+ }
793
+ var init_push_gitleaks_scan = __esm({
794
+ "src/push-gitleaks.scan.ts"() {
795
+ "use strict";
796
+ init_push_gitleaks_config();
797
+ init_utils_fs();
798
+ }
799
+ });
800
+
794
801
  // src/push-gitleaks.ts
795
802
  function findingIdentityKey(f) {
796
803
  const fp = f.Fingerprint;
@@ -870,7 +877,6 @@ var init_push_gitleaks = __esm({
870
877
  init_push_checks();
871
878
  init_push_gitleaks_scan();
872
879
  init_utils();
873
- init_push_gitleaks_scan();
874
880
  SESSION_PATH = /^shared\/projects\/[^/]+\/([^/]+)\.jsonl$/;
875
881
  SUBAGENT_SESSION_PATH = /^shared\/projects\/[^/]+\/([^/]+)\/.*\.jsonl$/;
876
882
  LEGACY_FATAL = "gitleaks detected secrets; review staged changes with git diff --cached and unstage offending files before retry";
@@ -1204,7 +1210,7 @@ function cmdClean(opts, backupBase = BACKUP_BASE) {
1204
1210
  }
1205
1211
 
1206
1212
  // src/commands.doctor.ts
1207
- import { existsSync as existsSync19 } from "node:fs";
1213
+ import { existsSync as existsSync18 } from "node:fs";
1208
1214
  import { join as join22 } from "node:path";
1209
1215
 
1210
1216
  // src/commands.doctor.checks.repo.ts
@@ -1535,14 +1541,14 @@ function reportNeverSync(section2) {
1535
1541
  // src/commands.doctor.checks.repository.ts
1536
1542
  init_color();
1537
1543
  init_config();
1538
- import { execFileSync as execFileSync4 } from "node:child_process";
1539
- import { existsSync as existsSync11 } from "node:fs";
1540
- import { join as join13, relative as relative2 } from "node:path";
1544
+ import { execFileSync as execFileSync3 } from "node:child_process";
1545
+ import { existsSync as existsSync10 } from "node:fs";
1546
+ import { join as join12, relative as relative2 } from "node:path";
1541
1547
  init_push_checks();
1542
1548
  init_utils();
1543
1549
  function reportGitleaksProbe(section2) {
1544
1550
  try {
1545
- const v = execFileSync4("gitleaks", ["version"], { stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
1551
+ const v = execFileSync3("gitleaks", ["version"], { stdio: ["ignore", "pipe", "pipe"] }).toString().trim();
1546
1552
  addItem(section2, `${green(okGlyph)} gitleaks: ${dim(v)}`);
1547
1553
  return true;
1548
1554
  } catch (err) {
@@ -1556,8 +1562,8 @@ function reportGitleaksProbe(section2) {
1556
1562
  }
1557
1563
  }
1558
1564
  function reportGitlinks(section2) {
1559
- const sharedDir = join13(REPO_HOME, "shared");
1560
- if (existsSync11(sharedDir)) {
1565
+ const sharedDir = join12(REPO_HOME, "shared");
1566
+ if (existsSync10(sharedDir)) {
1561
1567
  const gitlinks = findGitlinks(sharedDir);
1562
1568
  for (const p of gitlinks) {
1563
1569
  const rel = relative2(REPO_HOME, p);
@@ -1575,7 +1581,7 @@ function reportGitlinks(section2) {
1575
1581
  }
1576
1582
  function reportRemote(section2) {
1577
1583
  try {
1578
- const url = execFileSync4("git", ["remote", "get-url", "origin"], {
1584
+ const url = execFileSync3("git", ["remote", "get-url", "origin"], {
1579
1585
  cwd: REPO_HOME,
1580
1586
  stdio: ["ignore", "pipe", "pipe"]
1581
1587
  }).toString().trim();
@@ -1599,8 +1605,8 @@ function reportRebaseClean(section2) {
1599
1605
 
1600
1606
  // src/commands.doctor.checks.backups.ts
1601
1607
  init_color();
1602
- import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
1603
- import { join as join14 } from "node:path";
1608
+ import { existsSync as existsSync11, lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
1609
+ import { join as join13 } from "node:path";
1604
1610
  init_config();
1605
1611
  var TS_SHAPE2 = /^\d{8}-\d{6}(-\d+)?$/;
1606
1612
  function safeReaddir(dir) {
@@ -1616,7 +1622,7 @@ var BYTES_PER_MB = 1024 * 1024;
1616
1622
  function dirSizeBytes(dir) {
1617
1623
  let bytes = 0;
1618
1624
  for (const entry of safeReaddir(dir)) {
1619
- const full = join14(dir, entry);
1625
+ const full = join13(dir, entry);
1620
1626
  const st = lstatSync5(full, { throwIfNoEntry: false });
1621
1627
  if (!st) continue;
1622
1628
  if (st.isSymbolicLink()) continue;
@@ -1627,11 +1633,11 @@ function dirSizeBytes(dir) {
1627
1633
  }
1628
1634
  function totalSizeMb(backupBase, dirs) {
1629
1635
  let bytes = 0;
1630
- for (const name of dirs) bytes += dirSizeBytes(join14(backupBase, name));
1636
+ for (const name of dirs) bytes += dirSizeBytes(join13(backupBase, name));
1631
1637
  return bytes / BYTES_PER_MB;
1632
1638
  }
1633
1639
  function reportBackupsCheck(section2, backupBase = BACKUP_BASE) {
1634
- if (!existsSync12(backupBase)) return;
1640
+ if (!existsSync11(backupBase)) return;
1635
1641
  const dirs = safeReaddir(backupBase).filter((n) => TS_SHAPE2.test(n));
1636
1642
  const count = dirs.length;
1637
1643
  const sizeMb = totalSizeMb(backupBase, dirs);
@@ -1645,14 +1651,14 @@ function reportBackupsCheck(section2, backupBase = BACKUP_BASE) {
1645
1651
 
1646
1652
  // src/commands.doctor.check-schema.ts
1647
1653
  init_color();
1648
- import { existsSync as existsSync13 } from "node:fs";
1649
- import { join as join15 } from "node:path";
1654
+ import { existsSync as existsSync12 } from "node:fs";
1655
+ import { join as join14 } from "node:path";
1650
1656
  init_config();
1651
1657
 
1652
1658
  // src/http-fetch.ts
1653
- import { execFileSync as execFileSync5 } from "node:child_process";
1659
+ import { execFileSync as execFileSync4 } from "node:child_process";
1654
1660
  var FETCH_TIMEOUT_MS = 3e3;
1655
- function fetchUrl(url, run = execFileSync5) {
1661
+ function fetchUrl(url, run = execFileSync4) {
1656
1662
  try {
1657
1663
  return run("curl", ["-fsSL", "-m", "3", url], {
1658
1664
  stdio: ["ignore", "pipe", "pipe"],
@@ -1683,8 +1689,8 @@ function fetchSchemaKeys() {
1683
1689
  }
1684
1690
  }
1685
1691
  function reportCheckSchema(section2) {
1686
- const settingsPath = join15(CLAUDE_HOME, "settings.json");
1687
- if (!existsSync13(settingsPath)) {
1692
+ const settingsPath = join14(CLAUDE_HOME, "settings.json");
1693
+ if (!existsSync12(settingsPath)) {
1688
1694
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json to check`);
1689
1695
  return;
1690
1696
  }
@@ -1714,7 +1720,7 @@ function reportCheckSchema(section2) {
1714
1720
  init_color();
1715
1721
  import { randomBytes } from "node:crypto";
1716
1722
  import { execFileSync as execFileSync6 } from "node:child_process";
1717
- import { existsSync as existsSync15, mkdirSync as mkdirSync4, readdirSync as readdirSync6, rmSync as rmSync6 } from "node:fs";
1723
+ import { existsSync as existsSync14, mkdirSync as mkdirSync4, readdirSync as readdirSync6, rmSync as rmSync6 } from "node:fs";
1718
1724
  import { homedir as homedir4 } from "node:os";
1719
1725
  import { join as join18 } from "node:path";
1720
1726
 
@@ -1817,7 +1823,7 @@ init_config();
1817
1823
  init_utils();
1818
1824
  init_utils_fs();
1819
1825
  init_utils_json();
1820
- import { cpSync as cpSync3, existsSync as existsSync14, mkdirSync as mkdirSync3, readdirSync as readdirSync5, rmSync as rmSync5, statSync as statSync4 } from "node:fs";
1826
+ import { cpSync as cpSync3, existsSync as existsSync13, mkdirSync as mkdirSync3, readdirSync as readdirSync5, rmSync as rmSync5, statSync as statSync4 } from "node:fs";
1821
1827
  import { join as join17, relative as relative3, sep } from "node:path";
1822
1828
  function copyDir(src, dst) {
1823
1829
  rmSync5(dst, { recursive: true, force: true });
@@ -1846,7 +1852,7 @@ function remapPull(ts, opts = {}) {
1846
1852
  const wouldPull = [];
1847
1853
  const mapPath = join17(REPO_HOME, "path-map.json");
1848
1854
  const repoProjects = join17(REPO_HOME, "shared", "projects");
1849
- if (!existsSync14(mapPath) || !existsSync14(repoProjects)) {
1855
+ if (!existsSync13(mapPath) || !existsSync13(repoProjects)) {
1850
1856
  log("no path-map or repo projects dir; skipping session remap");
1851
1857
  return { unmapped: 0, pulled, wouldPull };
1852
1858
  }
@@ -1861,7 +1867,7 @@ function remapPull(ts, opts = {}) {
1861
1867
  continue;
1862
1868
  }
1863
1869
  const src = join17(repoProjects, logical);
1864
- if (!existsSync14(src)) continue;
1870
+ if (!existsSync13(src)) continue;
1865
1871
  const dst = join17(localProjects, encodePath(localPath));
1866
1872
  if (dryRun) {
1867
1873
  wouldPull.push(logical);
@@ -1904,7 +1910,7 @@ function remapPush(ts, opts = {}) {
1904
1910
  const pushed = [];
1905
1911
  const wouldPush = [];
1906
1912
  const mapPath = join17(REPO_HOME, "path-map.json");
1907
- if (!existsSync14(mapPath)) {
1913
+ if (!existsSync13(mapPath)) {
1908
1914
  log("no path-map.json; skipping session export");
1909
1915
  return { unmapped: 0, collisions: 0, pushed, wouldPush };
1910
1916
  }
@@ -1912,7 +1918,7 @@ function remapPush(ts, opts = {}) {
1912
1918
  const localProjects = join17(CLAUDE_HOME, "projects");
1913
1919
  const repoProjects = join17(REPO_HOME, "shared", "projects");
1914
1920
  const reverse = buildReverseMap(map);
1915
- if (!existsSync14(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
1921
+ if (!existsSync13(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
1916
1922
  if (!dryRun) mkdirSync3(repoProjects, { recursive: true });
1917
1923
  for (const dir of readdirSync5(localProjects)) {
1918
1924
  const logical = reverse.get(dir);
@@ -1939,7 +1945,7 @@ function buildScanTree(tmpRoot) {
1939
1945
  const logicalToEncoded = /* @__PURE__ */ new Map();
1940
1946
  let staged = 0;
1941
1947
  const mapPath = join18(REPO_HOME, "path-map.json");
1942
- if (!existsSync15(mapPath)) return { logicalToEncoded, staged, malformed: false };
1948
+ if (!existsSync14(mapPath)) return { logicalToEncoded, staged, malformed: false };
1943
1949
  let map;
1944
1950
  try {
1945
1951
  map = readJson(mapPath);
@@ -1957,7 +1963,7 @@ function buildScanTree(tmpRoot) {
1957
1963
  reverse.set(encodePath(p), logical);
1958
1964
  }
1959
1965
  const localProjects = join18(CLAUDE_HOME, "projects");
1960
- if (!existsSync15(localProjects)) return { logicalToEncoded, staged, malformed: false };
1966
+ if (!existsSync14(localProjects)) return { logicalToEncoded, staged, malformed: false };
1961
1967
  for (const dir of readdirSync6(localProjects)) {
1962
1968
  const logical = reverse.get(dir);
1963
1969
  if (!logical) continue;
@@ -2017,7 +2023,7 @@ function reportCheckShared(section2, gitleaksReady) {
2017
2023
 
2018
2024
  // src/commands.doctor.checks.hooks.scope.ts
2019
2025
  init_color();
2020
- import { existsSync as existsSync16, readFileSync as readFileSync5, readdirSync as readdirSync7, realpathSync } from "node:fs";
2026
+ import { existsSync as existsSync15, readFileSync as readFileSync5, readdirSync as readdirSync7, realpathSync } from "node:fs";
2021
2027
  import { dirname as dirname2, extname, join as join19 } from "node:path";
2022
2028
  init_config();
2023
2029
  function typeFromPackageJson(pkgPath) {
@@ -2041,7 +2047,7 @@ function effectiveType(hookPath) {
2041
2047
  let dir = dirname2(real);
2042
2048
  for (; ; ) {
2043
2049
  const pkg = join19(dir, "package.json");
2044
- if (existsSync16(pkg)) return typeFromPackageJson(pkg);
2050
+ if (existsSync15(pkg)) return typeFromPackageJson(pkg);
2045
2051
  const parent = dirname2(dir);
2046
2052
  if (parent === dir) return "cjs";
2047
2053
  dir = parent;
@@ -2084,7 +2090,7 @@ function safeRead(path) {
2084
2090
  }
2085
2091
  function reportHookScopeCheck(section2) {
2086
2092
  const hooksDir = join19(CLAUDE_HOME, "hooks");
2087
- if (!existsSync16(hooksDir)) {
2093
+ if (!existsSync15(hooksDir)) {
2088
2094
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/hooks; skipping module-scope check`);
2089
2095
  return;
2090
2096
  }
@@ -2111,7 +2117,7 @@ function reportHookScopeCheck(section2) {
2111
2117
 
2112
2118
  // src/commands.doctor.checks.hooks.ts
2113
2119
  init_color();
2114
- import { existsSync as existsSync17 } from "node:fs";
2120
+ import { existsSync as existsSync16 } from "node:fs";
2115
2121
  import { join as join20 } from "node:path";
2116
2122
  init_config();
2117
2123
  function expandHome(token) {
@@ -2150,7 +2156,7 @@ function checkEventGroups(section2, event, groups) {
2150
2156
  for (const group of groups) {
2151
2157
  for (const cmd of commandsFromGroup(group)) {
2152
2158
  for (const resolved of claudePathsIn(cmd)) {
2153
- if (existsSync17(resolved)) continue;
2159
+ if (existsSync16(resolved)) continue;
2154
2160
  addItem(section2, `${red(failGlyph)} hooks/${event}: command target missing: ${resolved}`);
2155
2161
  process.exitCode = 1;
2156
2162
  anyFail = true;
@@ -2161,7 +2167,7 @@ function checkEventGroups(section2, event, groups) {
2161
2167
  }
2162
2168
  function reportHooksTargetCheck(section2) {
2163
2169
  const settingsPath = join20(CLAUDE_HOME, "settings.json");
2164
- if (!existsSync17(settingsPath)) {
2170
+ if (!existsSync16(settingsPath)) {
2165
2171
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping hook target check`);
2166
2172
  return;
2167
2173
  }
@@ -2291,7 +2297,7 @@ function reportNodeEngineCheck(section2) {
2291
2297
  // src/commands.doctor.gitleaks-version.ts
2292
2298
  init_color();
2293
2299
  import { execFileSync as execFileSync7 } from "node:child_process";
2294
- import { existsSync as existsSync18 } from "node:fs";
2300
+ import { existsSync as existsSync17 } from "node:fs";
2295
2301
  import { join as join21 } from "node:path";
2296
2302
  init_config();
2297
2303
  var SEMVER_MAJOR_MINOR = /^(\d+)\.(\d+)\.\d+$/;
@@ -2313,7 +2319,7 @@ function readGitleaksVersion(run, tomlExists) {
2313
2319
  return null;
2314
2320
  }
2315
2321
  }
2316
- function reportGitleaksVersionCheck(section2, run = execFileSync7, tomlExists = existsSync18) {
2322
+ function reportGitleaksVersionCheck(section2, run = execFileSync7, tomlExists = existsSync17) {
2317
2323
  const raw = readGitleaksVersion(run, tomlExists);
2318
2324
  if (raw === null) return;
2319
2325
  const local = majorMinorOf(raw);
@@ -2487,7 +2493,7 @@ function cmdDoctor(opts = {}) {
2487
2493
  reportRepoState(host);
2488
2494
  const links = section("Shared links");
2489
2495
  const mapPath = join22(REPO_HOME, "path-map.json");
2490
- const rawMap = existsSync19(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
2496
+ const rawMap = existsSync18(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
2491
2497
  const map = rawMap ?? { projects: {} };
2492
2498
  reportSharedLinks(links, map);
2493
2499
  const hooksScan = section("Hook targets");
@@ -2534,7 +2540,7 @@ function cmdDoctor(opts = {}) {
2534
2540
  // src/commands.drop-session.ts
2535
2541
  init_config();
2536
2542
  import { execFileSync as execFileSync12 } from "node:child_process";
2537
- import { existsSync as existsSync21, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
2543
+ import { existsSync as existsSync20, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
2538
2544
  import { join as join25, relative as relative4 } from "node:path";
2539
2545
 
2540
2546
  // src/commands.drop-session.git.ts
@@ -2578,7 +2584,7 @@ function isInIndex(rel) {
2578
2584
  init_config();
2579
2585
  init_utils();
2580
2586
  init_utils_json();
2581
- import { existsSync as existsSync20 } from "node:fs";
2587
+ import { existsSync as existsSync19 } from "node:fs";
2582
2588
  import { join as join23 } from "node:path";
2583
2589
  var SHARED_PROJECT_LOGICAL = /^shared\/projects\/([^/]+)\//;
2584
2590
  function reportScrubHint(id, matches) {
@@ -2596,7 +2602,7 @@ function reportScrubHint(id, matches) {
2596
2602
  function resolveLiveTranscript(id, matches) {
2597
2603
  try {
2598
2604
  const mapPath = join23(REPO_HOME, "path-map.json");
2599
- if (!existsSync20(mapPath)) return null;
2605
+ if (!existsSync19(mapPath)) return null;
2600
2606
  const projects = readJson(mapPath).projects;
2601
2607
  for (const rel of matches) {
2602
2608
  const logical = SHARED_PROJECT_LOGICAL.exec(rel)?.[1];
@@ -2604,7 +2610,7 @@ function resolveLiveTranscript(id, matches) {
2604
2610
  const abs = projects[logical]?.[HOST];
2605
2611
  if (abs === void 0) continue;
2606
2612
  const live = join23(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
2607
- if (existsSync20(live)) return live;
2613
+ if (existsSync19(live)) return live;
2608
2614
  }
2609
2615
  return null;
2610
2616
  } catch {
@@ -2730,12 +2736,12 @@ function cmdDropSession(id) {
2730
2736
  fail(`invalid session id: ${id}`);
2731
2737
  process.exit(1);
2732
2738
  }
2733
- if (!existsSync21(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2739
+ if (!existsSync20(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2734
2740
  const handle = acquireLock("drop-session");
2735
2741
  if (handle === null) process.exit(0);
2736
2742
  try {
2737
2743
  const repoProjects = join25(REPO_HOME, "shared", "projects");
2738
- if (!existsSync21(repoProjects)) {
2744
+ if (!existsSync20(repoProjects)) {
2739
2745
  throw new NomadFatal(`no staged session matches ${id}`);
2740
2746
  }
2741
2747
  const matches = collectMatches(repoProjects, id);
@@ -2758,11 +2764,11 @@ function collectMatches(repoProjects, id) {
2758
2764
  const matches = [];
2759
2765
  for (const logical of readdirSync8(repoProjects)) {
2760
2766
  const candidate = join25(repoProjects, logical, `${id}.jsonl`);
2761
- if (existsSync21(candidate)) {
2767
+ if (existsSync20(candidate)) {
2762
2768
  matches.push(relative4(REPO_HOME, candidate));
2763
2769
  }
2764
2770
  const dir = join25(repoProjects, logical, id);
2765
- if (existsSync21(dir) && statSync5(dir).isDirectory()) {
2771
+ if (existsSync20(dir) && statSync5(dir).isDirectory()) {
2766
2772
  const dirRel = relative4(REPO_HOME, dir);
2767
2773
  const staged = expandStagedDir(dirRel);
2768
2774
  if (staged.length > 0) matches.push(...staged);
@@ -2798,15 +2804,15 @@ function unstageOne(rel) {
2798
2804
 
2799
2805
  // src/commands.redact.ts
2800
2806
  init_config();
2801
- import { existsSync as existsSync23, statSync as statSync7 } from "node:fs";
2807
+ import { existsSync as existsSync22, statSync as statSync7 } from "node:fs";
2802
2808
  import { dirname as dirname4, join as join27 } from "node:path";
2803
2809
 
2804
2810
  // src/commands.redact.subtree.ts
2805
- import { existsSync as existsSync22, lstatSync as lstatSync6, readFileSync as readFileSync9, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
2811
+ import { existsSync as existsSync21, lstatSync as lstatSync6, readFileSync as readFileSync9, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
2806
2812
  import { join as join26 } from "node:path";
2807
2813
  init_utils_fs();
2808
2814
  function collectFiles(dir, out) {
2809
- if (!existsSync22(dir)) return;
2815
+ if (!existsSync21(dir)) return;
2810
2816
  const st = lstatSync6(dir);
2811
2817
  if (!st.isDirectory()) return;
2812
2818
  for (const entry of readdirSync9(dir)) {
@@ -2861,13 +2867,13 @@ init_utils();
2861
2867
  function resolveLiveTranscript2(id) {
2862
2868
  try {
2863
2869
  const mapPath = join27(REPO_HOME, "path-map.json");
2864
- if (!existsSync23(mapPath)) return null;
2870
+ if (!existsSync22(mapPath)) return null;
2865
2871
  const projects = readJson(mapPath).projects;
2866
2872
  for (const hostMap of Object.values(projects)) {
2867
2873
  const abs = hostMap[HOST];
2868
2874
  if (abs === void 0) continue;
2869
2875
  const live = join27(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
2870
- if (existsSync23(live)) return live;
2876
+ if (existsSync22(live)) return live;
2871
2877
  }
2872
2878
  return null;
2873
2879
  } catch {
@@ -2885,12 +2891,12 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
2885
2891
  fail(`invalid session id: ${id}`);
2886
2892
  process.exit(1);
2887
2893
  }
2888
- if (!existsSync23(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2894
+ if (!existsSync22(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2889
2895
  const handle = acquireLock("redact");
2890
2896
  if (handle === null) process.exit(0);
2891
2897
  try {
2892
2898
  const localPath = resolveLiveTranscript2(id);
2893
- if (localPath === null || !existsSync23(localPath)) {
2899
+ if (localPath === null || !existsSync22(localPath)) {
2894
2900
  fail(`could not resolve local transcript for session ${id} on this host`);
2895
2901
  process.exitCode = 1;
2896
2902
  return;
@@ -2948,7 +2954,7 @@ ${lines}`);
2948
2954
  }
2949
2955
 
2950
2956
  // src/commands.pull.ts
2951
- import { existsSync as existsSync29, mkdirSync as mkdirSync7 } from "node:fs";
2957
+ import { existsSync as existsSync28, mkdirSync as mkdirSync7 } from "node:fs";
2952
2958
  import { join as join33 } from "node:path";
2953
2959
 
2954
2960
  // src/commands.push.sections.ts
@@ -3045,7 +3051,7 @@ init_config();
3045
3051
 
3046
3052
  // src/extras-sync.ts
3047
3053
  init_config();
3048
- import { existsSync as existsSync26 } from "node:fs";
3054
+ import { existsSync as existsSync25 } from "node:fs";
3049
3055
  import { join as join30 } from "node:path";
3050
3056
 
3051
3057
  // src/extras-sync.diff.ts
@@ -3073,7 +3079,7 @@ function listDivergingFiles(a, b) {
3073
3079
 
3074
3080
  // src/extras-sync.core.ts
3075
3081
  init_config();
3076
- import { cpSync as cpSync4, existsSync as existsSync24, rmSync as rmSync7 } from "node:fs";
3082
+ import { cpSync as cpSync4, existsSync as existsSync23, rmSync as rmSync7 } from "node:fs";
3077
3083
  import { join as join28 } from "node:path";
3078
3084
 
3079
3085
  // src/extras-sync.guards.ts
@@ -3099,7 +3105,7 @@ init_utils_json();
3099
3105
  function loadValidatedExtras(opts) {
3100
3106
  const mapPath = join28(REPO_HOME, "path-map.json");
3101
3107
  const repoExtras = join28(REPO_HOME, "shared", "extras");
3102
- if (!existsSync24(mapPath) || opts.requireRepoExtras === true && !existsSync24(repoExtras)) {
3108
+ if (!existsSync23(mapPath) || opts.requireRepoExtras === true && !existsSync23(repoExtras)) {
3103
3109
  if (opts.missingMsg !== void 0) log(opts.missingMsg);
3104
3110
  return null;
3105
3111
  }
@@ -3141,7 +3147,7 @@ init_utils_json();
3141
3147
 
3142
3148
  // src/extras-sync.remap.ts
3143
3149
  init_config();
3144
- import { existsSync as existsSync25, mkdirSync as mkdirSync6 } from "node:fs";
3150
+ import { existsSync as existsSync24, mkdirSync as mkdirSync6 } from "node:fs";
3145
3151
  import { join as join29 } from "node:path";
3146
3152
  init_utils_fs();
3147
3153
  function runExtrasOp(v, dryRun, paths, backup) {
@@ -3150,7 +3156,7 @@ function runExtrasOp(v, dryRun, paths, backup) {
3150
3156
  const would = [];
3151
3157
  for (const t of eachExtrasTarget(v, counts)) {
3152
3158
  const { src, dst } = paths(t);
3153
- if (!existsSync25(src)) continue;
3159
+ if (!existsSync24(src)) continue;
3154
3160
  const item = `${t.logical}/${t.dirname}`;
3155
3161
  if (dryRun) {
3156
3162
  would.push(item);
@@ -3210,7 +3216,7 @@ function divergenceCheckExtras(ts) {
3210
3216
  for (const { logical, localRoot, dirname: dirname6 } of eachExtrasTarget(v, counts)) {
3211
3217
  const local = join30(localRoot, dirname6);
3212
3218
  const repo = join30(REPO_HOME, "shared", "extras", logical, dirname6);
3213
- if (!existsSync26(local) || !existsSync26(repo)) continue;
3219
+ if (!existsSync25(local) || !existsSync25(repo)) continue;
3214
3220
  const diff = listDivergingFiles(local, repo);
3215
3221
  if (diff.length === 0) continue;
3216
3222
  const projectBackupRoot = join30(backupRoot, encodePath(localRoot));
@@ -3226,7 +3232,7 @@ init_config();
3226
3232
  init_utils();
3227
3233
  init_utils_fs();
3228
3234
  init_utils_json();
3229
- import { existsSync as existsSync27, lstatSync as lstatSync7, rmSync as rmSync8 } from "node:fs";
3235
+ import { existsSync as existsSync26, lstatSync as lstatSync7, rmSync as rmSync8 } from "node:fs";
3230
3236
  import { join as join31 } from "node:path";
3231
3237
  function applySharedLinks(ts, map, opts = {}) {
3232
3238
  const dryRun = opts.dryRun === true;
@@ -3234,9 +3240,9 @@ function applySharedLinks(ts, map, opts = {}) {
3234
3240
  for (const name of linkNames) {
3235
3241
  const linkPath = join31(CLAUDE_HOME, name);
3236
3242
  const target = join31(REPO_HOME, "shared", name);
3237
- if (!existsSync27(linkPath)) continue;
3243
+ if (!existsSync26(linkPath)) continue;
3238
3244
  if (lstatSync7(linkPath).isSymbolicLink()) continue;
3239
- if (!existsSync27(target)) continue;
3245
+ if (!existsSync26(target)) continue;
3240
3246
  if (dryRun) {
3241
3247
  log(`would auto-move non-symlink: ${linkPath} -> backup/${ts}/${name}`);
3242
3248
  continue;
@@ -3246,7 +3252,7 @@ function applySharedLinks(ts, map, opts = {}) {
3246
3252
  }
3247
3253
  for (const name of linkNames) {
3248
3254
  const target = join31(REPO_HOME, "shared", name);
3249
- if (!existsSync27(target)) continue;
3255
+ if (!existsSync26(target)) continue;
3250
3256
  if (dryRun) {
3251
3257
  log(`would create symlink: ${join31(CLAUDE_HOME, name)} -> ${target}`);
3252
3258
  continue;
@@ -3258,15 +3264,15 @@ function regenerateSettings(ts, opts = {}) {
3258
3264
  const dryRun = opts.dryRun === true;
3259
3265
  const basePath = join31(REPO_HOME, "shared", "settings.base.json");
3260
3266
  const hostPath = join31(REPO_HOME, "hosts", `${HOST}.json`);
3261
- if (!existsSync27(basePath)) {
3267
+ if (!existsSync26(basePath)) {
3262
3268
  die("repo not initialized; run 'nomad init' to scaffold");
3263
3269
  }
3264
3270
  const base = readJson(basePath);
3265
- const hasOverrides = existsSync27(hostPath);
3271
+ const hasOverrides = existsSync26(hostPath);
3266
3272
  const overrides = hasOverrides ? readJson(hostPath) : {};
3267
3273
  const merged = deepMerge(base, overrides);
3268
3274
  const settingsPath = join31(CLAUDE_HOME, "settings.json");
3269
- if (!hasOverrides && existsSync27(settingsPath)) {
3275
+ if (!hasOverrides && existsSync26(settingsPath)) {
3270
3276
  try {
3271
3277
  const existing = readJson(settingsPath);
3272
3278
  const baseKeys = new Set(Object.keys(base));
@@ -3292,7 +3298,7 @@ function regenerateSettings(ts, opts = {}) {
3292
3298
 
3293
3299
  // src/preview.ts
3294
3300
  init_config();
3295
- import { existsSync as existsSync28 } from "node:fs";
3301
+ import { existsSync as existsSync27 } from "node:fs";
3296
3302
  import { join as join32 } from "node:path";
3297
3303
 
3298
3304
  // node_modules/diff/libesm/diff/base.js
@@ -3579,7 +3585,7 @@ function diffJsonStrings(currentJsonText, newJsonText) {
3579
3585
  return lines.join("\n");
3580
3586
  }
3581
3587
  function readJsonOrNull(path) {
3582
- if (!existsSync28(path)) return null;
3588
+ if (!existsSync27(path)) return null;
3583
3589
  try {
3584
3590
  return readJson(path);
3585
3591
  } catch {
@@ -3593,12 +3599,12 @@ function previewSettings(basePath, hostPath, settingsPath) {
3593
3599
  return;
3594
3600
  }
3595
3601
  const hostOverrides = readJsonOrNull(hostPath);
3596
- if (hostOverrides === null && existsSync28(hostPath)) {
3602
+ if (hostOverrides === null && existsSync27(hostPath)) {
3597
3603
  log(`settings.json: malformed hosts/${HOST}.json; ignoring overrides`);
3598
3604
  }
3599
3605
  const merged = deepMerge(base, hostOverrides ?? {});
3600
3606
  const current = readJsonOrNull(settingsPath);
3601
- if (current === null && existsSync28(settingsPath)) {
3607
+ if (current === null && existsSync27(settingsPath)) {
3602
3608
  log("settings.json: malformed; skipping diff");
3603
3609
  return;
3604
3610
  }
@@ -3648,8 +3654,8 @@ function applyWetPull(ts, map) {
3648
3654
  }
3649
3655
  function cmdPull(opts = {}) {
3650
3656
  const dryRun = opts.dryRun === true;
3651
- if (!existsSync29(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3652
- if (!existsSync29(join33(REPO_HOME, "shared", "settings.base.json"))) {
3657
+ if (!existsSync28(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3658
+ if (!existsSync28(join33(REPO_HOME, "shared", "settings.base.json"))) {
3653
3659
  die("repo not initialized; run 'nomad init' to scaffold");
3654
3660
  }
3655
3661
  const handle = acquireLock("pull");
@@ -3669,7 +3675,7 @@ function cmdPull(opts = {}) {
3669
3675
  );
3670
3676
  gitOrFatal(["pull", "--rebase", "--autostash"], "git pull --rebase", REPO_HOME);
3671
3677
  const mapPath = join33(REPO_HOME, "path-map.json");
3672
- const map = existsSync29(mapPath) ? readPathMap(mapPath) : { projects: {} };
3678
+ const map = existsSync28(mapPath) ? readPathMap(mapPath) : { projects: {} };
3673
3679
  divergenceCheckExtras(ts);
3674
3680
  if (dryRun) {
3675
3681
  const previewResult = computePreview(ts, map);
@@ -3692,7 +3698,7 @@ function cmdPull(opts = {}) {
3692
3698
 
3693
3699
  // src/commands.push.ts
3694
3700
  init_config();
3695
- import { existsSync as existsSync32 } from "node:fs";
3701
+ import { existsSync as existsSync31 } from "node:fs";
3696
3702
  import { join as join38, relative as relative5 } from "node:path";
3697
3703
 
3698
3704
  // src/commands.push.allowlist.ts
@@ -3773,7 +3779,7 @@ import { createInterface } from "node:readline/promises";
3773
3779
  // src/commands.push.recovery.redact.ts
3774
3780
  init_config();
3775
3781
  init_config_sharedDirs_guard();
3776
- import { cpSync as cpSync5, existsSync as existsSync30, mkdirSync as mkdirSync8, statSync as statSync8 } from "node:fs";
3782
+ import { cpSync as cpSync5, existsSync as existsSync29, mkdirSync as mkdirSync8, statSync as statSync8 } from "node:fs";
3777
3783
  import { dirname as dirname5, join as join34, sep as sep2 } from "node:path";
3778
3784
  init_push_gitleaks_scan();
3779
3785
  init_utils_json();
@@ -3863,7 +3869,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
3863
3869
  }
3864
3870
  mkdirSync8(stagedProjectDir, { recursive: true });
3865
3871
  cpSync5(localPath, join34(stagedProjectDir, `${sid}.jsonl`), { force: true });
3866
- if (existsSync30(sessionDir)) {
3872
+ if (existsSync29(sessionDir)) {
3867
3873
  cpSync5(sessionDir, join34(stagedProjectDir, sid), { force: true, recursive: true });
3868
3874
  }
3869
3875
  return true;
@@ -4084,7 +4090,7 @@ init_color();
4084
4090
  init_config();
4085
4091
  init_config_sharedDirs_guard();
4086
4092
  import { randomBytes as randomBytes2 } from "node:crypto";
4087
- import { copyFileSync, existsSync as existsSync31, mkdirSync as mkdirSync9, readdirSync as readdirSync10, rmSync as rmSync11 } from "node:fs";
4093
+ import { copyFileSync, existsSync as existsSync30, mkdirSync as mkdirSync9, readdirSync as readdirSync10, rmSync as rmSync11 } from "node:fs";
4088
4094
  import { homedir as homedir5 } from "node:os";
4089
4095
  import { join as join37 } from "node:path";
4090
4096
  init_push_leak_verdict();
@@ -4102,7 +4108,7 @@ function stageSessions(tmpRoot, map) {
4102
4108
  reverse.set(encodePath(p), logical);
4103
4109
  }
4104
4110
  const localProjects = join37(CLAUDE_HOME, "projects");
4105
- if (!existsSync31(localProjects)) return 0;
4111
+ if (!existsSync30(localProjects)) return 0;
4106
4112
  let staged = 0;
4107
4113
  for (const dir of readdirSync10(localProjects)) {
4108
4114
  const logical = reverse.get(dir);
@@ -4124,7 +4130,7 @@ function stageExtras(tmpRoot, map) {
4124
4130
  for (const dirname6 of dirnames) {
4125
4131
  if (!whitelist.includes(dirname6)) continue;
4126
4132
  const src = join37(localRoot, dirname6);
4127
- if (!existsSync31(src)) continue;
4133
+ if (!existsSync30(src)) continue;
4128
4134
  const dst = join37(tmpRoot, "shared", "extras", logical, dirname6);
4129
4135
  copyExtras(src, dst);
4130
4136
  staged++;
@@ -4144,7 +4150,7 @@ function previewPushLeaks(map) {
4144
4150
  return { leak: false, verdictRow: NOTHING_TO_SCAN_ROW, recovery: null, findings: [] };
4145
4151
  }
4146
4152
  const ignoreFile = join37(REPO_HOME, ".gitleaksignore");
4147
- if (existsSync31(ignoreFile)) {
4153
+ if (existsSync30(ignoreFile)) {
4148
4154
  copyFileSync(ignoreFile, join37(tmpRoot, ".gitleaksignore"));
4149
4155
  }
4150
4156
  let findings;
@@ -4219,7 +4225,7 @@ async function cmdPush(opts = {}) {
4219
4225
  const allowAll = opts.allowAll === true;
4220
4226
  const allowRule = opts.allowRule;
4221
4227
  guardResolutionModeConflicts(dryRun, redactAll, allowAll, allowRule);
4222
- if (!existsSync32(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4228
+ if (!existsSync31(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4223
4229
  const handle = acquireLock("push");
4224
4230
  if (handle === null) process.exit(0);
4225
4231
  try {
@@ -4238,7 +4244,7 @@ async function cmdPush(opts = {}) {
4238
4244
  return;
4239
4245
  }
4240
4246
  const mapPath = join38(REPO_HOME, "path-map.json");
4241
- if (!existsSync32(mapPath)) {
4247
+ if (!existsSync31(mapPath)) {
4242
4248
  if (dryRun) return runDryRunPreview(st, null);
4243
4249
  die("path-map.json missing, cannot enforce push allow-list");
4244
4250
  }
@@ -4278,17 +4284,17 @@ init_config();
4278
4284
 
4279
4285
  // src/diff.ts
4280
4286
  init_config();
4281
- import { existsSync as existsSync33 } from "node:fs";
4287
+ import { existsSync as existsSync32 } from "node:fs";
4282
4288
  import { join as join39 } from "node:path";
4283
4289
  init_utils();
4284
4290
  init_utils_fs();
4285
4291
  init_utils_json();
4286
4292
  function cmdDiff() {
4287
4293
  try {
4288
- if (!existsSync33(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4294
+ if (!existsSync32(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4289
4295
  const ts = freshBackupTs(BACKUP_BASE);
4290
4296
  const mapPath = join39(REPO_HOME, "path-map.json");
4291
- const map = existsSync33(mapPath) ? readPathMap(mapPath) : { projects: {} };
4297
+ const map = existsSync32(mapPath) ? readPathMap(mapPath) : { projects: {} };
4292
4298
  const result = computePreview(ts, map);
4293
4299
  emitSummary("diff", result.unmapped);
4294
4300
  } catch (err) {
@@ -4303,7 +4309,7 @@ function cmdDiff() {
4303
4309
 
4304
4310
  // src/init.ts
4305
4311
  init_config();
4306
- import { existsSync as existsSync35, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
4312
+ import { existsSync as existsSync34, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
4307
4313
  import { join as join41 } from "node:path";
4308
4314
 
4309
4315
  // src/init.gh-onboard.ts
@@ -4385,16 +4391,16 @@ init_config();
4385
4391
  init_utils();
4386
4392
  init_utils_fs();
4387
4393
  init_utils_json();
4388
- import { copyFileSync as copyFileSync2, cpSync as cpSync6, existsSync as existsSync34, rmSync as rmSync12, statSync as statSync9 } from "node:fs";
4394
+ import { copyFileSync as copyFileSync2, cpSync as cpSync6, existsSync as existsSync33, rmSync as rmSync12, statSync as statSync9 } from "node:fs";
4389
4395
  import { join as join40 } from "node:path";
4390
4396
  function snapshotIntoShared(map) {
4391
4397
  for (const name of allSharedLinks(map)) {
4392
4398
  const src = join40(CLAUDE_HOME, name);
4393
- if (!existsSync34(src)) continue;
4399
+ if (!existsSync33(src)) continue;
4394
4400
  const dst = join40(REPO_HOME, "shared", name);
4395
4401
  if (statSync9(src).isDirectory()) {
4396
4402
  const gk = join40(dst, ".gitkeep");
4397
- if (existsSync34(gk)) rmSync12(gk);
4403
+ if (existsSync33(gk)) rmSync12(gk);
4398
4404
  cpSync6(src, dst, { recursive: true, force: false, errorOnExist: true });
4399
4405
  } else {
4400
4406
  copyFileSync2(src, dst);
@@ -4402,7 +4408,7 @@ function snapshotIntoShared(map) {
4402
4408
  log(`snapshotted shared/${name} from ${src}`);
4403
4409
  }
4404
4410
  const userSettings = join40(CLAUDE_HOME, "settings.json");
4405
- if (existsSync34(userSettings)) {
4411
+ if (existsSync33(userSettings)) {
4406
4412
  let parsed;
4407
4413
  try {
4408
4414
  parsed = readJson(userSettings);
@@ -4429,7 +4435,7 @@ function preflightConflict(repoHome) {
4429
4435
  join41(repoHome, "shared")
4430
4436
  ];
4431
4437
  for (const c of candidates) {
4432
- if (existsSync35(c)) return c;
4438
+ if (existsSync34(c)) return c;
4433
4439
  }
4434
4440
  return null;
4435
4441
  }
@@ -4448,7 +4454,7 @@ function cmdInit(opts = {}) {
4448
4454
  mkdirSync10(join41(REPO_HOME, "shared", name), { recursive: true });
4449
4455
  }
4450
4456
  const userClaudeMd = join41(CLAUDE_HOME, "CLAUDE.md");
4451
- if (!snapshot || !existsSync35(userClaudeMd)) {
4457
+ if (!snapshot || !existsSync34(userClaudeMd)) {
4452
4458
  writeFileSync6(join41(REPO_HOME, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
4453
4459
  log("created shared/CLAUDE.md");
4454
4460
  }
@@ -4722,7 +4728,7 @@ function parsePushArgs(argv) {
4722
4728
  // package.json
4723
4729
  var package_default = {
4724
4730
  name: "claude-nomad",
4725
- version: "0.38.0",
4731
+ version: "0.38.1",
4726
4732
  type: "module",
4727
4733
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
4728
4734
  keywords: [
@@ -4912,7 +4918,7 @@ var DEFAULT_HELP = [
4912
4918
  init_config();
4913
4919
  init_utils();
4914
4920
  init_utils_json();
4915
- import { existsSync as existsSync36, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "node:fs";
4921
+ import { existsSync as existsSync35, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "node:fs";
4916
4922
  import { join as join42 } from "node:path";
4917
4923
  function resumeCmd(sessionId) {
4918
4924
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId) || sessionId.length > 128) {
@@ -4920,7 +4926,7 @@ function resumeCmd(sessionId) {
4920
4926
  process.exit(1);
4921
4927
  }
4922
4928
  const projectsRoot = join42(CLAUDE_HOME, "projects");
4923
- if (!existsSync36(projectsRoot)) {
4929
+ if (!existsSync35(projectsRoot)) {
4924
4930
  fail(`${projectsRoot} does not exist`);
4925
4931
  process.exit(1);
4926
4932
  }
@@ -4935,7 +4941,7 @@ function resumeCmd(sessionId) {
4935
4941
  process.exit(1);
4936
4942
  }
4937
4943
  const mapPath = join42(REPO_HOME, "path-map.json");
4938
- if (!existsSync36(mapPath)) {
4944
+ if (!existsSync35(mapPath)) {
4939
4945
  fail("path-map.json missing");
4940
4946
  process.exit(1);
4941
4947
  }
@@ -4959,7 +4965,7 @@ function resumeCmd(sessionId) {
4959
4965
  function findTranscriptPath(projectsRoot, sessionId) {
4960
4966
  for (const dir of readdirSync11(projectsRoot)) {
4961
4967
  const candidate = join42(projectsRoot, dir, `${sessionId}.jsonl`);
4962
- if (existsSync36(candidate)) return candidate;
4968
+ if (existsSync35(candidate)) return candidate;
4963
4969
  }
4964
4970
  return null;
4965
4971
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nomad",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "type": "module",
5
5
  "description": "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
6
6
  "keywords": [