claude-nomad 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/nomad.mjs +252 -244
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.39.0](https://github.com/funkadelic/claude-nomad/compare/v0.38.1...v0.39.0) (2026-06-02)
4
+
5
+
6
+ ### Added
7
+
8
+ * **doctor:** group version checks into Nomad + Dependency sections ([#228](https://github.com/funkadelic/claude-nomad/issues/228)) ([08e8bf7](https://github.com/funkadelic/claude-nomad/commit/08e8bf79a730f1e7f025a1c2ad9dd406f586b05e))
9
+
10
+
11
+ ### Documentation
12
+
13
+ * **how-it-works:** render repo-layout trees with FileTree ([#229](https://github.com/funkadelic/claude-nomad/issues/229)) ([b52de15](https://github.com/funkadelic/claude-nomad/commit/b52de152416ac5dabb650a1970b53a3b45262396))
14
+
15
+ ## [0.38.1](https://github.com/funkadelic/claude-nomad/compare/v0.38.0...v0.38.1) (2026-06-02)
16
+
17
+
18
+ ### Fixed
19
+
20
+ * **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))
21
+
22
+
23
+ ### Changed
24
+
25
+ * adopt fallow analyzer config ([#227](https://github.com/funkadelic/claude-nomad/issues/227)) ([ebf7ca0](https://github.com/funkadelic/claude-nomad/commit/ebf7ca0aa05510fa9edde5f408e951b7bfec05ab))
26
+ * 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))
27
+ * **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))
28
+
29
+
30
+ ### Documentation
31
+
32
+ * 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))
33
+
3
34
  ## [0.38.0](https://github.com/funkadelic/claude-nomad/compare/v0.37.0...v0.38.0) (2026-06-02)
4
35
 
5
36
 
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);
@@ -2336,7 +2342,7 @@ init_color();
2336
2342
  import { execFileSync as execFileSync8 } from "node:child_process";
2337
2343
  var VERSION_TOKEN = /(\d{1,9}\.\d{1,9}\.\d{1,9})/;
2338
2344
  var PROBE_TIMEOUT_MS = 3e3;
