@dzhechkov/harness-cli 0.7.4 → 0.7.6
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 +51 -11
- package/README.md +35 -5
- package/dist/boolean-flags.d.ts +26 -0
- package/dist/boolean-flags.d.ts.map +1 -0
- package/dist/boolean-flags.js +118 -0
- package/dist/boolean-flags.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +619 -21
- package/dist/cli.js.map +1 -1
- package/dist/install-spec.d.ts +36 -0
- package/dist/install-spec.d.ts.map +1 -0
- package/dist/install-spec.js +68 -0
- package/dist/install-spec.js.map +1 -0
- package/dist/known-flags.d.ts.map +1 -1
- package/dist/known-flags.js +9 -0
- package/dist/known-flags.js.map +1 -1
- package/package.json +18 -18
- package/sbom.json +110 -10
- package/src/boolean-flags.ts +118 -0
- package/src/cli.ts +564 -21
- package/src/install-spec.ts +86 -0
- package/src/known-flags.ts +9 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `dz install` argument resolution — feature install-spec-honesty (backlog 43a52cf2 + c999786b).
|
|
3
|
+
*
|
|
4
|
+
* cmdInstall used to splice the RAW argument into `join(projectRoot, 'node_modules', pkg)`.
|
|
5
|
+
* MEASURED, five broken forms: an absolute path (path.join CONCATENATES an absolute segment —
|
|
6
|
+
* `/proj/node_modules/home/dz/pkgs/...`); a versioned spec `@dzhechkov/health-advisor@1.9.0`
|
|
7
|
+
* (the WORST: `npm install` SUCCEEDS and mutates the project's package.json, then dz dies on an
|
|
8
|
+
* invented path with exit 1 — and the versioned form is exactly what the npm-lag README
|
|
9
|
+
* prescribes); a tarball `pack-1.0.0.tgz`; `github:user/repo`; an alias `ha@npm:...`.
|
|
10
|
+
*
|
|
11
|
+
* The cure is a PURE resolver that runs BEFORE any npm process: every accepted form yields the
|
|
12
|
+
* npm spec AND the node_modules directory name it will land under; everything else is a NAMED
|
|
13
|
+
* refusal carrying the working two-command form. A spec whose landing dir cannot be established
|
|
14
|
+
* must never reach npm — that is what made the versioned failure mutate state and then die.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface InstallSpecProbe {
|
|
18
|
+
/** Does `path` exist as a regular file? */
|
|
19
|
+
readonly isFile: (path: string) => boolean;
|
|
20
|
+
/** Does `path` exist as a directory? */
|
|
21
|
+
readonly isDir: (path: string) => boolean;
|
|
22
|
+
/** `name` from `package/package.json` inside a tarball, or null (unreadable/absent). */
|
|
23
|
+
readonly readTarballName: (path: string) => string | null;
|
|
24
|
+
/** `name` from `<dir>/package.json`, or null. */
|
|
25
|
+
readonly readDirName: (path: string) => string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type InstallSpecResolution =
|
|
29
|
+
| { readonly kind: 'name' | 'versioned' | 'alias' | 'tarball' | 'dir'; readonly npmSpec: string; readonly dirName: string }
|
|
30
|
+
| { readonly kind: 'refused'; readonly reason: string; readonly hint: string };
|
|
31
|
+
|
|
32
|
+
const BARE_NAME_RE = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
|
|
33
|
+
|
|
34
|
+
/** The two-command fallback that always works, named in every refusal (43a52cf2's own ask). */
|
|
35
|
+
function twoCommandHint(raw: string): string {
|
|
36
|
+
return `working form: npm install ${raw} --save-dev && dz init --skills-dir node_modules/<installed-package-name>`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function resolveInstallSpec(raw: string, resolveAgainstCwd: (p: string) => string, probe: InstallSpecProbe): InstallSpecResolution {
|
|
40
|
+
const spec = raw.trim();
|
|
41
|
+
if (spec === '') return { kind: 'refused', reason: 'empty spec', hint: 'dz install <package|package@version|path/to.tgz|path/to/dir>' };
|
|
42
|
+
|
|
43
|
+
// Path forms first — a path is never an npm name. Absolute, explicit-relative, or an existing
|
|
44
|
+
// .tgz/.tar.gz/.dir anywhere: the OLD code spliced these into node_modules verbatim.
|
|
45
|
+
const looksPathy = spec.startsWith('/') || spec.startsWith('./') || spec.startsWith('../') || /\.(tgz|tar\.gz)$/.test(spec);
|
|
46
|
+
if (looksPathy) {
|
|
47
|
+
const abs = resolveAgainstCwd(spec);
|
|
48
|
+
if (/\.(tgz|tar\.gz)$/.test(spec)) {
|
|
49
|
+
if (!probe.isFile(abs)) return { kind: 'refused', reason: `tarball not found: ${abs}`, hint: twoCommandHint(spec) };
|
|
50
|
+
const name = probe.readTarballName(abs);
|
|
51
|
+
if (name === null) return { kind: 'refused', reason: `cannot read package/package.json name from ${abs}`, hint: twoCommandHint(spec) };
|
|
52
|
+
return { kind: 'tarball', npmSpec: abs, dirName: name };
|
|
53
|
+
}
|
|
54
|
+
if (probe.isDir(abs)) {
|
|
55
|
+
const name = probe.readDirName(abs);
|
|
56
|
+
if (name === null) return { kind: 'refused', reason: `${abs} has no readable package.json name`, hint: twoCommandHint(spec) };
|
|
57
|
+
return { kind: 'dir', npmSpec: abs, dirName: name };
|
|
58
|
+
}
|
|
59
|
+
return { kind: 'refused', reason: `path does not exist: ${abs}`, hint: twoCommandHint(spec) };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// git/github/url specs: the landing dir is not cheaply establishable — refuse with the cure.
|
|
63
|
+
if (/^(github:|git\+|git:|https?:\/\/)/.test(spec)) {
|
|
64
|
+
return { kind: 'refused', reason: `git/url specs are not resolvable to a node_modules dir up front (${spec})`, hint: twoCommandHint(spec) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// alias@npm:real[@version] — installs under the ALIAS name.
|
|
68
|
+
const alias = /^([^@][^@]*|@[^/]+\/[^@]+)@npm:(.+)$/.exec(spec);
|
|
69
|
+
if (alias !== null) {
|
|
70
|
+
return { kind: 'alias', npmSpec: spec, dirName: alias[1] as string };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (BARE_NAME_RE.test(spec)) return { kind: 'name', npmSpec: spec, dirName: spec };
|
|
74
|
+
|
|
75
|
+
// name@version / @scope/name@version — the dir is the name WITHOUT the version.
|
|
76
|
+
const at = spec.lastIndexOf('@');
|
|
77
|
+
if (at > 0) {
|
|
78
|
+
const name = spec.slice(0, at);
|
|
79
|
+
const version = spec.slice(at + 1);
|
|
80
|
+
if (BARE_NAME_RE.test(name) && version !== '' && !version.includes('/')) {
|
|
81
|
+
return { kind: 'versioned', npmSpec: spec, dirName: name };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return { kind: 'refused', reason: `unrecognized install spec: ${spec}`, hint: twoCommandHint(spec) };
|
|
86
|
+
}
|
package/src/known-flags.ts
CHANGED
|
@@ -38,6 +38,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
38
38
|
'candidates',
|
|
39
39
|
'canonical',
|
|
40
40
|
'category',
|
|
41
|
+
'channel',
|
|
41
42
|
'check',
|
|
42
43
|
'claim-check',
|
|
43
44
|
'claude-bin',
|
|
@@ -52,6 +53,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
52
53
|
'confirmed',
|
|
53
54
|
'context-only',
|
|
54
55
|
'corroborate',
|
|
56
|
+
'count-project',
|
|
55
57
|
'day',
|
|
56
58
|
'deep',
|
|
57
59
|
'default-family',
|
|
@@ -62,6 +64,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
62
64
|
'dir',
|
|
63
65
|
'domain',
|
|
64
66
|
'done',
|
|
67
|
+
'draft',
|
|
65
68
|
'dry-run',
|
|
66
69
|
'effect',
|
|
67
70
|
'effort',
|
|
@@ -132,6 +135,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
132
135
|
'margin',
|
|
133
136
|
'mark',
|
|
134
137
|
'max',
|
|
138
|
+
'max-per-day',
|
|
135
139
|
'max-wall-clock',
|
|
136
140
|
'memory',
|
|
137
141
|
'mock',
|
|
@@ -142,6 +146,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
142
146
|
'n',
|
|
143
147
|
'name',
|
|
144
148
|
'name-only',
|
|
149
|
+
'night',
|
|
145
150
|
'no-audit',
|
|
146
151
|
'no-decorate',
|
|
147
152
|
'no-dry-run',
|
|
@@ -183,6 +188,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
183
188
|
'porcelain',
|
|
184
189
|
'preset',
|
|
185
190
|
'pretty',
|
|
191
|
+
'preview',
|
|
186
192
|
'project',
|
|
187
193
|
'promote',
|
|
188
194
|
'proposal',
|
|
@@ -197,6 +203,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
197
203
|
'recalled',
|
|
198
204
|
'reconcile',
|
|
199
205
|
'record-provisional',
|
|
206
|
+
'refresh-publishes',
|
|
200
207
|
'registry',
|
|
201
208
|
'reinforce',
|
|
202
209
|
'remove',
|
|
@@ -222,6 +229,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
222
229
|
'seed',
|
|
223
230
|
'select',
|
|
224
231
|
'semantic',
|
|
232
|
+
'send',
|
|
225
233
|
'session',
|
|
226
234
|
'sessions-dir',
|
|
227
235
|
'short',
|
|
@@ -274,6 +282,7 @@ export const KNOWN_CLI_FLAGS: readonly string[] = [
|
|
|
274
282
|
'week',
|
|
275
283
|
'weekly',
|
|
276
284
|
'window-days',
|
|
285
|
+
'window',
|
|
277
286
|
'with-pairs',
|
|
278
287
|
'with-references',
|
|
279
288
|
'work-order',
|