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/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 ℹ︎-prefixed
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
- // Settings section: skip-with-log when base or current is missing. Per the
97
- // locked phrasing decision, the message text is fixed so cmdDiff users see
98
- // the same line regardless of which side is missing. Calling
99
- // regenerateSettings(ts, { dryRun: true }) would only emit a generic
100
- // "would write" intent line; we want the unified diff here, so we compute
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
  /**