2339
- var FETCHER_LABEL = "HTTP fetcher (curl or wget)";
2345
+ var FETCHER_BASE = "HTTP fetcher";
2340
2346
  function parseFirstVersion(line) {
2341
2347
  const m = VERSION_TOKEN.exec(line);
2342
2348
  return m ? m[1] : null;
@@ -2360,13 +2366,13 @@ function reportFetcherRow(section2, run) {
2360
2366
  const curl = probeOptionalDep("curl", run);
2361
2367
  const wget = probeOptionalDep("wget", run);
2362
2368
  if (curl.status === "present") {
2363
- addItem(section2, `${green(okGlyph)} ${FETCHER_LABEL}: ${curl.version ?? "present"}`);
2369
+ addItem(section2, `${green(okGlyph)} ${FETCHER_BASE}: curl ${curl.version ?? "(present)"}`);
2364
2370
  } else if (wget.status === "present") {
2365
- addItem(section2, `${green(okGlyph)} ${FETCHER_LABEL}: ${wget.version ?? "present"}`);
2371
+ addItem(section2, `${green(okGlyph)} ${FETCHER_BASE}: wget ${wget.version ?? "(present)"}`);
2366
2372
  } else {
2367
2373
  addItem(
2368
2374
  section2,
2369
- `${yellow(warnGlyph)} ${FETCHER_LABEL}: not installed (optional; needed for release-version staleness check + nomad doctor --check-schema)`
2375
+ `${yellow(warnGlyph)} ${FETCHER_BASE} (curl or wget): not installed (optional; needed for release-version staleness check + nomad doctor --check-schema)`
2370
2376
  );
2371
2377
  }
2372
2378
  }
@@ -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");
@@ -2507,18 +2513,20 @@ function cmdDoctor(opts = {}) {
2507
2513
  reportRemote(repository);
2508
2514
  reportRebaseClean(repository);
2509
2515
  reportActionsDrift(repository);
2510
- const version = section("Version Checks");
2511
- reportVersionCheck(version);
2512
- reportNodeEngineCheck(version);
2513
- reportGitleaksVersionCheck(version);
2514
- reportOptionalDeps(version);
2515
- reportBackupsCheck(version);
2516
+ const nomadVersion = section("Nomad Version");
2517
+ reportVersionCheck(nomadVersion);
2518
+ reportBackupsCheck(nomadVersion);
2519
+ const depVersions = section("Dependency Versions");
2520
+ reportNodeEngineCheck(depVersions);
2521
+ reportGitleaksVersionCheck(depVersions);
2522
+ reportOptionalDeps(depVersions);
2516
2523
  const sharedScan = section("Shared scan");
2517
2524
  if (opts.checkShared === true) reportCheckShared(sharedScan, gitleaksReady);
2518
2525
  const schemaScan = section("Schema scan");
2519
2526
  if (opts.checkSchema === true) reportCheckSchema(schemaScan);
2520
2527
  renderDoctor([
2521
- version,
2528
+ nomadVersion,
2529
+ depVersions,
2522
2530
  host,
2523
2531
  links,
2524
2532
  hooksScan,
@@ -2534,7 +2542,7 @@ function cmdDoctor(opts = {}) {
2534
2542
  // src/commands.drop-session.ts
2535
2543
  init_config();
2536
2544
  import { execFileSync as execFileSync12 } from "node:child_process";
2537
- import { existsSync as existsSync21, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
2545
+ import { existsSync as existsSync20, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
2538
2546
  import { join as join25, relative as relative4 } from "node:path";
2539
2547
 
2540
2548
  // src/commands.drop-session.git.ts
@@ -2578,7 +2586,7 @@ function isInIndex(rel) {
2578
2586
  init_config();
2579
2587
  init_utils();
2580
2588
  init_utils_json();
2581
- import { existsSync as existsSync20 } from "node:fs";
2589
+ import { existsSync as existsSync19 } from "node:fs";
2582
2590
  import { join as join23 } from "node:path";
2583
2591
  var SHARED_PROJECT_LOGICAL = /^shared\/projects\/([^/]+)\//;
2584
2592
  function reportScrubHint(id, matches) {
@@ -2596,7 +2604,7 @@ function reportScrubHint(id, matches) {
2596
2604
  function resolveLiveTranscript(id, matches) {
2597
2605
  try {
2598
2606
  const mapPath = join23(REPO_HOME, "path-map.json");
2599
- if (!existsSync20(mapPath)) return null;
2607
+ if (!existsSync19(mapPath)) return null;
2600
2608
  const projects = readJson(mapPath).projects;
2601
2609
  for (const rel of matches) {
2602
2610
  const logical = SHARED_PROJECT_LOGICAL.exec(rel)?.[1];
@@ -2604,7 +2612,7 @@ function resolveLiveTranscript(id, matches) {
2604
2612
  const abs = projects[logical]?.[HOST];
2605
2613
  if (abs === void 0) continue;
2606
2614
  const live = join23(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
2607
- if (existsSync20(live)) return live;
2615
+ if (existsSync19(live)) return live;
2608
2616
  }
2609
2617
  return null;
2610
2618
  } catch {
@@ -2730,12 +2738,12 @@ function cmdDropSession(id) {
2730
2738
  fail(`invalid session id: ${id}`);
2731
2739
  process.exit(1);
2732
2740
  }
2733
- if (!existsSync21(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2741
+ if (!existsSync20(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2734
2742
  const handle = acquireLock("drop-session");
2735
2743
  if (handle === null) process.exit(0);
2736
2744
  try {
2737
2745
  const repoProjects = join25(REPO_HOME, "shared", "projects");
2738
- if (!existsSync21(repoProjects)) {
2746
+ if (!existsSync20(repoProjects)) {
2739
2747
  throw new NomadFatal(`no staged session matches ${id}`);
2740
2748
  }
2741
2749
  const matches = collectMatches(repoProjects, id);
@@ -2758,11 +2766,11 @@ function collectMatches(repoProjects, id) {
2758
2766
  const matches = [];
2759
2767
  for (const logical of readdirSync8(repoProjects)) {
2760
2768
  const candidate = join25(repoProjects, logical, `${id}.jsonl`);
2761
- if (existsSync21(candidate)) {
2769
+ if (existsSync20(candidate)) {
2762
2770
  matches.push(relative4(REPO_HOME, candidate));
2763
2771
  }
2764
2772
  const dir = join25(repoProjects, logical, id);
2765
- if (existsSync21(dir) && statSync5(dir).isDirectory()) {
2773
+ if (existsSync20(dir) && statSync5(dir).isDirectory()) {
2766
2774
  const dirRel = relative4(REPO_HOME, dir);
2767
2775
  const staged = expandStagedDir(dirRel);
2768
2776
  if (staged.length > 0) matches.push(...staged);
@@ -2798,15 +2806,15 @@ function unstageOne(rel) {
2798
2806
 
2799
2807
  // src/commands.redact.ts
2800
2808
  init_config();
2801
- import { existsSync as existsSync23, statSync as statSync7 } from "node:fs";
2809
+ import { existsSync as existsSync22, statSync as statSync7 } from "node:fs";
2802
2810
  import { dirname as dirname4, join as join27 } from "node:path";
2803
2811
 
2804
2812
  // 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";
2813
+ import { existsSync as existsSync21, lstatSync as lstatSync6, readFileSync as readFileSync9, readdirSync as readdirSync9, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
2806
2814
  import { join as join26 } from "node:path";
2807
2815
  init_utils_fs();
2808
2816
  function collectFiles(dir, out) {
2809
- if (!existsSync22(dir)) return;
2817
+ if (!existsSync21(dir)) return;
2810
2818
  const st = lstatSync6(dir);
2811
2819
  if (!st.isDirectory()) return;
2812
2820
  for (const entry of readdirSync9(dir)) {
@@ -2861,13 +2869,13 @@ init_utils();
2861
2869
  function resolveLiveTranscript2(id) {
2862
2870
  try {
2863
2871
  const mapPath = join27(REPO_HOME, "path-map.json");
2864
- if (!existsSync23(mapPath)) return null;
2872
+ if (!existsSync22(mapPath)) return null;
2865
2873
  const projects = readJson(mapPath).projects;
2866
2874
  for (const hostMap of Object.values(projects)) {
2867
2875
  const abs = hostMap[HOST];
2868
2876
  if (abs === void 0) continue;
2869
2877
  const live = join27(CLAUDE_HOME, "projects", encodePath(abs), `${id}.jsonl`);
2870
- if (existsSync23(live)) return live;
2878
+ if (existsSync22(live)) return live;
2871
2879
  }
2872
2880
  return null;
2873
2881
  } catch {
@@ -2885,12 +2893,12 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
2885
2893
  fail(`invalid session id: ${id}`);
2886
2894
  process.exit(1);
2887
2895
  }
2888
- if (!existsSync23(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2896
+ if (!existsSync22(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
2889
2897
  const handle = acquireLock("redact");
2890
2898
  if (handle === null) process.exit(0);
2891
2899
  try {
2892
2900
  const localPath = resolveLiveTranscript2(id);
2893
- if (localPath === null || !existsSync23(localPath)) {
2901
+ if (localPath === null || !existsSync22(localPath)) {
2894
2902
  fail(`could not resolve local transcript for session ${id} on this host`);
2895
2903
  process.exitCode = 1;
2896
2904
  return;
@@ -2948,7 +2956,7 @@ ${lines}`);
2948
2956
  }
2949
2957
 
2950
2958
  // src/commands.pull.ts
2951
- import { existsSync as existsSync29, mkdirSync as mkdirSync7 } from "node:fs";
2959
+ import { existsSync as existsSync28, mkdirSync as mkdirSync7 } from "node:fs";
2952
2960
  import { join as join33 } from "node:path";
2953
2961
 
2954
2962
  // src/commands.push.sections.ts
@@ -3045,7 +3053,7 @@ init_config();
3045
3053
 
3046
3054
  // src/extras-sync.ts
3047
3055
  init_config();
3048
- import { existsSync as existsSync26 } from "node:fs";
3056
+ import { existsSync as existsSync25 } from "node:fs";
3049
3057
  import { join as join30 } from "node:path";
3050
3058
 
3051
3059
  // src/extras-sync.diff.ts
@@ -3073,7 +3081,7 @@ function listDivergingFiles(a, b) {
3073
3081
 
3074
3082
  // src/extras-sync.core.ts
3075
3083
  init_config();
3076
- import { cpSync as cpSync4, existsSync as existsSync24, rmSync as rmSync7 } from "node:fs";
3084
+ import { cpSync as cpSync4, existsSync as existsSync23, rmSync as rmSync7 } from "node:fs";
3077
3085
  import { join as join28 } from "node:path";
3078
3086
 
3079
3087
  // src/extras-sync.guards.ts
@@ -3099,7 +3107,7 @@ init_utils_json();
3099
3107
  function loadValidatedExtras(opts) {
3100
3108
  const mapPath = join28(REPO_HOME, "path-map.json");
3101
3109
  const repoExtras = join28(REPO_HOME, "shared", "extras");
3102
- if (!existsSync24(mapPath) || opts.requireRepoExtras === true && !existsSync24(repoExtras)) {
3110
+ if (!existsSync23(mapPath) || opts.requireRepoExtras === true && !existsSync23(repoExtras)) {
3103
3111
  if (opts.missingMsg !== void 0) log(opts.missingMsg);
3104
3112
  return null;
3105
3113
  }
@@ -3141,7 +3149,7 @@ init_utils_json();
3141
3149
 
3142
3150
  // src/extras-sync.remap.ts
3143
3151
  init_config();
3144
- import { existsSync as existsSync25, mkdirSync as mkdirSync6 } from "node:fs";
3152
+ import { existsSync as existsSync24, mkdirSync as mkdirSync6 } from "node:fs";
3145
3153
  import { join as join29 } from "node:path";
3146
3154
  init_utils_fs();
3147
3155
  function runExtrasOp(v, dryRun, paths, backup) {
@@ -3150,7 +3158,7 @@ function runExtrasOp(v, dryRun, paths, backup) {
3150
3158
  const would = [];
3151
3159
  for (const t of eachExtrasTarget(v, counts)) {
3152
3160
  const { src, dst } = paths(t);
3153
- if (!existsSync25(src)) continue;
3161
+ if (!existsSync24(src)) continue;
3154
3162
  const item = `${t.logical}/${t.dirname}`;
3155
3163
  if (dryRun) {
3156
3164
  would.push(item);
@@ -3210,7 +3218,7 @@ function divergenceCheckExtras(ts) {
3210
3218
  for (const { logical, localRoot, dirname: dirname6 } of eachExtrasTarget(v, counts)) {
3211
3219
  const local = join30(localRoot, dirname6);
3212
3220
  const repo = join30(REPO_HOME, "shared", "extras", logical, dirname6);
3213
- if (!existsSync26(local) || !existsSync26(repo)) continue;
3221
+ if (!existsSync25(local) || !existsSync25(repo)) continue;
3214
3222
  const diff = listDivergingFiles(local, repo);
3215
3223
  if (diff.length === 0) continue;
3216
3224
  const projectBackupRoot = join30(backupRoot, encodePath(localRoot));
@@ -3226,7 +3234,7 @@ init_config();
3226
3234
  init_utils();
3227
3235
  init_utils_fs();
3228
3236
  init_utils_json();
3229
- import { existsSync as existsSync27, lstatSync as lstatSync7, rmSync as rmSync8 } from "node:fs";
3237
+ import { existsSync as existsSync26, lstatSync as lstatSync7, rmSync as rmSync8 } from "node:fs";
3230
3238
  import { join as join31 } from "node:path";
3231
3239
  function applySharedLinks(ts, map, opts = {}) {
3232
3240
  const dryRun = opts.dryRun === true;
@@ -3234,9 +3242,9 @@ function applySharedLinks(ts, map, opts = {}) {
3234
3242
  for (const name of linkNames) {
3235
3243
  const linkPath = join31(CLAUDE_HOME, name);
3236
3244
  const target = join31(REPO_HOME, "shared", name);
3237
- if (!existsSync27(linkPath)) continue;
3245
+ if (!existsSync26(linkPath)) continue;
3238
3246
  if (lstatSync7(linkPath).isSymbolicLink()) continue;
3239
- if (!existsSync27(target)) continue;
3247
+ if (!existsSync26(target)) continue;
3240
3248
  if (dryRun) {
3241
3249
  log(`would auto-move non-symlink: ${linkPath} -> backup/${ts}/${name}`);
3242
3250
  continue;
@@ -3246,7 +3254,7 @@ function applySharedLinks(ts, map, opts = {}) {
3246
3254
  }
3247
3255
  for (const name of linkNames) {
3248
3256
  const target = join31(REPO_HOME, "shared", name);
3249
- if (!existsSync27(target)) continue;
3257
+ if (!existsSync26(target)) continue;
3250
3258
  if (dryRun) {
3251
3259
  log(`would create symlink: ${join31(CLAUDE_HOME, name)} -> ${target}`);
3252
3260
  continue;
@@ -3258,15 +3266,15 @@ function regenerateSettings(ts, opts = {}) {
3258
3266
  const dryRun = opts.dryRun === true;
3259
3267
  const basePath = join31(REPO_HOME, "shared", "settings.base.json");
3260
3268
  const hostPath = join31(REPO_HOME, "hosts", `${HOST}.json`);
3261
- if (!existsSync27(basePath)) {
3269
+ if (!existsSync26(basePath)) {
3262
3270
  die("repo not initialized; run 'nomad init' to scaffold");
3263
3271
  }
3264
3272
  const base = readJson(basePath);
3265
- const hasOverrides = existsSync27(hostPath);
3273
+ const hasOverrides = existsSync26(hostPath);
3266
3274
  const overrides = hasOverrides ? readJson(hostPath) : {};
3267
3275
  const merged = deepMerge(base, overrides);
3268
3276
  const settingsPath = join31(CLAUDE_HOME, "settings.json");
3269
- if (!hasOverrides && existsSync27(settingsPath)) {
3277
+ if (!hasOverrides && existsSync26(settingsPath)) {
3270
3278
  try {
3271
3279
  const existing = readJson(settingsPath);
3272
3280
  const baseKeys = new Set(Object.keys(base));
@@ -3292,7 +3300,7 @@ function regenerateSettings(ts, opts = {}) {
3292
3300
 
3293
3301
  // src/preview.ts
3294
3302
  init_config();
3295
- import { existsSync as existsSync28 } from "node:fs";
3303
+ import { existsSync as existsSync27 } from "node:fs";
3296
3304
  import { join as join32 } from "node:path";
3297
3305
 
3298
3306
  // node_modules/diff/libesm/diff/base.js
@@ -3579,7 +3587,7 @@ function diffJsonStrings(currentJsonText, newJsonText) {
3579
3587
  return lines.join("\n");
3580
3588
  }
3581
3589
  function readJsonOrNull(path) {
3582
- if (!existsSync28(path)) return null;
3590
+ if (!existsSync27(path)) return null;
3583
3591
  try {
3584
3592
  return readJson(path);
3585
3593
  } catch {
@@ -3593,12 +3601,12 @@ function previewSettings(basePath, hostPath, settingsPath) {
3593
3601
  return;
3594
3602
  }
3595
3603
  const hostOverrides = readJsonOrNull(hostPath);
3596
- if (hostOverrides === null && existsSync28(hostPath)) {
3604
+ if (hostOverrides === null && existsSync27(hostPath)) {
3597
3605
  log(`settings.json: malformed hosts/${HOST}.json; ignoring overrides`);
3598
3606
  }
3599
3607
  const merged = deepMerge(base, hostOverrides ?? {});
3600
3608
  const current = readJsonOrNull(settingsPath);
3601
- if (current === null && existsSync28(settingsPath)) {
3609
+ if (current === null && existsSync27(settingsPath)) {
3602
3610
  log("settings.json: malformed; skipping diff");
3603
3611
  return;
3604
3612
  }
@@ -3648,8 +3656,8 @@ function applyWetPull(ts, map) {
3648
3656
  }
3649
3657
  function cmdPull(opts = {}) {
3650
3658
  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"))) {
3659
+ if (!existsSync28(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
3660
+ if (!existsSync28(join33(REPO_HOME, "shared", "settings.base.json"))) {
3653
3661
  die("repo not initialized; run 'nomad init' to scaffold");
3654
3662
  }
3655
3663
  const handle = acquireLock("pull");
@@ -3669,7 +3677,7 @@ function cmdPull(opts = {}) {
3669
3677
  );
3670
3678
  gitOrFatal(["pull", "--rebase", "--autostash"], "git pull --rebase", REPO_HOME);
3671
3679
  const mapPath = join33(REPO_HOME, "path-map.json");
3672
- const map = existsSync29(mapPath) ? readPathMap(mapPath) : { projects: {} };
3680
+ const map = existsSync28(mapPath) ? readPathMap(mapPath) : { projects: {} };
3673
3681
  divergenceCheckExtras(ts);
3674
3682
  if (dryRun) {
3675
3683
  const previewResult = computePreview(ts, map);
@@ -3692,7 +3700,7 @@ function cmdPull(opts = {}) {
3692
3700
 
3693
3701
  // src/commands.push.ts
3694
3702
  init_config();
3695
- import { existsSync as existsSync32 } from "node:fs";
3703
+ import { existsSync as existsSync31 } from "node:fs";
3696
3704
  import { join as join38, relative as relative5 } from "node:path";
3697
3705
 
3698
3706
  // src/commands.push.allowlist.ts
@@ -3773,7 +3781,7 @@ import { createInterface } from "node:readline/promises";
3773
3781
  // src/commands.push.recovery.redact.ts
3774
3782
  init_config();
3775
3783
  init_config_sharedDirs_guard();
3776
- import { cpSync as cpSync5, existsSync as existsSync30, mkdirSync as mkdirSync8, statSync as statSync8 } from "node:fs";
3784
+ import { cpSync as cpSync5, existsSync as existsSync29, mkdirSync as mkdirSync8, statSync as statSync8 } from "node:fs";
3777
3785
  import { dirname as dirname5, join as join34, sep as sep2 } from "node:path";
3778
3786
  init_push_gitleaks_scan();
3779
3787
  init_utils_json();
@@ -3863,7 +3871,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
3863
3871
  }
3864
3872
  mkdirSync8(stagedProjectDir, { recursive: true });
3865
3873
  cpSync5(localPath, join34(stagedProjectDir, `${sid}.jsonl`), { force: true });
3866
- if (existsSync30(sessionDir)) {
3874
+ if (existsSync29(sessionDir)) {
3867
3875
  cpSync5(sessionDir, join34(stagedProjectDir, sid), { force: true, recursive: true });
3868
3876
  }
3869
3877
  return true;
@@ -4084,7 +4092,7 @@ init_color();
4084
4092
  init_config();
4085
4093
  init_config_sharedDirs_guard();
4086
4094
  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";
4095
+ import { copyFileSync, existsSync as existsSync30, mkdirSync as mkdirSync9, readdirSync as readdirSync10, rmSync as rmSync11 } from "node:fs";
4088
4096
  import { homedir as homedir5 } from "node:os";
4089
4097
  import { join as join37 } from "node:path";
4090
4098
  init_push_leak_verdict();
@@ -4102,7 +4110,7 @@ function stageSessions(tmpRoot, map) {
4102
4110
  reverse.set(encodePath(p), logical);
4103
4111
  }
4104
4112
  const localProjects = join37(CLAUDE_HOME, "projects");
4105
- if (!existsSync31(localProjects)) return 0;
4113
+ if (!existsSync30(localProjects)) return 0;
4106
4114
  let staged = 0;
4107
4115
  for (const dir of readdirSync10(localProjects)) {
4108
4116
  const logical = reverse.get(dir);
@@ -4124,7 +4132,7 @@ function stageExtras(tmpRoot, map) {
4124
4132
  for (const dirname6 of dirnames) {
4125
4133
  if (!whitelist.includes(dirname6)) continue;
4126
4134
  const src = join37(localRoot, dirname6);
4127
- if (!existsSync31(src)) continue;
4135
+ if (!existsSync30(src)) continue;
4128
4136
  const dst = join37(tmpRoot, "shared", "extras", logical, dirname6);
4129
4137
  copyExtras(src, dst);
4130
4138
  staged++;
@@ -4144,7 +4152,7 @@ function previewPushLeaks(map) {
4144
4152
  return { leak: false, verdictRow: NOTHING_TO_SCAN_ROW, recovery: null, findings: [] };
4145
4153
  }
4146
4154
  const ignoreFile = join37(REPO_HOME, ".gitleaksignore");
4147
- if (existsSync31(ignoreFile)) {
4155
+ if (existsSync30(ignoreFile)) {
4148
4156
  copyFileSync(ignoreFile, join37(tmpRoot, ".gitleaksignore"));
4149
4157
  }
4150
4158
  let findings;
@@ -4219,7 +4227,7 @@ async function cmdPush(opts = {}) {
4219
4227
  const allowAll = opts.allowAll === true;
4220
4228
  const allowRule = opts.allowRule;
4221
4229
  guardResolutionModeConflicts(dryRun, redactAll, allowAll, allowRule);
4222
- if (!existsSync32(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4230
+ if (!existsSync31(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4223
4231
  const handle = acquireLock("push");
4224
4232
  if (handle === null) process.exit(0);
4225
4233
  try {
@@ -4238,7 +4246,7 @@ async function cmdPush(opts = {}) {
4238
4246
  return;
4239
4247
  }
4240
4248
  const mapPath = join38(REPO_HOME, "path-map.json");
4241
- if (!existsSync32(mapPath)) {
4249
+ if (!existsSync31(mapPath)) {
4242
4250
  if (dryRun) return runDryRunPreview(st, null);
4243
4251
  die("path-map.json missing, cannot enforce push allow-list");
4244
4252
  }
@@ -4278,17 +4286,17 @@ init_config();
4278
4286
 
4279
4287
  // src/diff.ts
4280
4288
  init_config();
4281
- import { existsSync as existsSync33 } from "node:fs";
4289
+ import { existsSync as existsSync32 } from "node:fs";
4282
4290
  import { join as join39 } from "node:path";
4283
4291
  init_utils();
4284
4292
  init_utils_fs();
4285
4293
  init_utils_json();
4286
4294
  function cmdDiff() {
4287
4295
  try {
4288
- if (!existsSync33(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4296
+ if (!existsSync32(REPO_HOME)) die(`repo not cloned at ${REPO_HOME}`);
4289
4297
  const ts = freshBackupTs(BACKUP_BASE);
4290
4298
  const mapPath = join39(REPO_HOME, "path-map.json");
4291
- const map = existsSync33(mapPath) ? readPathMap(mapPath) : { projects: {} };
4299
+ const map = existsSync32(mapPath) ? readPathMap(mapPath) : { projects: {} };
4292
4300
  const result = computePreview(ts, map);
4293
4301
  emitSummary("diff", result.unmapped);
4294
4302
  } catch (err) {
@@ -4303,7 +4311,7 @@ function cmdDiff() {
4303
4311
 
4304
4312
  // src/init.ts
4305
4313
  init_config();
4306
- import { existsSync as existsSync35, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
4314
+ import { existsSync as existsSync34, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "node:fs";
4307
4315
  import { join as join41 } from "node:path";
4308
4316
 
4309
4317
  // src/init.gh-onboard.ts
@@ -4385,16 +4393,16 @@ init_config();
4385
4393
  init_utils();
4386
4394
  init_utils_fs();
4387
4395
  init_utils_json();
4388
- import { copyFileSync as copyFileSync2, cpSync as cpSync6, existsSync as existsSync34, rmSync as rmSync12, statSync as statSync9 } from "node:fs";
4396
+ import { copyFileSync as copyFileSync2, cpSync as cpSync6, existsSync as existsSync33, rmSync as rmSync12, statSync as statSync9 } from "node:fs";
4389
4397
  import { join as join40 } from "node:path";
4390
4398
  function snapshotIntoShared(map) {
4391
4399
  for (const name of allSharedLinks(map)) {
4392
4400
  const src = join40(CLAUDE_HOME, name);
4393
- if (!existsSync34(src)) continue;
4401
+ if (!existsSync33(src)) continue;
4394
4402
  const dst = join40(REPO_HOME, "shared", name);
4395
4403
  if (statSync9(src).isDirectory()) {
4396
4404
  const gk = join40(dst, ".gitkeep");
4397
- if (existsSync34(gk)) rmSync12(gk);
4405
+ if (existsSync33(gk)) rmSync12(gk);
4398
4406
  cpSync6(src, dst, { recursive: true, force: false, errorOnExist: true });
4399
4407
  } else {
4400
4408
  copyFileSync2(src, dst);
@@ -4402,7 +4410,7 @@ function snapshotIntoShared(map) {
4402
4410
  log(`snapshotted shared/${name} from ${src}`);
4403
4411
  }
4404
4412
  const userSettings = join40(CLAUDE_HOME, "settings.json");
4405
- if (existsSync34(userSettings)) {
4413
+ if (existsSync33(userSettings)) {
4406
4414
  let parsed;
4407
4415
  try {
4408
4416
  parsed = readJson(userSettings);
@@ -4429,7 +4437,7 @@ function preflightConflict(repoHome) {
4429
4437
  join41(repoHome, "shared")
4430
4438
  ];
4431
4439
  for (const c of candidates) {
4432
- if (existsSync35(c)) return c;
4440
+ if (existsSync34(c)) return c;
4433
4441
  }
4434
4442
  return null;
4435
4443
  }
@@ -4448,7 +4456,7 @@ function cmdInit(opts = {}) {
4448
4456
  mkdirSync10(join41(REPO_HOME, "shared", name), { recursive: true });
4449
4457
  }
4450
4458
  const userClaudeMd = join41(CLAUDE_HOME, "CLAUDE.md");
4451
- if (!snapshot || !existsSync35(userClaudeMd)) {
4459
+ if (!snapshot || !existsSync34(userClaudeMd)) {
4452
4460
  writeFileSync6(join41(REPO_HOME, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
4453
4461
  log("created shared/CLAUDE.md");
4454
4462
  }
@@ -4722,7 +4730,7 @@ function parsePushArgs(argv) {
4722
4730
  // package.json
4723
4731
  var package_default = {
4724
4732
  name: "claude-nomad",
4725
- version: "0.38.0",
4733
+ version: "0.39.0",
4726
4734
  type: "module",
4727
4735
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
4728
4736
  keywords: [
@@ -4912,7 +4920,7 @@ var DEFAULT_HELP = [
4912
4920
  init_config();
4913
4921
  init_utils();
4914
4922
  init_utils_json();
4915
- import { existsSync as existsSync36, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "node:fs";
4923
+ import { existsSync as existsSync35, readFileSync as readFileSync11, readdirSync as readdirSync11 } from "node:fs";
4916
4924
  import { join as join42 } from "node:path";
4917
4925
  function resumeCmd(sessionId) {
4918
4926
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId) || sessionId.length > 128) {
@@ -4920,7 +4928,7 @@ function resumeCmd(sessionId) {
4920
4928
  process.exit(1);
4921
4929
  }
4922
4930
  const projectsRoot = join42(CLAUDE_HOME, "projects");
4923
- if (!existsSync36(projectsRoot)) {
4931
+ if (!existsSync35(projectsRoot)) {
4924
4932
  fail(`${projectsRoot} does not exist`);
4925
4933
  process.exit(1);
4926
4934
  }
@@ -4935,7 +4943,7 @@ function resumeCmd(sessionId) {
4935
4943
  process.exit(1);
4936
4944
  }
4937
4945
  const mapPath = join42(REPO_HOME, "path-map.json");
4938
- if (!existsSync36(mapPath)) {
4946
+ if (!existsSync35(mapPath)) {
4939
4947
  fail("path-map.json missing");
4940
4948
  process.exit(1);
4941
4949
  }
@@ -4959,7 +4967,7 @@ function resumeCmd(sessionId) {
4959
4967
  function findTranscriptPath(projectsRoot, sessionId) {
4960
4968
  for (const dir of readdirSync11(projectsRoot)) {
4961
4969
  const candidate = join42(projectsRoot, dir, `${sessionId}.jsonl`);
4962
- if (existsSync36(candidate)) return candidate;
4970
+ if (existsSync35(candidate)) return candidate;
4963
4971
  }
4964
4972
  return null;
4965
4973
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nomad",
3
- "version": "0.38.0",
3
+ "version": "0.39.0",
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": [