claude-nomad 0.62.3 → 0.62.4
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 +19 -0
- package/dist/nomad.mjs +58 -51
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.62.4](https://github.com/funkadelic/claude-nomad/compare/v0.62.3...v0.62.4) (2026-07-21)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Fixed
|
|
7
|
+
|
|
8
|
+
* **sync:** compute the dry-run pull preview after the fetch ([#451](https://github.com/funkadelic/claude-nomad/issues/451)) ([8118625](https://github.com/funkadelic/claude-nomad/commit/81186258896081a7b2a2585f40eed67bd3e5c6b6))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
* **pull:** split commands.pull.recovery.ts on the force-remote seam ([#456](https://github.com/funkadelic/claude-nomad/issues/456)) ([1c1875b](https://github.com/funkadelic/claude-nomad/commit/1c1875b40e67512329e9a2d1215afa7667c29d1c))
|
|
14
|
+
* **push:** split redact-all batch from recovery actions ([#457](https://github.com/funkadelic/claude-nomad/issues/457)) ([b104472](https://github.com/funkadelic/claude-nomad/commit/b104472b87d3f847546ee938900bcaa4ea1abdd8))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Testing
|
|
18
|
+
|
|
19
|
+
* precompile the CLI once per vitest run ([#453](https://github.com/funkadelic/claude-nomad/issues/453)) ([e0b043b](https://github.com/funkadelic/claude-nomad/commit/e0b043b851ae9bd89da026199f70d723e213aed9))
|
|
20
|
+
* **pull:** reset process.exitCode in beforeEach as well as afterEach ([#450](https://github.com/funkadelic/claude-nomad/issues/450)) ([78943e7](https://github.com/funkadelic/claude-nomad/commit/78943e72a41d4a542a4d6528d995ae9f8a8452cc))
|
|
21
|
+
|
|
3
22
|
## [0.62.3](https://github.com/funkadelic/claude-nomad/compare/v0.62.2...v0.62.3) (2026-07-21)
|
|
4
23
|
|
|
5
24
|
|
package/dist/nomad.mjs
CHANGED
|
@@ -5668,6 +5668,10 @@ function dispatchActions(findings, actions, opts) {
|
|
|
5668
5668
|
dispatchOne(f, ctx);
|
|
5669
5669
|
}
|
|
5670
5670
|
}
|
|
5671
|
+
|
|
5672
|
+
// src/commands.push.recovery.redact-all.ts
|
|
5673
|
+
init_push_gitleaks_scan();
|
|
5674
|
+
init_utils();
|
|
5671
5675
|
function redactAllDedupeKey(f) {
|
|
5672
5676
|
const sid = sessionIdFromFinding(f);
|
|
5673
5677
|
if (sid !== null) return sid;
|
|
@@ -7238,7 +7242,7 @@ function buildSettingsSectionForPreview(result) {
|
|
|
7238
7242
|
function computePreview(ts, map, verb = "pull") {
|
|
7239
7243
|
const repo = repoHome();
|
|
7240
7244
|
const claude = claudeHome();
|
|
7241
|
-
console.log(`would pull on host=${HOST} (
|
|
7245
|
+
console.log(`would pull on host=${HOST} (preview; nothing applied)`);
|
|
7242
7246
|
console.log("");
|
|
7243
7247
|
const links = section("Symlinks");
|
|
7244
7248
|
applySharedLinks(ts, map, {
|
|
@@ -7286,10 +7290,11 @@ init_commands_pull_wedge();
|
|
|
7286
7290
|
|
|
7287
7291
|
// src/commands.pull.recovery.ts
|
|
7288
7292
|
init_config();
|
|
7289
|
-
init_commands_pull_wedge();
|
|
7290
|
-
init_exit_codes();
|
|
7291
7293
|
init_utils();
|
|
7292
7294
|
init_utils_fs();
|
|
7295
|
+
|
|
7296
|
+
// src/commands.pull.recovery.git.ts
|
|
7297
|
+
init_utils();
|
|
7293
7298
|
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
7294
7299
|
function gitCapture(args, cwd) {
|
|
7295
7300
|
return execFileSync21("git", args, {
|
|
@@ -7298,23 +7303,6 @@ function gitCapture(args, cwd) {
|
|
|
7298
7303
|
maxBuffer: 64 * 1024 * 1024
|
|
7299
7304
|
}).toString().trim();
|
|
7300
7305
|
}
|
|
7301
|
-
function isSyncedConfig(path) {
|
|
7302
|
-
return PUSH_ALLOWED_STATIC.some(
|
|
7303
|
-
(entry) => entry.endsWith("/") ? path.startsWith(entry) : path === entry
|
|
7304
|
-
);
|
|
7305
|
-
}
|
|
7306
|
-
function classifyTouched(touched) {
|
|
7307
|
-
const synced = [];
|
|
7308
|
-
const toolSource = [];
|
|
7309
|
-
for (const p of touched) {
|
|
7310
|
-
if (isSyncedConfig(p)) {
|
|
7311
|
-
synced.push(p);
|
|
7312
|
-
} else {
|
|
7313
|
-
toolSource.push(p);
|
|
7314
|
-
}
|
|
7315
|
-
}
|
|
7316
|
-
return { synced, toolSource };
|
|
7317
|
-
}
|
|
7318
7306
|
function parsePorcelainZ(raw) {
|
|
7319
7307
|
const tracked = [];
|
|
7320
7308
|
const untracked = [];
|
|
@@ -7343,6 +7331,25 @@ function parsePorcelainZ(raw) {
|
|
|
7343
7331
|
function parseDirtyPaths(repo, opts = {}) {
|
|
7344
7332
|
return parsePorcelainZ(gitStatusPorcelainZ(repo, opts));
|
|
7345
7333
|
}
|
|
7334
|
+
|
|
7335
|
+
// src/commands.pull.recovery.ts
|
|
7336
|
+
function isSyncedConfig(path) {
|
|
7337
|
+
return PUSH_ALLOWED_STATIC.some(
|
|
7338
|
+
(entry) => entry.endsWith("/") ? path.startsWith(entry) : path === entry
|
|
7339
|
+
);
|
|
7340
|
+
}
|
|
7341
|
+
function classifyTouched(touched) {
|
|
7342
|
+
const synced = [];
|
|
7343
|
+
const toolSource = [];
|
|
7344
|
+
for (const p of touched) {
|
|
7345
|
+
if (isSyncedConfig(p)) {
|
|
7346
|
+
synced.push(p);
|
|
7347
|
+
} else {
|
|
7348
|
+
toolSource.push(p);
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
return { synced, toolSource };
|
|
7352
|
+
}
|
|
7346
7353
|
function buildRecoverySummary(branchName, strandedLog, untracked) {
|
|
7347
7354
|
const strandedLines = strandedLog.split("\n").filter(Boolean).map((l) => ` ${l}`).join("\n");
|
|
7348
7355
|
const parts = [`parked stranded commits on ${branchName}`];
|
|
@@ -7367,26 +7374,6 @@ function freshStrandedBranch(repo) {
|
|
|
7367
7374
|
while (exists(`${base}-${n}`)) n++;
|
|
7368
7375
|
return `${base}-${n}`;
|
|
7369
7376
|
}
|
|
7370
|
-
function recoverUnmergedIndex(repo) {
|
|
7371
|
-
const conflicted = new Set(
|
|
7372
|
-
gitCapture(["diff", "--diff-filter=U", "--name-only", "-z"], repo).split("\0").filter(Boolean)
|
|
7373
|
-
);
|
|
7374
|
-
gitOrFatal(["reset", "--mixed", "HEAD"], "git reset --mixed HEAD", repo);
|
|
7375
|
-
const { tracked, untracked } = parseDirtyPaths(repo, { untrackedAll: true });
|
|
7376
|
-
const present = /* @__PURE__ */ new Set([...tracked, ...untracked]);
|
|
7377
|
-
const residual = [...conflicted].filter((p) => present.has(p));
|
|
7378
|
-
if (orphanedAutostashPresent(repo)) {
|
|
7379
|
-
log(
|
|
7380
|
-
'orphaned autostash preserved in the stash list; run "git stash pop" to restore or "git stash drop" to discard it, then re-run "nomad pull"'
|
|
7381
|
-
);
|
|
7382
|
-
}
|
|
7383
|
-
if (residual.length > 0) {
|
|
7384
|
-
die(
|
|
7385
|
-
"index cleared, but these files still carry unresolved conflict content from the torn-down rebase or merge:\n" + residual.map((p) => ` ${p}`).join("\n") + '\n\nThe repo is no longer wedged, so nothing else is blocked. Nothing was applied to ~/.claude/: pulling now would publish that content to your live config.\n\nResolve each file above (remove any <<<<<<< / ======= / >>>>>>> markers and keep the content you want; a file left untracked was deleted upstream, so keep or delete it deliberately), commit or checkout the result, then re-run "nomad pull".',
|
|
7386
|
-
{ code: EXIT.CONFLICT }
|
|
7387
|
-
);
|
|
7388
|
-
}
|
|
7389
|
-
}
|
|
7390
7377
|
function recoverForceRemote(mode, repo) {
|
|
7391
7378
|
if (mode === "merge") {
|
|
7392
7379
|
gitOrFatal(["merge", "--abort"], "git merge --abort", repo);
|
|
@@ -7416,6 +7403,31 @@ function recoverForceRemote(mode, repo) {
|
|
|
7416
7403
|
log(buildRecoverySummary(branchName, strandedLog, untracked));
|
|
7417
7404
|
}
|
|
7418
7405
|
|
|
7406
|
+
// src/commands.pull.recovery.unmerged.ts
|
|
7407
|
+
init_exit_codes();
|
|
7408
|
+
init_commands_pull_wedge();
|
|
7409
|
+
init_utils();
|
|
7410
|
+
function recoverUnmergedIndex(repo) {
|
|
7411
|
+
const conflicted = new Set(
|
|
7412
|
+
gitCapture(["diff", "--diff-filter=U", "--name-only", "-z"], repo).split("\0").filter(Boolean)
|
|
7413
|
+
);
|
|
7414
|
+
gitOrFatal(["reset", "--mixed", "HEAD"], "git reset --mixed HEAD", repo);
|
|
7415
|
+
const { tracked, untracked } = parseDirtyPaths(repo, { untrackedAll: true });
|
|
7416
|
+
const present = /* @__PURE__ */ new Set([...tracked, ...untracked]);
|
|
7417
|
+
const residual = [...conflicted].filter((p) => present.has(p));
|
|
7418
|
+
if (orphanedAutostashPresent(repo)) {
|
|
7419
|
+
log(
|
|
7420
|
+
'orphaned autostash preserved in the stash list; run "git stash pop" to restore or "git stash drop" to discard it, then re-run "nomad pull"'
|
|
7421
|
+
);
|
|
7422
|
+
}
|
|
7423
|
+
if (residual.length > 0) {
|
|
7424
|
+
die(
|
|
7425
|
+
"index cleared, but these files still carry unresolved conflict content from the torn-down rebase or merge:\n" + residual.map((p) => ` ${p}`).join("\n") + '\n\nThe repo is no longer wedged, so nothing else is blocked. Nothing was applied to ~/.claude/: pulling now would publish that content to your live config.\n\nResolve each file above (remove any <<<<<<< / ======= / >>>>>>> markers and keep the content you want; a file left untracked was deleted upstream, so keep or delete it deliberately), commit or checkout the result, then re-run "nomad pull".',
|
|
7426
|
+
{ code: EXIT.CONFLICT }
|
|
7427
|
+
);
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
|
|
7419
7431
|
// src/commands.pull.ts
|
|
7420
7432
|
init_exit_codes();
|
|
7421
7433
|
init_utils();
|
|
@@ -7507,7 +7519,6 @@ function runPullCore(opts = {}) {
|
|
|
7507
7519
|
const divergedKeptLocal = divergenceCheckExtras(ts, dryRun ? prePostHeads : void 0);
|
|
7508
7520
|
if (dryRun) {
|
|
7509
7521
|
computePreview(ts, map, "pull");
|
|
7510
|
-
log("dry-run complete; no mutation");
|
|
7511
7522
|
return { tag: "dry" };
|
|
7512
7523
|
}
|
|
7513
7524
|
const { sections, localOnly, settingsLabel, unmapped, extrasSkipped } = buildWetPullSections(
|
|
@@ -7538,6 +7549,7 @@ function cmdPull(opts = {}) {
|
|
|
7538
7549
|
try {
|
|
7539
7550
|
const result = runPullCore(opts);
|
|
7540
7551
|
if (result.tag === "wet") renderTree(result.sections);
|
|
7552
|
+
else log("dry-run complete; nothing applied to ~/.claude/");
|
|
7541
7553
|
} catch (err) {
|
|
7542
7554
|
if (err instanceof NomadFatal) {
|
|
7543
7555
|
fail(err.message);
|
|
@@ -8134,8 +8146,6 @@ import { join as join59 } from "node:path";
|
|
|
8134
8146
|
init_config();
|
|
8135
8147
|
init_color();
|
|
8136
8148
|
init_utils();
|
|
8137
|
-
init_utils_fs();
|
|
8138
|
-
init_utils_json();
|
|
8139
8149
|
function isNoopSync(pull, pushOutcome) {
|
|
8140
8150
|
if (!pushOutcome.ok) return false;
|
|
8141
8151
|
if (pull.localOnly !== 0 || pull.divergedKeptLocal !== 0) return false;
|
|
@@ -8256,19 +8266,16 @@ async function runSyncWet(verbose) {
|
|
|
8256
8266
|
const pushOutcome = await runSyncPushHalf();
|
|
8257
8267
|
renderWetSync(pull, pushOutcome, verbose);
|
|
8258
8268
|
}
|
|
8259
|
-
async function runSyncDryRun(
|
|
8260
|
-
|
|
8261
|
-
const mapPath = join59(repo, "path-map.json");
|
|
8262
|
-
const map = existsSync48(mapPath) ? readPathMap(mapPath) : { projects: {} };
|
|
8263
|
-
computePreview(ts, map, "pull");
|
|
8269
|
+
async function runSyncDryRun() {
|
|
8270
|
+
runPullCore({ dryRun: true });
|
|
8264
8271
|
log("push preview below is computed against pre-pull state (a real sync pushes after pull)");
|
|
8265
8272
|
await runPushCore({ dryRun: true });
|
|
8273
|
+
log("dry-run complete; nothing applied to ~/.claude/, nothing pushed");
|
|
8266
8274
|
}
|
|
8267
8275
|
async function cmdSync(opts = {}) {
|
|
8268
8276
|
const dryRun = opts.dryRun === true;
|
|
8269
8277
|
const verbose = opts.verbose === true;
|
|
8270
8278
|
const repo = repoHome();
|
|
8271
|
-
const backup = backupBase();
|
|
8272
8279
|
if (!existsSync48(repo)) die(`repo not cloned at ${repo}`);
|
|
8273
8280
|
if (!existsSync48(join59(repo, "shared", "settings.base.json"))) {
|
|
8274
8281
|
die("repo not initialized; run 'nomad init' to scaffold");
|
|
@@ -8277,7 +8284,7 @@ async function cmdSync(opts = {}) {
|
|
|
8277
8284
|
if (handle === null) process.exit(0);
|
|
8278
8285
|
try {
|
|
8279
8286
|
if (dryRun) {
|
|
8280
|
-
await runSyncDryRun(
|
|
8287
|
+
await runSyncDryRun();
|
|
8281
8288
|
} else {
|
|
8282
8289
|
await runSyncWet(verbose);
|
|
8283
8290
|
}
|
|
@@ -9089,7 +9096,7 @@ function parseSyncArgs(argv) {
|
|
|
9089
9096
|
// package.json
|
|
9090
9097
|
var package_default = {
|
|
9091
9098
|
name: "claude-nomad",
|
|
9092
|
-
version: "0.62.
|
|
9099
|
+
version: "0.62.4",
|
|
9093
9100
|
type: "module",
|
|
9094
9101
|
description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
|
|
9095
9102
|
keywords: [
|
package/package.json
CHANGED