claude-nomad 0.22.2 → 0.23.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 +19 -0
- package/package.json +1 -1
- package/src/commands.doctor.engine.ts +90 -0
- package/src/commands.doctor.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.23.0](https://github.com/funkadelic/claude-nomad/compare/v0.22.3...v0.23.0) (2026-05-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
* **doctor:** warn when host node is below engines.node minimum ([#116](https://github.com/funkadelic/claude-nomad/issues/116)) ([3caf8d0](https://github.com/funkadelic/claude-nomad/commit/3caf8d09362b2f290af3d0efd9ea79a64aac39c1))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
* **tests:** add lockfile drift gate to catch release-please mismatches ([#114](https://github.com/funkadelic/claude-nomad/issues/114)) ([5847553](https://github.com/funkadelic/claude-nomad/commit/58475538ed405e1d2d1d00662ea6730ad124da42))
|
|
14
|
+
|
|
15
|
+
## [0.22.3](https://github.com/funkadelic/claude-nomad/compare/v0.22.2...v0.22.3) (2026-05-23)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
* **deps:** resync package-lock with manifest after 0.22.2 ([#109](https://github.com/funkadelic/claude-nomad/issues/109)) ([7317fd4](https://github.com/funkadelic/claude-nomad/commit/7317fd4bb375c5a5fb9c05c327fc75423946b0f0))
|
|
21
|
+
|
|
3
22
|
## [0.22.2](https://github.com/funkadelic/claude-nomad/compare/v0.22.1...v0.22.2) (2026-05-23)
|
|
4
23
|
|
|
5
24
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { green, okGlyph, warnGlyph, yellow } from './color.ts';
|
|
5
|
+
import { addItem, type DoctorSection } from './commands.doctor.format.ts';
|
|
6
|
+
import { compareSemver } from './commands.doctor.version.ts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Soft host-fitness check appended to the Version section of `nomad doctor`.
|
|
10
|
+
* Compares the running node version (`process.version`) to the minimum required
|
|
11
|
+
* by `engines.node` in `package.json`, emitting one of:
|
|
12
|
+
* - `✓ node: vX.Y.Z (satisfies >=A.B.C)` when current >= required
|
|
13
|
+
* - `⚠︎ node: vX.Y.Z (below required >=A.B.C, run \`nvm install\`)` when below
|
|
14
|
+
* Every failure path (missing engines, unsupported range syntax, unreadable
|
|
15
|
+
* `package.json`) is a SILENT skip; this module never sets `process.exitCode`
|
|
16
|
+
* and never writes to stderr. Mirrors the philosophy of the sibling release-
|
|
17
|
+
* version check in `commands.doctor.version.ts`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** Strict `>=X.Y.Z` matcher. The project's `engines.node` field has always
|
|
21
|
+
* used this form; anything more exotic (`^`, `~`, exact pin, OR ranges) is
|
|
22
|
+
* out of scope and triggers the silent-skip path so we never falsely PASS or
|
|
23
|
+
* falsely WARN on a spec we cannot parse with full confidence. */
|
|
24
|
+
const ENGINES_GTE = /^>=\s*(\d+\.\d+\.\d+)$/;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Peel the minimum strict-semver out of an `engines.node` spec when the spec
|
|
28
|
+
* is `>=X.Y.Z` (optional whitespace after `>=`). Returns the bare `X.Y.Z`
|
|
29
|
+
* string. Any other shape (`^X.Y.Z`, `~X.Y.Z`, exact pins, OR ranges, bare
|
|
30
|
+
* versions) returns `null` so the caller silently skips the diagnostic.
|
|
31
|
+
*/
|
|
32
|
+
export function parseMinVersion(spec: string): string | null {
|
|
33
|
+
const m = ENGINES_GTE.exec(spec);
|
|
34
|
+
return m ? m[1] : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Locate and parse the local `package.json`, returning the `engines.node`
|
|
39
|
+
* string when present, non-empty, and a string. Any throw (missing file,
|
|
40
|
+
* parse error, etc.) becomes a `null` return so the caller silently skips.
|
|
41
|
+
*/
|
|
42
|
+
function readEnginesNode(): string | null {
|
|
43
|
+
try {
|
|
44
|
+
const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
45
|
+
const parsed = JSON.parse(readFileSync(pkgPath, 'utf8')) as {
|
|
46
|
+
engines?: { node?: unknown };
|
|
47
|
+
};
|
|
48
|
+
const node = parsed.engines?.node;
|
|
49
|
+
if (typeof node === 'string' && node.length > 0) return node;
|
|
50
|
+
return null;
|
|
51
|
+
} catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Emit a single, non-fatal node-engine diagnostic for `nomad doctor` by
|
|
58
|
+
* comparing `process.version` to the minimum required by `engines.node`.
|
|
59
|
+
*
|
|
60
|
+
* Logs one of:
|
|
61
|
+
* - `✓ node: vX.Y.Z (satisfies >=A.B.C)` when current is at or above the minimum
|
|
62
|
+
* - `⚠︎ node: vX.Y.Z (below required >=A.B.C, run \`nvm install\`)` when below
|
|
63
|
+
*
|
|
64
|
+
* Any failure to read `package.json`, locate `engines.node`, or parse the
|
|
65
|
+
* range spec results in no output and does not change `process.exitCode`.
|
|
66
|
+
*/
|
|
67
|
+
export function reportNodeEngineCheck(section: DoctorSection): void {
|
|
68
|
+
const required = readEnginesNode();
|
|
69
|
+
if (required === null) return;
|
|
70
|
+
const min = parseMinVersion(required);
|
|
71
|
+
if (min === null) return;
|
|
72
|
+
const current = process.version.replace(/^v/, '');
|
|
73
|
+
// Belt-and-suspenders: official Node release builds always produce a strict
|
|
74
|
+
// `vX.Y.Z`, but prerelease/nightly builds can carry a suffix
|
|
75
|
+
// (e.g. `v22.0.0-rc.1`) that compareSemver classifies as undecidable
|
|
76
|
+
// (returns 0). Without this guard, an undecidable comparison would fall
|
|
77
|
+
// through to the green PASS branch and falsely claim the host satisfies the
|
|
78
|
+
// engine constraint. Silent-skip matches the module's "err on the side of
|
|
79
|
+
// saying nothing" philosophy.
|
|
80
|
+
if (!/^\d+\.\d+\.\d+$/.test(current)) return;
|
|
81
|
+
const cmp = compareSemver(current, min);
|
|
82
|
+
if (cmp === -1) {
|
|
83
|
+
addItem(
|
|
84
|
+
section,
|
|
85
|
+
`${yellow(warnGlyph)} node: ${process.version} (below required >=${min}, run \`nvm install\`)`,
|
|
86
|
+
);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
addItem(section, `${green(okGlyph)} node: ${process.version} (satisfies >=${min})`);
|
|
90
|
+
}
|
package/src/commands.doctor.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
reportRepoState,
|
|
13
13
|
reportSharedLinks,
|
|
14
14
|
} from './commands.doctor.checks.ts';
|
|
15
|
+
import { reportNodeEngineCheck } from './commands.doctor.engine.ts';
|
|
15
16
|
import { renderDoctor, section } from './commands.doctor.format.ts';
|
|
16
17
|
import { reportVersionCheck } from './commands.doctor.version.ts';
|
|
17
18
|
|
|
@@ -51,6 +52,7 @@ export function cmdDoctor(): void {
|
|
|
51
52
|
|
|
52
53
|
const version = section('Version');
|
|
53
54
|
reportVersionCheck(version);
|
|
55
|
+
reportNodeEngineCheck(version);
|
|
54
56
|
|
|
55
57
|
renderDoctor([version, host, links, settings, pathMap, neverSync, repository]);
|
|
56
58
|
}
|