claude-nomad 0.25.4 → 0.26.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.
- package/CHANGELOG.md +25 -0
- package/README.md +314 -102
- package/package.json +9 -2
- package/src/commands.doctor.check-shared.scan.ts +29 -5
- package/src/commands.doctor.checks.pathmap.ts +2 -2
- package/src/commands.doctor.checks.repo.ts +85 -40
- package/src/commands.doctor.format.ts +22 -7
- package/src/commands.doctor.mirror-actions.ts +8 -3
- package/src/commands.doctor.ts +1 -1
- package/src/commands.doctor.version.ts +15 -9
- package/src/gh-actions.ts +19 -7
- package/src/init.ts +5 -0
- package/src/nomad.help.ts +51 -21
- package/src/nomad.ts +2 -6
- package/src/preview.ts +42 -42
- package/src/push-gitleaks.scan.ts +7 -0
package/src/preview.ts
CHANGED
|
@@ -66,6 +66,42 @@ function readJsonOrNull(path: string): Record<string, unknown> | null {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Emit the settings.json section of the dry-run preview. Reads base, host
|
|
71
|
+
* overrides, and current settings; logs a unified diff or a skip message.
|
|
72
|
+
*
|
|
73
|
+
* Extracted from `computePreview` to reduce cognitive complexity: the nested
|
|
74
|
+
* base-null / malformed-host / malformed-current branches each add score.
|
|
75
|
+
*/
|
|
76
|
+
function previewSettings(basePath: string, hostPath: string, settingsPath: string): void {
|
|
77
|
+
const base = readJsonOrNull(basePath);
|
|
78
|
+
if (base === null) {
|
|
79
|
+
log('settings.json: section skipped (base or current missing)');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Tolerate a malformed hosts/<HOST>.json: log once and fall back to no overrides.
|
|
83
|
+
const hostOverrides = readJsonOrNull(hostPath);
|
|
84
|
+
if (hostOverrides === null && existsSync(hostPath)) {
|
|
85
|
+
log(`settings.json: malformed hosts/${HOST}.json; ignoring overrides`);
|
|
86
|
+
}
|
|
87
|
+
const merged = deepMerge(base, hostOverrides ?? {});
|
|
88
|
+
const current = readJsonOrNull(settingsPath);
|
|
89
|
+
if (current === null && existsSync(settingsPath)) {
|
|
90
|
+
log('settings.json: malformed; skipping diff');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const diff = diffJsonStrings(
|
|
94
|
+
JSON.stringify(current ?? {}, null, 2),
|
|
95
|
+
JSON.stringify(merged, null, 2),
|
|
96
|
+
);
|
|
97
|
+
if (diff === '') {
|
|
98
|
+
log('settings.json: no changes');
|
|
99
|
+
} else {
|
|
100
|
+
log('settings.json:');
|
|
101
|
+
for (const line of diff.split('\n')) log(line);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
69
105
|
/**
|
|
70
106
|
* Orchestrate the dry-run preview across all three sync modalities:
|
|
71
107
|
* symlinks (via applySharedLinks dry-run), settings.json (via deepMerge +
|
|
@@ -83,7 +119,7 @@ function readJsonOrNull(path: string): Record<string, unknown> | null {
|
|
|
83
119
|
* preview may run against a partially-scaffolded repo (e.g. right after a
|
|
84
120
|
* fresh clone before `nomad init`).
|
|
85
121
|
*
|
|
86
|
-
* Settings diff output goes through `log()` so each line gets the
|
|
122
|
+
* Settings diff output goes through `log()` so each line gets the info-prefixed
|
|
87
123
|
* prefix, keeping output channels consistent across the three sections.
|
|
88
124
|
*/
|
|
89
125
|
export function computePreview(ts: string): { unmapped: number; collisions: number } {
|
|
@@ -93,47 +129,11 @@ export function computePreview(ts: string): { unmapped: number; collisions: numb
|
|
|
93
129
|
// lines. dryRun:true is mandatory; a real call here would mutate disk.
|
|
94
130
|
applySharedLinks(ts, { dryRun: true });
|
|
95
131
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// it directly from base + host-override + current.
|
|
102
|
-
const basePath = join(REPO_HOME, 'shared', 'settings.base.json');
|
|
103
|
-
const hostPath = join(REPO_HOME, 'hosts', `${HOST}.json`);
|
|
104
|
-
const settingsPath = join(CLAUDE_HOME, 'settings.json');
|
|
105
|
-
const base = readJsonOrNull(basePath);
|
|
106
|
-
if (base === null) {
|
|
107
|
-
// Base is the load-bearing input here. Per the locked phrasing decision,
|
|
108
|
-
// emit one canonical message and skip the diff. The current-side missing
|
|
109
|
-
// case (no ~/.claude/settings.json) is handled below by treating current
|
|
110
|
-
// as `{}` and producing a normal diff; only base-missing is fatal-ish.
|
|
111
|
-
log('settings.json: section skipped (base or current missing)');
|
|
112
|
-
} else {
|
|
113
|
-
// Tolerate a malformed hosts/<HOST>.json the same way base and current
|
|
114
|
-
// are tolerated: log once and fall back to no overrides so the preview
|
|
115
|
-
// keeps rendering instead of crashing the dry-run.
|
|
116
|
-
const hostOverrides = readJsonOrNull(hostPath);
|
|
117
|
-
if (hostOverrides === null && existsSync(hostPath)) {
|
|
118
|
-
log(`settings.json: malformed hosts/${HOST}.json; ignoring overrides`);
|
|
119
|
-
}
|
|
120
|
-
const overrides = hostOverrides ?? {};
|
|
121
|
-
const merged = deepMerge(base, overrides);
|
|
122
|
-
const current = readJsonOrNull(settingsPath);
|
|
123
|
-
if (current === null && existsSync(settingsPath)) {
|
|
124
|
-
log('settings.json: malformed; skipping diff');
|
|
125
|
-
} else {
|
|
126
|
-
const currentText = JSON.stringify(current ?? {}, null, 2);
|
|
127
|
-
const mergedText = JSON.stringify(merged, null, 2);
|
|
128
|
-
const diff = diffJsonStrings(currentText, mergedText);
|
|
129
|
-
if (diff === '') {
|
|
130
|
-
log('settings.json: no changes');
|
|
131
|
-
} else {
|
|
132
|
-
log('settings.json:');
|
|
133
|
-
for (const line of diff.split('\n')) log(line);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
132
|
+
previewSettings(
|
|
133
|
+
join(REPO_HOME, 'shared', 'settings.base.json'),
|
|
134
|
+
join(REPO_HOME, 'hosts', `${HOST}.json`),
|
|
135
|
+
join(CLAUDE_HOME, 'settings.json'),
|
|
136
|
+
);
|
|
137
137
|
|
|
138
138
|
// Projects: remapPull emits its own would-overwrite lines and returns the
|
|
139
139
|
// skipped count.
|
|
@@ -31,6 +31,13 @@ export type Finding = {
|
|
|
31
31
|
StartLine: number;
|
|
32
32
|
Match: string;
|
|
33
33
|
Fingerprint: string;
|
|
34
|
+
/**
|
|
35
|
+
* Human-readable rule description gitleaks bakes into every finding (the
|
|
36
|
+
* matched rule's `description` from its toml). Optional: absent on older
|
|
37
|
+
* gitleaks reports or custom rules with no description, in which case the
|
|
38
|
+
* doctor legend silently omits the entry (graceful degradation, no network).
|
|
39
|
+
*/
|
|
40
|
+
Description?: string;
|
|
34
41
|
};
|
|
35
42
|
|
|
36
43
|
/**
|