claude-nomad 0.62.0 → 0.62.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.62.2](https://github.com/funkadelic/claude-nomad/compare/v0.62.1...v0.62.2) (2026-07-21)
4
+
5
+
6
+ ### Fixed
7
+
8
+ * **push:** close the interactive-push secret-gate fail-open ([#446](https://github.com/funkadelic/claude-nomad/issues/446)) ([5de8975](https://github.com/funkadelic/claude-nomad/commit/5de8975f83f5e99711041ef6025fe69933b1ab15))
9
+
10
+ ## [0.62.1](https://github.com/funkadelic/claude-nomad/compare/v0.62.0...v0.62.1) (2026-07-20)
11
+
12
+
13
+ ### Changed
14
+
15
+ * **coderabbit:** skip Snyk security-bump PRs ([#436](https://github.com/funkadelic/claude-nomad/issues/436)) ([10ded7c](https://github.com/funkadelic/claude-nomad/commit/10ded7cb5657b1180f8d33b1fbf73c3000fea6c3))
16
+ * **deps:** refresh lockfile for brace-expansion and fast-uri patches ([#445](https://github.com/funkadelic/claude-nomad/issues/445)) ([d4ea973](https://github.com/funkadelic/claude-nomad/commit/d4ea9739a450c71763a98769f48a7deefb38eca5))
17
+ * drop 3 dead exports flagged by knip ([#437](https://github.com/funkadelic/claude-nomad/issues/437)) ([51750d8](https://github.com/funkadelic/claude-nomad/commit/51750d8801f96b4bca8137ac863c851d63f7c074))
18
+ * **redact:** extract shared live-session guard ([#438](https://github.com/funkadelic/claude-nomad/issues/438)) ([59d8208](https://github.com/funkadelic/claude-nomad/commit/59d82085aaf59a53d8341de6850240fdce4aa7ea))
19
+
20
+
21
+ ### Dependencies
22
+
23
+ * bump actions/setup-node from 6.4.0 to 7.0.0 ([#441](https://github.com/funkadelic/claude-nomad/issues/441)) ([f24a847](https://github.com/funkadelic/claude-nomad/commit/f24a847476e6ec63c4e85715c2ebfc42cce138c3))
24
+ * bump astro from 7.0.7 to 7.1.3 in /docs-site ([#444](https://github.com/funkadelic/claude-nomad/issues/444)) ([01d56b7](https://github.com/funkadelic/claude-nomad/commit/01d56b7f20e1ea71f1dd64b7076411abc4fe9c02))
25
+ * bump SonarSource/sonarqube-scan-action from 8.2.0 to 8.2.1 ([#443](https://github.com/funkadelic/claude-nomad/issues/443)) ([2928f0f](https://github.com/funkadelic/claude-nomad/commit/2928f0f87e40147a17b068b0053486fee6cbd6e6))
26
+ * bump the codeql-action group with 2 updates ([#440](https://github.com/funkadelic/claude-nomad/issues/440)) ([8d30319](https://github.com/funkadelic/claude-nomad/commit/8d303191e692128c5fdc9dfaab7ff1f16eb0780d))
27
+ * bump the dev-dependencies group with 2 updates ([#442](https://github.com/funkadelic/claude-nomad/issues/442)) ([22427db](https://github.com/funkadelic/claude-nomad/commit/22427dbbe4fb3f455a6ec24f0d4105dee904ee17))
28
+
3
29
  ## [0.62.0](https://github.com/funkadelic/claude-nomad/compare/v0.61.0...v0.62.0) (2026-07-18)
4
30
 
5
31
 
package/dist/nomad.mjs CHANGED
@@ -4895,12 +4895,12 @@ import { isAbsolute as isAbsolute2, resolve as resolve3, sep as sep7 } from "nod
4895
4895
  // src/commands.push.recovery.redact.ts
4896
4896
  init_config();
4897
4897
  init_config_sharedDirs_guard();
4898
- import { cpSync as cpSync8, existsSync as existsSync32, mkdirSync as mkdirSync10, statSync as statSync8 } from "node:fs";
4898
+ import { cpSync as cpSync8, existsSync as existsSync32, mkdirSync as mkdirSync10 } from "node:fs";
4899
4899
  import { dirname as dirname10, join as join39, sep as sep5 } from "node:path";
4900
4900
 
4901
4901
  // src/commands.redact.ts
4902
4902
  init_config();
4903
- import { existsSync as existsSync30, statSync as statSync7 } from "node:fs";
4903
+ import { existsSync as existsSync30 } from "node:fs";
4904
4904
  import { dirname as dirname9, join as join37 } from "node:path";
4905
4905
 
4906
4906
  // src/commands.redact.subtree.ts
@@ -4936,6 +4936,10 @@ function newestSubtreeMtimeMs(mainPath, subtreeFiles, statMtime = (p) => statSyn
4936
4936
  }
4937
4937
  return newest;
4938
4938
  }
4939
+ function isSubtreeActive(mainPath, subtreeFiles, now) {
4940
+ const subtreeMtime = newestSubtreeMtimeMs(mainPath, subtreeFiles, (p) => statSync6(p).mtimeMs);
4941
+ return isRecentlyModified(subtreeMtime, now);
4942
+ }
4939
4943
  function applySubtreeRedactions(mainPath, mainFindings, subtreeFiles, rule, ts, scan, dryRun) {
4940
4944
  const dirty = [];
4941
4945
  if (mainFindings.length > 0) dirty.push({ path: mainPath, findings: mainFindings });
@@ -5059,8 +5063,7 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
5059
5063
  }
5060
5064
  const sessionDir = join37(dirname9(localPath), id);
5061
5065
  const subtreeFiles = listSubtreeFiles(sessionDir);
5062
- const subtreeMtime = newestSubtreeMtimeMs(localPath, subtreeFiles, (p) => statSync7(p).mtimeMs);
5063
- if (isRecentlyModified(subtreeMtime, nowMs())) {
5066
+ if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
5064
5067
  log(
5065
5068
  `session ${id} was modified recently and may be active.
5066
5069
  Refusing to rewrite a potentially live transcript.
@@ -5260,8 +5263,7 @@ function preflightRedactable(f, map, nowMs) {
5260
5263
  if (localPath === null) return `session ${sid}: local transcript not found`;
5261
5264
  const sessionDir = join39(dirname10(localPath), sid);
5262
5265
  const subtreeFiles = listSubtreeFiles(sessionDir);
5263
- const subtreeMtime = newestSubtreeMtimeMs(localPath, subtreeFiles, (p) => statSync8(p).mtimeMs);
5264
- if (isRecentlyModified(subtreeMtime, nowMs())) {
5266
+ if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
5265
5267
  return `session ${sid}: looks active (modified within the last 5 minutes)`;
5266
5268
  }
5267
5269
  if (resolveStagedDir(localPath, map, claudeHome(), repoHome()) === null) {
@@ -5290,8 +5292,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
5290
5292
  }
5291
5293
  const sessionDir = join39(dirname10(localPath), sid);
5292
5294
  const subtreeFiles = listSubtreeFiles(sessionDir);
5293
- const subtreeMtime = newestSubtreeMtimeMs(localPath, subtreeFiles, (p) => statSync8(p).mtimeMs);
5294
- if (isRecentlyModified(subtreeMtime, nowMs())) {
5295
+ if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
5295
5296
  return refuse(
5296
5297
  `session ${sid} looks active (modified within the last 5 minutes); refusing to redact, no changes made.
5297
5298
  End the session and choose Redact again, or choose Drop session (holds this session back from the push, local copy kept) or Skip.`
@@ -5354,7 +5355,7 @@ import {
5354
5355
  mkdirSync as mkdirSync12,
5355
5356
  readFileSync as readFileSync16,
5356
5357
  realpathSync as realpathSync4,
5357
- statSync as statSync9,
5358
+ statSync as statSync7,
5358
5359
  writeFileSync as writeFileSync8
5359
5360
  } from "node:fs";
5360
5361
  import { dirname as dirname11, join as join42, sep as sep6 } from "node:path";
@@ -5435,7 +5436,7 @@ function resolveSkillLocalPath(name, relPath) {
5435
5436
  const realLocal = realpathSync4(localPath);
5436
5437
  const realRoot = realpathSync4(skillsRoot);
5437
5438
  if (!realLocal.startsWith(realRoot + sep6)) return null;
5438
- if (!statSync9(realLocal).isFile()) return null;
5439
+ if (!statSync7(realLocal).isFile()) return null;
5439
5440
  } catch {
5440
5441
  return null;
5441
5442
  }
@@ -5725,6 +5726,9 @@ function allowThenRescan(append, scanVerdict, repoHome2) {
5725
5726
  throw err;
5726
5727
  }
5727
5728
  }
5729
+ function leakBlockedFatal(recovery) {
5730
+ return new NomadFatal(recovery ?? "gitleaks detected secrets", { code: EXIT.LEAK_BLOCKED });
5731
+ }
5728
5732
  function makeRealPrompt() {
5729
5733
  return async (prompt) => {
5730
5734
  const rl = createInterface2({
@@ -5771,9 +5775,10 @@ async function resolveLeakFindings(verdict, ts, map, deps = {}) {
5771
5775
  );
5772
5776
  }
5773
5777
  if (!isTTYCheck()) {
5774
- throw new NomadFatal(current.recovery ?? "gitleaks detected secrets", {
5775
- code: EXIT.LEAK_BLOCKED
5776
- });
5778
+ throw leakBlockedFatal(current.recovery);
5779
+ }
5780
+ if (current.leak && current.findings.length === 0) {
5781
+ throw leakBlockedFatal(current.recovery);
5777
5782
  }
5778
5783
  const prompt = makePromptFn();
5779
5784
  printLegend();
@@ -5788,6 +5793,7 @@ async function resolveLeakFindings(verdict, ts, map, deps = {}) {
5788
5793
  gitOrFatal(["add", "-A"], "git add", repo);
5789
5794
  current = scanVerdict(repo);
5790
5795
  }
5796
+ if (current.leak) throw leakBlockedFatal(current.recovery);
5791
5797
  return current;
5792
5798
  }
5793
5799
 
@@ -6223,7 +6229,7 @@ function parseDoctorArgs(args) {
6223
6229
  // src/commands.drop-session.ts
6224
6230
  init_config();
6225
6231
  import { execFileSync as execFileSync20 } from "node:child_process";
6226
- import { existsSync as existsSync38, readdirSync as readdirSync15, statSync as statSync10 } from "node:fs";
6232
+ import { existsSync as existsSync38, readdirSync as readdirSync15, statSync as statSync8 } from "node:fs";
6227
6233
  import { join as join47, relative as relative6 } from "node:path";
6228
6234
 
6229
6235
  // src/commands.drop-session.git.ts
@@ -6343,7 +6349,7 @@ function collectMatches(repoProjects, id, repo) {
6343
6349
  matches.push(relative6(repo, candidate));
6344
6350
  }
6345
6351
  const dir = join47(repoProjects, logical, id);
6346
- if (existsSync38(dir) && statSync10(dir).isDirectory()) {
6352
+ if (existsSync38(dir) && statSync8(dir).isDirectory()) {
6347
6353
  const dirRel = relative6(repo, dir);
6348
6354
  const staged = expandStagedDir(dirRel, repo);
6349
6355
  if (staged.length > 0) matches.push(...staged);
@@ -6487,7 +6493,7 @@ init_config();
6487
6493
 
6488
6494
  // src/extras-sync.ts
6489
6495
  init_config();
6490
- import { existsSync as existsSync40, statSync as statSync11 } from "node:fs";
6496
+ import { existsSync as existsSync40, statSync as statSync9 } from "node:fs";
6491
6497
  import { join as join50 } from "node:path";
6492
6498
  init_utils();
6493
6499
  init_utils_json();
@@ -6799,7 +6805,7 @@ function divergenceCheckExtras(ts, prePostHeads) {
6799
6805
  divergenceWarnLine({
6800
6806
  dirname: dirname13,
6801
6807
  logical,
6802
- isDir: statSync11(local).isDirectory(),
6808
+ isDir: statSync9(local).isDirectory(),
6803
6809
  count: modified.length,
6804
6810
  projectBackupRoot
6805
6811
  })
@@ -7466,7 +7472,7 @@ import { join as join57 } from "node:path";
7466
7472
 
7467
7473
  // src/commands.push.selection.ts
7468
7474
  init_config();
7469
- import { existsSync as existsSync43, statSync as statSync12 } from "node:fs";
7475
+ import { existsSync as existsSync43, statSync as statSync10 } from "node:fs";
7470
7476
  import { join as join53 } from "node:path";
7471
7477
  init_utils_json();
7472
7478
  function buildCurrentMap(map) {
@@ -7479,7 +7485,7 @@ function buildCurrentMap(map) {
7479
7485
  const localDir = join53(claude, "projects", encodePath(localPath));
7480
7486
  if (!existsSync43(localDir)) continue;
7481
7487
  for (const f of enumerateSourceFiles(localDir)) {
7482
- const st = statSync12(f);
7488
+ const st = statSync10(f);
7483
7489
  current[f] = { size: st.size, mtime: st.mtimeMs };
7484
7490
  }
7485
7491
  }
@@ -7883,6 +7889,7 @@ async function commitAndPush(st, ts, map, resolution, repo, newManifest, render)
7883
7889
  if (!render) log("push (leak recovery)");
7884
7890
  renderPushTree(st, verdict);
7885
7891
  verdict = await resolveLeakFindings(verdict, ts, map, resolution);
7892
+ if (verdict.leak) throw leakBlockedFatal(verdict.recovery);
7886
7893
  }
7887
7894
  gitOrFatal(["commit", "-m", `chore: sync from ${HOST}`], "git commit", repo);
7888
7895
  withSpinner("Pushing", () => gitOrFatal(["push"], "git push", repo));
@@ -8251,7 +8258,7 @@ init_config();
8251
8258
 
8252
8259
  // src/crash-report.write.ts
8253
8260
  init_config();
8254
- import { mkdirSync as mkdirSync16, readdirSync as readdirSync18, statSync as statSync13, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
8261
+ import { mkdirSync as mkdirSync16, readdirSync as readdirSync18, statSync as statSync11, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
8255
8262
  import { join as join60 } from "node:path";
8256
8263
 
8257
8264
  // src/crash-report.ts
@@ -8364,7 +8371,7 @@ function listCrashFiles(dir = crashDir()) {
8364
8371
  try {
8365
8372
  return readdirSync18(dir).flatMap((name) => {
8366
8373
  try {
8367
- return [{ name, mtimeMs: statSync13(join60(dir, name)).mtimeMs }];
8374
+ return [{ name, mtimeMs: statSync11(join60(dir, name)).mtimeMs }];
8368
8375
  } catch {
8369
8376
  return [];
8370
8377
  }
@@ -8525,7 +8532,7 @@ init_config();
8525
8532
  init_utils();
8526
8533
  init_utils_fs();
8527
8534
  init_utils_json();
8528
- import { copyFileSync as copyFileSync2, cpSync as cpSync10, existsSync as existsSync49, rmSync as rmSync19, statSync as statSync14 } from "node:fs";
8535
+ import { copyFileSync as copyFileSync2, cpSync as cpSync10, existsSync as existsSync49, rmSync as rmSync19, statSync as statSync12 } from "node:fs";
8529
8536
  import { join as join62 } from "node:path";
8530
8537
  function snapshotIntoShared(map) {
8531
8538
  const repo = repoHome();
@@ -8534,7 +8541,7 @@ function snapshotIntoShared(map) {
8534
8541
  const src = join62(claude, name);
8535
8542
  if (!existsSync49(src)) continue;
8536
8543
  const dst = join62(repo, "shared", name);
8537
- if (statSync14(src).isDirectory()) {
8544
+ if (statSync12(src).isDirectory()) {
8538
8545
  const gk = join62(dst, ".gitkeep");
8539
8546
  if (existsSync49(gk)) rmSync19(gk);
8540
8547
  cpSync10(src, dst, { recursive: true, force: false, errorOnExist: true });
@@ -8676,13 +8683,13 @@ function maybeDisableRepoActions(repoHome2, run) {
8676
8683
  // src/init.prompt.ts
8677
8684
  init_config();
8678
8685
  init_utils();
8679
- import { existsSync as existsSync51, readdirSync as readdirSync19, statSync as statSync15 } from "node:fs";
8686
+ import { existsSync as existsSync51, readdirSync as readdirSync19, statSync as statSync13 } from "node:fs";
8680
8687
  import { join as join64 } from "node:path";
8681
8688
  import { createInterface as createInterface3 } from "node:readline/promises";
8682
8689
  function nonEmptyExists(path) {
8683
8690
  if (!existsSync51(path)) return false;
8684
8691
  try {
8685
- if (statSync15(path).isDirectory()) return readdirSync19(path).length > 0;
8692
+ if (statSync13(path).isDirectory()) return readdirSync19(path).length > 0;
8686
8693
  return true;
8687
8694
  } catch {
8688
8695
  return false;
@@ -8997,7 +9004,7 @@ function parseSyncArgs(argv) {
8997
9004
  // package.json
8998
9005
  var package_default = {
8999
9006
  name: "claude-nomad",
9000
- version: "0.62.0",
9007
+ version: "0.62.2",
9001
9008
  type: "module",
9002
9009
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
9003
9010
  keywords: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nomad",
3
- "version": "0.62.0",
3
+ "version": "0.62.2",
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": [