@dzhechkov/harness-cli 0.4.5 → 0.5.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/.dz-manifest.json +92 -16
- package/LICENSE +21 -0
- package/README.md +345 -18
- package/dist/bin.d.ts +10 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +45 -12
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +712 -170
- package/dist/cli.js.map +1 -1
- package/dist/core-compat.d.ts +106 -0
- package/dist/core-compat.d.ts.map +1 -0
- package/dist/core-compat.js +252 -0
- package/dist/core-compat.js.map +1 -0
- package/package.json +12 -12
- package/sbom.json +205 -15
- package/src/bin.ts +43 -12
- package/src/cli.ts +707 -146
- package/src/core-compat.ts +240 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/harness-core` compatibility guard — the import-free island.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this module exists
|
|
5
|
+
*
|
|
6
|
+
* ESM resolves and link-checks **every named binding of the whole static graph** before
|
|
7
|
+
* the first byte of user code runs. `bin.ts` used to `import { runCli } from './cli.js'`
|
|
8
|
+
* statically, and `cli.ts` statically imports ~100 names from `@dzhechkov/harness-core`.
|
|
9
|
+
* Against a cached lower core the linker threw
|
|
10
|
+
* `SyntaxError: … does not provide an export named 'GRADE_SUCCESS_FLOOR'` at
|
|
11
|
+
* `#asyncInstantiate` — every subcommand, `--version` included, died before any guard
|
|
12
|
+
* could speak. (MEASURED against `@dzhechkov/harness-core@0.4.1`; `^0.4.0` legally
|
|
13
|
+
* resolves it and the symbol only exists from core 0.4.2.)
|
|
14
|
+
*
|
|
15
|
+
* ## The defining constraint — negative, and enforced rather than remembered
|
|
16
|
+
*
|
|
17
|
+
* **This file may not import anything from `@dzhechkov/harness-core`, directly or
|
|
18
|
+
* transitively — only `node:` builtins.** If it joins the graph it is guarding, it dies
|
|
19
|
+
* with it and the guard is decorative. `test/core-compat-guard.test.ts` parses this
|
|
20
|
+
* file's import list and asserts exactly that.
|
|
21
|
+
*
|
|
22
|
+
* ## Fail-open on an unreadable version — a deliberate exception
|
|
23
|
+
*
|
|
24
|
+
* When the installed core's version cannot be determined the guard **proceeds**. Its job
|
|
25
|
+
* is to replace a bad message with a good one, not to gate execution; blocking a working
|
|
26
|
+
* install because a version string was unreadable would be a self-inflicted outage
|
|
27
|
+
* strictly worse than the `SyntaxError`. This is a conscious exception to the house rule
|
|
28
|
+
* "inconclusive never passes", which governs gates that grant a *quality* verdict — do
|
|
29
|
+
* not "fix" it. The symmetric hazard (a guard that fires wrongly and bricks a good
|
|
30
|
+
* install) is covered by {@link compareSemver} treating any unparseable component as
|
|
31
|
+
* compatible.
|
|
32
|
+
*
|
|
33
|
+
* @packageDocumentation
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* The lowest `@dzhechkov/harness-core` this CLI build can run against.
|
|
37
|
+
*
|
|
38
|
+
* Kept equal to the minimum of the declared dependency range in `package.json` — a
|
|
39
|
+
* standing test (`test/core-import-floor.test.ts`, F1) fails if the two drift apart,
|
|
40
|
+
* because a guard that says 0.4.7 while npm may install 0.4.2 is worse than no guard.
|
|
41
|
+
*/
|
|
42
|
+
export declare const MIN_CORE = "0.5.0";
|
|
43
|
+
/** The npm name of the guarded package — one literal, used by every leg below. */
|
|
44
|
+
export declare const CORE_PACKAGE_NAME = "@dzhechkov/harness-core";
|
|
45
|
+
/**
|
|
46
|
+
* Compare two semver strings by `major.minor.patch`, then by prerelease.
|
|
47
|
+
*
|
|
48
|
+
* Rules that matter here:
|
|
49
|
+
* - every component runs through a `Number.isFinite` clamp; a non-finite or missing
|
|
50
|
+
* component makes the comparison return `0` (compatible), never a false "too old";
|
|
51
|
+
* - **prerelease (`-…`) and build metadata (`+…`) are parsed SEPARATELY**, because they
|
|
52
|
+
* mean opposite things. A prerelease sorts BELOW its release (`0.4.6-rc.1` < `0.4.6`),
|
|
53
|
+
* so a release-candidate core does not silently satisfy a floor it has not reached;
|
|
54
|
+
* build metadata is **ignored entirely** (`0.4.6+sha1234` === `0.4.6`), because a core
|
|
55
|
+
* built from a tagged commit is that version and refusing it would be a self-inflicted
|
|
56
|
+
* outage — exactly what ADR-003 driver D6 forbids.
|
|
57
|
+
*
|
|
58
|
+
* Both halves were wrong before fix round 1 (QE F3): one capture group `(?:[-+](.*))?`
|
|
59
|
+
* swallowed either sigil, patched over by `!m[4].startsWith('build')`. MEASURED
|
|
60
|
+
* consequences: `0.4.6+sha1234` was REFUSED (false block) and `0.4.6-build.5` was
|
|
61
|
+
* ACCEPTED (false pass) against a `0.4.6` floor. A string special case is not SemVer.
|
|
62
|
+
*/
|
|
63
|
+
export declare function compareSemver(a: string, b: string): -1 | 0 | 1;
|
|
64
|
+
/**
|
|
65
|
+
* Best-effort: what version of `@dzhechkov/harness-core` will actually be loaded?
|
|
66
|
+
*
|
|
67
|
+
* Three legs, in order — the obvious one does **not** work on its own:
|
|
68
|
+
*
|
|
69
|
+
* 1. `import.meta.resolve(CORE_PACKAGE_NAME)` (a function on node ≥20.6; `typeof`-guarded
|
|
70
|
+
* because `engines` says `>=20` and it is flagged on 20.0–20.5), then walk up to the
|
|
71
|
+
* nearest `package.json`.
|
|
72
|
+
* 2. Ancestor-walk from this file for `node_modules/@dzhechkov/harness-core/package.json`
|
|
73
|
+
* — **no resolver semantics**. This leg is load-bearing rather than a fallback: an old
|
|
74
|
+
* core's `exports` map declares only `{".": {"import": …}}`, so
|
|
75
|
+
* `require.resolve('@dzhechkov/harness-core/package.json')` fails with
|
|
76
|
+
* `ERR_PACKAGE_PATH_NOT_EXPORTED` (MEASURED in this tree) — and the old core is
|
|
77
|
+
* precisely the case the guard exists for.
|
|
78
|
+
* 3. `null` — the fail-open path documented at the top of this file.
|
|
79
|
+
*/
|
|
80
|
+
export declare function resolveInstalledCoreVersion(fromUrl: string): string | null;
|
|
81
|
+
/** The verdict of {@link checkCoreCompat}. */
|
|
82
|
+
export type CoreCompatVerdict = {
|
|
83
|
+
readonly ok: true;
|
|
84
|
+
} | {
|
|
85
|
+
readonly ok: false;
|
|
86
|
+
readonly message: string;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Decide whether the found core is usable, and if not, say so in words a user can act on.
|
|
90
|
+
*
|
|
91
|
+
* `found === null` ⇒ `{ ok: true }` (fail-open — see the module doc comment).
|
|
92
|
+
*/
|
|
93
|
+
export declare function checkCoreCompat(input: {
|
|
94
|
+
found: string | null;
|
|
95
|
+
min: string;
|
|
96
|
+
}): CoreCompatVerdict;
|
|
97
|
+
/**
|
|
98
|
+
* Reactive translator for the failure the pre-emptive guard could not see.
|
|
99
|
+
*
|
|
100
|
+
* If the version probe fails open (leg 3) and the dynamic import then dies on a missing
|
|
101
|
+
* ESM binding, the raw `SyntaxError` reads like a corrupted install or a Node problem.
|
|
102
|
+
* Rewrite it into the same named form. Returns `null` for any OTHER error — the caller
|
|
103
|
+
* must re-throw those unchanged, so real bugs still surface.
|
|
104
|
+
*/
|
|
105
|
+
export declare function describeMissingExportError(error: unknown, found: string | null): string | null;
|
|
106
|
+
//# sourceMappingURL=core-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-compat.d.ts","sourceRoot":"","sources":["../src/core-compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAMH;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,UAAU,CAAC;AAEhC,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,4BAA4B,CAAC;AAiC3D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CA0B9D;AA2BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA4B1E;AAED,8CAA8C;AAC9C,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzG;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAY/F;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAU9F"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/harness-core` compatibility guard — the import-free island.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this module exists
|
|
5
|
+
*
|
|
6
|
+
* ESM resolves and link-checks **every named binding of the whole static graph** before
|
|
7
|
+
* the first byte of user code runs. `bin.ts` used to `import { runCli } from './cli.js'`
|
|
8
|
+
* statically, and `cli.ts` statically imports ~100 names from `@dzhechkov/harness-core`.
|
|
9
|
+
* Against a cached lower core the linker threw
|
|
10
|
+
* `SyntaxError: … does not provide an export named 'GRADE_SUCCESS_FLOOR'` at
|
|
11
|
+
* `#asyncInstantiate` — every subcommand, `--version` included, died before any guard
|
|
12
|
+
* could speak. (MEASURED against `@dzhechkov/harness-core@0.4.1`; `^0.4.0` legally
|
|
13
|
+
* resolves it and the symbol only exists from core 0.4.2.)
|
|
14
|
+
*
|
|
15
|
+
* ## The defining constraint — negative, and enforced rather than remembered
|
|
16
|
+
*
|
|
17
|
+
* **This file may not import anything from `@dzhechkov/harness-core`, directly or
|
|
18
|
+
* transitively — only `node:` builtins.** If it joins the graph it is guarding, it dies
|
|
19
|
+
* with it and the guard is decorative. `test/core-compat-guard.test.ts` parses this
|
|
20
|
+
* file's import list and asserts exactly that.
|
|
21
|
+
*
|
|
22
|
+
* ## Fail-open on an unreadable version — a deliberate exception
|
|
23
|
+
*
|
|
24
|
+
* When the installed core's version cannot be determined the guard **proceeds**. Its job
|
|
25
|
+
* is to replace a bad message with a good one, not to gate execution; blocking a working
|
|
26
|
+
* install because a version string was unreadable would be a self-inflicted outage
|
|
27
|
+
* strictly worse than the `SyntaxError`. This is a conscious exception to the house rule
|
|
28
|
+
* "inconclusive never passes", which governs gates that grant a *quality* verdict — do
|
|
29
|
+
* not "fix" it. The symmetric hazard (a guard that fires wrongly and bricks a good
|
|
30
|
+
* install) is covered by {@link compareSemver} treating any unparseable component as
|
|
31
|
+
* compatible.
|
|
32
|
+
*
|
|
33
|
+
* @packageDocumentation
|
|
34
|
+
*/
|
|
35
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
36
|
+
import { dirname, join, resolve } from 'node:path';
|
|
37
|
+
import { fileURLToPath } from 'node:url';
|
|
38
|
+
/**
|
|
39
|
+
* The lowest `@dzhechkov/harness-core` this CLI build can run against.
|
|
40
|
+
*
|
|
41
|
+
* Kept equal to the minimum of the declared dependency range in `package.json` — a
|
|
42
|
+
* standing test (`test/core-import-floor.test.ts`, F1) fails if the two drift apart,
|
|
43
|
+
* because a guard that says 0.4.7 while npm may install 0.4.2 is worse than no guard.
|
|
44
|
+
*/
|
|
45
|
+
export const MIN_CORE = '0.5.0';
|
|
46
|
+
/** The npm name of the guarded package — one literal, used by every leg below. */
|
|
47
|
+
export const CORE_PACKAGE_NAME = '@dzhechkov/harness-core';
|
|
48
|
+
/**
|
|
49
|
+
* Compare the dot-separated identifiers of two SemVer prerelease strings (§11.4).
|
|
50
|
+
*
|
|
51
|
+
* Numeric identifiers compare numerically and rank BELOW alphanumeric ones; when every
|
|
52
|
+
* shared identifier is equal, the longer list is the higher version.
|
|
53
|
+
*/
|
|
54
|
+
function comparePrerelease(a, b) {
|
|
55
|
+
if (a === b)
|
|
56
|
+
return 0;
|
|
57
|
+
const xs = a.split('.');
|
|
58
|
+
const ys = b.split('.');
|
|
59
|
+
for (let i = 0; i < Math.max(xs.length, ys.length); i += 1) {
|
|
60
|
+
const x = xs[i];
|
|
61
|
+
const y = ys[i];
|
|
62
|
+
// A shorter identifier list is the LOWER version (`1.0.0-rc` < `1.0.0-rc.1`).
|
|
63
|
+
if (x === undefined)
|
|
64
|
+
return -1;
|
|
65
|
+
if (y === undefined)
|
|
66
|
+
return 1;
|
|
67
|
+
const xNum = /^\d+$/.test(x);
|
|
68
|
+
const yNum = /^\d+$/.test(y);
|
|
69
|
+
if (xNum && yNum) {
|
|
70
|
+
const nx = Number(x);
|
|
71
|
+
const ny = Number(y);
|
|
72
|
+
if (nx !== ny)
|
|
73
|
+
return nx < ny ? -1 : 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Numeric identifiers always have lower precedence than alphanumeric ones.
|
|
77
|
+
if (xNum !== yNum)
|
|
78
|
+
return xNum ? -1 : 1;
|
|
79
|
+
if (x !== y)
|
|
80
|
+
return x < y ? -1 : 1;
|
|
81
|
+
}
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Compare two semver strings by `major.minor.patch`, then by prerelease.
|
|
86
|
+
*
|
|
87
|
+
* Rules that matter here:
|
|
88
|
+
* - every component runs through a `Number.isFinite` clamp; a non-finite or missing
|
|
89
|
+
* component makes the comparison return `0` (compatible), never a false "too old";
|
|
90
|
+
* - **prerelease (`-…`) and build metadata (`+…`) are parsed SEPARATELY**, because they
|
|
91
|
+
* mean opposite things. A prerelease sorts BELOW its release (`0.4.6-rc.1` < `0.4.6`),
|
|
92
|
+
* so a release-candidate core does not silently satisfy a floor it has not reached;
|
|
93
|
+
* build metadata is **ignored entirely** (`0.4.6+sha1234` === `0.4.6`), because a core
|
|
94
|
+
* built from a tagged commit is that version and refusing it would be a self-inflicted
|
|
95
|
+
* outage — exactly what ADR-003 driver D6 forbids.
|
|
96
|
+
*
|
|
97
|
+
* Both halves were wrong before fix round 1 (QE F3): one capture group `(?:[-+](.*))?`
|
|
98
|
+
* swallowed either sigil, patched over by `!m[4].startsWith('build')`. MEASURED
|
|
99
|
+
* consequences: `0.4.6+sha1234` was REFUSED (false block) and `0.4.6-build.5` was
|
|
100
|
+
* ACCEPTED (false pass) against a `0.4.6` floor. A string special case is not SemVer.
|
|
101
|
+
*/
|
|
102
|
+
export function compareSemver(a, b) {
|
|
103
|
+
const parse = (v) => {
|
|
104
|
+
// Prerelease and build metadata get one capture EACH, in SemVer's own order.
|
|
105
|
+
const m = /^\s*v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+([0-9A-Za-z.-]+))?\s*$/.exec(v);
|
|
106
|
+
if (m === null)
|
|
107
|
+
return null;
|
|
108
|
+
const nums = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
109
|
+
if (!nums.every((n) => Number.isFinite(n)))
|
|
110
|
+
return null;
|
|
111
|
+
// m[5] (build metadata) is deliberately never read: SemVer §10 says it is not
|
|
112
|
+
// part of precedence.
|
|
113
|
+
return { nums, pre: m[4] !== undefined && m[4].length > 0 ? m[4] : null };
|
|
114
|
+
};
|
|
115
|
+
const pa = parse(a);
|
|
116
|
+
const pb = parse(b);
|
|
117
|
+
// Unparseable on either side ⇒ "compatible": never brick a working install on a
|
|
118
|
+
// version string we failed to read.
|
|
119
|
+
if (pa === null || pb === null)
|
|
120
|
+
return 0;
|
|
121
|
+
for (let i = 0; i < 3; i += 1) {
|
|
122
|
+
const x = pa.nums[i] ?? 0;
|
|
123
|
+
const y = pb.nums[i] ?? 0;
|
|
124
|
+
if (x < y)
|
|
125
|
+
return -1;
|
|
126
|
+
if (x > y)
|
|
127
|
+
return 1;
|
|
128
|
+
}
|
|
129
|
+
if (pa.pre === null && pb.pre === null)
|
|
130
|
+
return 0;
|
|
131
|
+
if (pa.pre === null)
|
|
132
|
+
return 1;
|
|
133
|
+
if (pb.pre === null)
|
|
134
|
+
return -1;
|
|
135
|
+
return comparePrerelease(pa.pre, pb.pre);
|
|
136
|
+
}
|
|
137
|
+
/** Read `.version` out of a `package.json`, or `null` if it is missing/unreadable. */
|
|
138
|
+
function readVersion(packageJsonPath) {
|
|
139
|
+
try {
|
|
140
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
141
|
+
return typeof parsed.version === 'string' ? parsed.version : null;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Walk up from `start` to the nearest enclosing `package.json`, reading its version. */
|
|
148
|
+
function versionFromEnclosingPackage(start) {
|
|
149
|
+
let dir = start;
|
|
150
|
+
for (;;) {
|
|
151
|
+
const candidate = join(dir, 'package.json');
|
|
152
|
+
if (existsSync(candidate)) {
|
|
153
|
+
const version = readVersion(candidate);
|
|
154
|
+
if (version !== null)
|
|
155
|
+
return version;
|
|
156
|
+
}
|
|
157
|
+
const parent = dirname(dir);
|
|
158
|
+
if (parent === dir)
|
|
159
|
+
return null;
|
|
160
|
+
dir = parent;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Best-effort: what version of `@dzhechkov/harness-core` will actually be loaded?
|
|
165
|
+
*
|
|
166
|
+
* Three legs, in order — the obvious one does **not** work on its own:
|
|
167
|
+
*
|
|
168
|
+
* 1. `import.meta.resolve(CORE_PACKAGE_NAME)` (a function on node ≥20.6; `typeof`-guarded
|
|
169
|
+
* because `engines` says `>=20` and it is flagged on 20.0–20.5), then walk up to the
|
|
170
|
+
* nearest `package.json`.
|
|
171
|
+
* 2. Ancestor-walk from this file for `node_modules/@dzhechkov/harness-core/package.json`
|
|
172
|
+
* — **no resolver semantics**. This leg is load-bearing rather than a fallback: an old
|
|
173
|
+
* core's `exports` map declares only `{".": {"import": …}}`, so
|
|
174
|
+
* `require.resolve('@dzhechkov/harness-core/package.json')` fails with
|
|
175
|
+
* `ERR_PACKAGE_PATH_NOT_EXPORTED` (MEASURED in this tree) — and the old core is
|
|
176
|
+
* precisely the case the guard exists for.
|
|
177
|
+
* 3. `null` — the fail-open path documented at the top of this file.
|
|
178
|
+
*/
|
|
179
|
+
export function resolveInstalledCoreVersion(fromUrl) {
|
|
180
|
+
const meta = import.meta;
|
|
181
|
+
if (typeof meta.resolve === 'function') {
|
|
182
|
+
try {
|
|
183
|
+
const resolved = meta.resolve(CORE_PACKAGE_NAME);
|
|
184
|
+
const version = versionFromEnclosingPackage(dirname(fileURLToPath(resolved)));
|
|
185
|
+
if (version !== null)
|
|
186
|
+
return version;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* fall through to the filesystem walk */
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
let dir;
|
|
193
|
+
try {
|
|
194
|
+
dir = dirname(fileURLToPath(fromUrl));
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
dir = resolve('.');
|
|
198
|
+
}
|
|
199
|
+
for (;;) {
|
|
200
|
+
const candidate = join(dir, 'node_modules', ...CORE_PACKAGE_NAME.split('/'), 'package.json');
|
|
201
|
+
if (existsSync(candidate)) {
|
|
202
|
+
const version = readVersion(candidate);
|
|
203
|
+
if (version !== null)
|
|
204
|
+
return version;
|
|
205
|
+
}
|
|
206
|
+
const parent = dirname(dir);
|
|
207
|
+
if (parent === dir)
|
|
208
|
+
return null;
|
|
209
|
+
dir = parent;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Decide whether the found core is usable, and if not, say so in words a user can act on.
|
|
214
|
+
*
|
|
215
|
+
* `found === null` ⇒ `{ ok: true }` (fail-open — see the module doc comment).
|
|
216
|
+
*/
|
|
217
|
+
export function checkCoreCompat(input) {
|
|
218
|
+
const { found, min } = input;
|
|
219
|
+
if (found === null)
|
|
220
|
+
return { ok: true };
|
|
221
|
+
if (compareSemver(found, min) >= 0)
|
|
222
|
+
return { ok: true };
|
|
223
|
+
return {
|
|
224
|
+
ok: false,
|
|
225
|
+
message: [
|
|
226
|
+
`dz: needs ${CORE_PACKAGE_NAME} >= ${min}, found ${found}`,
|
|
227
|
+
' Your resolver reused a cached lower core. Fix: rm -rf ~/.npm/_npx && npx @dzhechkov/harness-cli@latest --version',
|
|
228
|
+
` (or: npm i -D ${CORE_PACKAGE_NAME}@latest)`,
|
|
229
|
+
].join('\n'),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Reactive translator for the failure the pre-emptive guard could not see.
|
|
234
|
+
*
|
|
235
|
+
* If the version probe fails open (leg 3) and the dynamic import then dies on a missing
|
|
236
|
+
* ESM binding, the raw `SyntaxError` reads like a corrupted install or a Node problem.
|
|
237
|
+
* Rewrite it into the same named form. Returns `null` for any OTHER error — the caller
|
|
238
|
+
* must re-throw those unchanged, so real bugs still surface.
|
|
239
|
+
*/
|
|
240
|
+
export function describeMissingExportError(error, found) {
|
|
241
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
242
|
+
const match = /does not provide an export named '?([A-Za-z0-9_$]+)'?/.exec(message);
|
|
243
|
+
if (match === null)
|
|
244
|
+
return null;
|
|
245
|
+
return [
|
|
246
|
+
`dz: this build needs ${CORE_PACKAGE_NAME} >= ${MIN_CORE}${found !== null ? `, found ${found}` : ''}`,
|
|
247
|
+
` The installed core does not export ${JSON.stringify(match[1] ?? '')}, which this CLI imports.`,
|
|
248
|
+
' Fix: rm -rf ~/.npm/_npx && npx @dzhechkov/harness-cli@latest --version',
|
|
249
|
+
` (or: npm i -D ${CORE_PACKAGE_NAME}@latest)`,
|
|
250
|
+
].join('\n');
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=core-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-compat.js","sourceRoot":"","sources":["../src/core-compat.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot.
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "The dz CLI — install AI skills for Claude Code, Codex, OpenCode, Hermes, OpenClaude, GitHub Copilot. 67 commands, 14 presets, 10 platform targets.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "dzhechko",
|
|
@@ -40,15 +40,8 @@
|
|
|
40
40
|
".dz-manifest.json",
|
|
41
41
|
"sbom.json"
|
|
42
42
|
],
|
|
43
|
-
"scripts": {
|
|
44
|
-
"build": "tsc -p tsconfig.json",
|
|
45
|
-
"test": "vitest run",
|
|
46
|
-
"test:watch": "vitest",
|
|
47
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
-
"lint": "tsc -p tsconfig.json --noEmit"
|
|
49
|
-
},
|
|
50
43
|
"dependencies": {
|
|
51
|
-
"@dzhechkov/harness-core": "^0.
|
|
44
|
+
"@dzhechkov/harness-core": "^0.5.0",
|
|
52
45
|
"@dzhechkov/harness-presets": "^0.5.0",
|
|
53
46
|
"@dzhechkov/scout": "^0.8.0",
|
|
54
47
|
"@dzhechkov/skills-devops": "^0.3.0",
|
|
@@ -82,5 +75,12 @@
|
|
|
82
75
|
"url": "https://github.com/djd1m/dz-harness-hub.git",
|
|
83
76
|
"directory": "packages/@dzhechkov/harness-cli"
|
|
84
77
|
},
|
|
85
|
-
"homepage": "https://github.com/djd1m/dz-harness-hub/tree/main/packages/@dzhechkov/harness-cli#readme"
|
|
86
|
-
|
|
78
|
+
"homepage": "https://github.com/djd1m/dz-harness-hub/tree/main/packages/@dzhechkov/harness-cli#readme",
|
|
79
|
+
"scripts": {
|
|
80
|
+
"build": "tsc -p tsconfig.json",
|
|
81
|
+
"test": "vitest run",
|
|
82
|
+
"test:watch": "vitest",
|
|
83
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
84
|
+
"lint": "tsc -p tsconfig.json --noEmit"
|
|
85
|
+
}
|
|
86
|
+
}
|