@hydranium/cli 1.0.0-next.30 → 1.0.0-next.300
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/README.md +75 -204
- package/bin/hydranium-cli.js +13 -0
- package/heap-analysis/heap/core/load.mjs +2 -2
- package/lib/cli-version.js.map +1 -1
- package/lib/cli.js +7 -2
- package/lib/cli.js.map +1 -1
- package/lib/commands/analyze-heap-args.js.map +1 -1
- package/lib/commands/analyze-heap.d.ts +3 -0
- package/lib/commands/analyze-heap.d.ts.map +1 -1
- package/lib/commands/analyze-heap.js +2 -1
- package/lib/commands/analyze-heap.js.map +1 -1
- package/lib/commands/ast-ground-truth-args.d.ts +3 -2
- package/lib/commands/ast-ground-truth-args.d.ts.map +1 -1
- package/lib/commands/ast-ground-truth-args.js +11 -9
- package/lib/commands/ast-ground-truth-args.js.map +1 -1
- package/lib/commands/ast-ground-truth-driver.js +2 -1
- package/lib/commands/ast-ground-truth-driver.js.map +1 -1
- package/lib/commands/ast-ground-truth.js +1 -1
- package/lib/commands/ast-ground-truth.js.map +1 -1
- package/lib/commands/client-session.d.ts +17 -0
- package/lib/commands/client-session.d.ts.map +1 -0
- package/lib/commands/client-session.js +27 -0
- package/lib/commands/client-session.js.map +1 -0
- package/lib/commands/create-args.d.ts +17 -0
- package/lib/commands/create-args.d.ts.map +1 -0
- package/lib/commands/create-args.js +53 -0
- package/lib/commands/create-args.js.map +1 -0
- package/lib/commands/create.d.ts +38 -0
- package/lib/commands/create.d.ts.map +1 -0
- package/lib/commands/create.js +43 -0
- package/lib/commands/create.js.map +1 -0
- package/lib/commands/delete-args.d.ts +17 -0
- package/lib/commands/delete-args.d.ts.map +1 -0
- package/lib/commands/delete-args.js +49 -0
- package/lib/commands/delete-args.js.map +1 -0
- package/lib/commands/delete.d.ts +30 -0
- package/lib/commands/delete.d.ts.map +1 -0
- package/lib/commands/delete.js +32 -0
- package/lib/commands/delete.js.map +1 -0
- package/lib/commands/generate-ast-builder.d.ts +49 -0
- package/lib/commands/generate-ast-builder.d.ts.map +1 -0
- package/lib/commands/generate-ast-builder.js +200 -0
- package/lib/commands/generate-ast-builder.js.map +1 -0
- package/lib/commands/generate-transfer-model-args.d.ts.map +1 -1
- package/lib/commands/generate-transfer-model-args.js +11 -1
- package/lib/commands/generate-transfer-model-args.js.map +1 -1
- package/lib/commands/generate-transfer-model-config.d.ts.map +1 -1
- package/lib/commands/generate-transfer-model-config.js +6 -3
- package/lib/commands/generate-transfer-model-config.js.map +1 -1
- package/lib/commands/generate-transfer-model.d.ts +9 -0
- package/lib/commands/generate-transfer-model.d.ts.map +1 -1
- package/lib/commands/generate-transfer-model.js +18 -4
- package/lib/commands/generate-transfer-model.js.map +1 -1
- package/lib/commands/harness-args.d.ts +44 -42
- package/lib/commands/harness-args.d.ts.map +1 -1
- package/lib/commands/harness-args.js +109 -27
- package/lib/commands/harness-args.js.map +1 -1
- package/lib/commands/headless-harness.d.ts +37 -20
- package/lib/commands/headless-harness.d.ts.map +1 -1
- package/lib/commands/headless-harness.js +68 -17
- package/lib/commands/headless-harness.js.map +1 -1
- package/lib/commands/init-args.js +6 -6
- package/lib/commands/init-args.js.map +1 -1
- package/lib/commands/init-prompt.d.ts.map +1 -1
- package/lib/commands/init-templates.d.ts +8 -10
- package/lib/commands/init-templates.d.ts.map +1 -1
- package/lib/commands/init-templates.js +261 -167
- package/lib/commands/init-templates.js.map +1 -1
- package/lib/commands/init-wizard.js +4 -4
- package/lib/commands/init-wizard.js.map +1 -1
- package/lib/commands/init-workspace.d.ts +13 -3
- package/lib/commands/init-workspace.d.ts.map +1 -1
- package/lib/commands/init-workspace.js +21 -6
- package/lib/commands/init-workspace.js.map +1 -1
- package/lib/commands/init.d.ts +16 -10
- package/lib/commands/init.d.ts.map +1 -1
- package/lib/commands/init.js +17 -15
- package/lib/commands/init.js.map +1 -1
- package/lib/commands/lint-grammar-args.d.ts +3 -2
- package/lib/commands/lint-grammar-args.d.ts.map +1 -1
- package/lib/commands/lint-grammar-args.js +13 -10
- package/lib/commands/lint-grammar-args.js.map +1 -1
- package/lib/commands/lint-grammar-driver.js +2 -1
- package/lib/commands/lint-grammar-driver.js.map +1 -1
- package/lib/commands/lint-grammar-report.js.map +1 -1
- package/lib/commands/lint-grammar.js +1 -1
- package/lib/commands/lint-grammar.js.map +1 -1
- package/lib/commands/measure-memory-args.d.ts +3 -2
- package/lib/commands/measure-memory-args.d.ts.map +1 -1
- package/lib/commands/measure-memory-args.js +22 -11
- package/lib/commands/measure-memory-args.js.map +1 -1
- package/lib/commands/measure-memory-driver.js +5 -3
- package/lib/commands/measure-memory-driver.js.map +1 -1
- package/lib/commands/measure-memory.js +1 -1
- package/lib/commands/measure-memory.js.map +1 -1
- package/lib/commands/model-docs-args.d.ts +4 -3
- package/lib/commands/model-docs-args.d.ts.map +1 -1
- package/lib/commands/model-docs-args.js +12 -10
- package/lib/commands/model-docs-args.js.map +1 -1
- package/lib/commands/model-docs-driver.js +2 -1
- package/lib/commands/model-docs-driver.js.map +1 -1
- package/lib/commands/model-docs.js +1 -1
- package/lib/commands/model-docs.js.map +1 -1
- package/lib/commands/projects-args.d.ts.map +1 -1
- package/lib/commands/projects-args.js +5 -5
- package/lib/commands/projects-args.js.map +1 -1
- package/lib/commands/projects.d.ts +3 -4
- package/lib/commands/projects.d.ts.map +1 -1
- package/lib/commands/projects.js +2 -2
- package/lib/commands/projects.js.map +1 -1
- package/lib/commands/query-args.d.ts.map +1 -1
- package/lib/commands/query-args.js +5 -5
- package/lib/commands/query-args.js.map +1 -1
- package/lib/commands/query.d.ts +3 -4
- package/lib/commands/query.d.ts.map +1 -1
- package/lib/commands/query.js +2 -2
- package/lib/commands/query.js.map +1 -1
- package/lib/commands/reflect-args.d.ts +3 -2
- package/lib/commands/reflect-args.d.ts.map +1 -1
- package/lib/commands/reflect-args.js +13 -10
- package/lib/commands/reflect-args.js.map +1 -1
- package/lib/commands/reflect-driver.js +2 -1
- package/lib/commands/reflect-driver.js.map +1 -1
- package/lib/commands/reflect-report.js.map +1 -1
- package/lib/commands/reflect.js +1 -1
- package/lib/commands/reflect.js.map +1 -1
- package/lib/commands/save-args.d.ts.map +1 -1
- package/lib/commands/save-args.js +7 -4
- package/lib/commands/save-args.js.map +1 -1
- package/lib/commands/save.d.ts +8 -4
- package/lib/commands/save.d.ts.map +1 -1
- package/lib/commands/save.js +12 -23
- package/lib/commands/save.js.map +1 -1
- package/lib/commands/validate-args.d.ts +3 -2
- package/lib/commands/validate-args.d.ts.map +1 -1
- package/lib/commands/validate-args.js +13 -10
- package/lib/commands/validate-args.js.map +1 -1
- package/lib/commands/validate-driver.js +2 -1
- package/lib/commands/validate-driver.js.map +1 -1
- package/lib/commands/validate-report.js.map +1 -1
- package/lib/commands/validate.js +1 -1
- package/lib/commands/validate.js.map +1 -1
- package/lib/commands/watch-args.d.ts.map +1 -1
- package/lib/commands/watch-args.js +6 -4
- package/lib/commands/watch-args.js.map +1 -1
- package/lib/commands/watch.d.ts +3 -4
- package/lib/commands/watch.d.ts.map +1 -1
- package/lib/commands/watch.js +20 -2
- package/lib/commands/watch.js.map +1 -1
- package/lib/driver-heap.d.ts +52 -0
- package/lib/driver-heap.d.ts.map +1 -0
- package/lib/driver-heap.js +51 -0
- package/lib/driver-heap.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/log-level.d.ts +21 -11
- package/lib/log-level.d.ts.map +1 -1
- package/lib/log-level.js +25 -14
- package/lib/log-level.js.map +1 -1
- package/lib/spawn-data-server.d.ts +9 -4
- package/lib/spawn-data-server.d.ts.map +1 -1
- package/lib/spawn-data-server.js +5 -4
- package/lib/spawn-data-server.js.map +1 -1
- package/lib/stderr-connection-logger.d.ts +12 -0
- package/lib/stderr-connection-logger.d.ts.map +1 -0
- package/lib/stderr-connection-logger.js +16 -0
- package/lib/stderr-connection-logger.js.map +1 -0
- package/lib/testing/echo-server.js +9 -1
- package/lib/testing/echo-server.js.map +1 -1
- package/package.json +50 -39
- package/src/cli.ts +7 -2
- package/src/commands/analyze-heap.ts +4 -1
- package/src/commands/ast-ground-truth-args.ts +15 -12
- package/src/commands/ast-ground-truth-driver.ts +2 -1
- package/src/commands/ast-ground-truth.ts +1 -1
- package/src/commands/client-session.ts +33 -0
- package/src/commands/create-args.ts +68 -0
- package/src/commands/create.ts +83 -0
- package/src/commands/delete-args.ts +64 -0
- package/src/commands/delete.ts +61 -0
- package/src/commands/generate-ast-builder.ts +246 -0
- package/src/commands/generate-transfer-model-args.ts +11 -1
- package/src/commands/generate-transfer-model-config.ts +6 -3
- package/src/commands/generate-transfer-model.ts +27 -4
- package/src/commands/harness-args.ts +99 -31
- package/src/commands/headless-harness.ts +86 -26
- package/src/commands/init-args.ts +6 -6
- package/src/commands/init-templates.ts +272 -169
- package/src/commands/init-wizard.ts +4 -4
- package/src/commands/init-workspace.ts +31 -7
- package/src/commands/init.ts +36 -26
- package/src/commands/lint-grammar-args.ts +17 -13
- package/src/commands/lint-grammar-driver.ts +2 -1
- package/src/commands/lint-grammar.ts +1 -1
- package/src/commands/measure-memory-args.ts +27 -14
- package/src/commands/measure-memory-driver.ts +5 -3
- package/src/commands/measure-memory.ts +1 -1
- package/src/commands/model-docs-args.ts +16 -13
- package/src/commands/model-docs-driver.ts +2 -1
- package/src/commands/model-docs.ts +1 -1
- package/src/commands/projects-args.ts +5 -4
- package/src/commands/projects.ts +4 -6
- package/src/commands/query-args.ts +5 -4
- package/src/commands/query.ts +4 -6
- package/src/commands/reflect-args.ts +17 -13
- package/src/commands/reflect-driver.ts +2 -1
- package/src/commands/reflect.ts +1 -1
- package/src/commands/save-args.ts +7 -3
- package/src/commands/save.ts +24 -27
- package/src/commands/validate-args.ts +17 -13
- package/src/commands/validate-driver.ts +2 -1
- package/src/commands/validate.ts +1 -1
- package/src/commands/watch-args.ts +6 -3
- package/src/commands/watch.ts +28 -7
- package/src/driver-heap.ts +65 -0
- package/src/index.ts +3 -0
- package/src/log-level.ts +42 -14
- package/src/spawn-data-server.ts +17 -5
- package/src/stderr-connection-logger.ts +18 -0
- package/src/testing/echo-server.ts +11 -2
|
@@ -219,10 +219,10 @@ async function askHeads(prompt: PromptPort): Promise<InitHead[]> {
|
|
|
219
219
|
/**
|
|
220
220
|
* Mark the grammar a scaffolded diagram edits.
|
|
221
221
|
*
|
|
222
|
-
* Only a real question with `glsp` on AND several grammars:
|
|
223
|
-
*
|
|
224
|
-
* that answer already — so asking would offer a choice
|
|
225
|
-
* silently overrule.
|
|
222
|
+
* Only a real question with `glsp` on AND several grammars: the scaffolded
|
|
223
|
+
* diagram is typed over one grammar's model, and with a single grammar the
|
|
224
|
+
* scaffolder derives that answer already — so asking would offer a choice
|
|
225
|
+
* whose "no" it would silently overrule.
|
|
226
226
|
*/
|
|
227
227
|
async function askDiagramGrammar(
|
|
228
228
|
prompt: PromptPort,
|
|
@@ -186,10 +186,14 @@ export interface WorkspaceDetection {
|
|
|
186
186
|
readonly baseTsconfig?: string;
|
|
187
187
|
/** That tsconfig's `compilerOptions`, so the emitted one can drop what it inherits. */
|
|
188
188
|
readonly baseCompilerOptions?: Readonly<Record<string, JsonValue>>;
|
|
189
|
-
/** The root
|
|
189
|
+
/** The root formatter config's `printWidth`, so emitted sources wrap where the repo wraps. */
|
|
190
190
|
readonly printWidth?: number;
|
|
191
191
|
/** Filename of the root eslint config, when there is one. Absent means the repo does not lint. */
|
|
192
192
|
readonly eslintConfig?: string;
|
|
193
|
+
/** Filename of the root Oxlint config, when present. */
|
|
194
|
+
readonly oxlintConfig?: string;
|
|
195
|
+
/** The npm version the root's `packageManager` field declares, when it names npm. */
|
|
196
|
+
readonly packageManagerNpm?: string;
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
/**
|
|
@@ -339,7 +343,7 @@ export function findBaseTsconfig(
|
|
|
339
343
|
}
|
|
340
344
|
|
|
341
345
|
/**
|
|
342
|
-
* The repo's
|
|
346
|
+
* The repo's formatter `printWidth`, so the emitted sources wrap where the repo
|
|
343
347
|
* wraps instead of at the scaffold's own default.
|
|
344
348
|
*
|
|
345
349
|
* **Why this is worth detecting at all.** There is no width that is stable for
|
|
@@ -360,19 +364,21 @@ export function findBaseTsconfig(
|
|
|
360
364
|
* adopter's formatter rewraps on first commit. So a heuristic that is usually
|
|
361
365
|
* right strictly improves on no detection, and can break nothing.
|
|
362
366
|
*/
|
|
363
|
-
export function
|
|
367
|
+
export function findFormatterPrintWidth(rootDir: string, probe: WorkspaceProbe): number | undefined {
|
|
364
368
|
const manifest = probe.readJson(path.join(rootDir, 'package.json'));
|
|
365
369
|
if (isJsonObject(manifest) && isJsonObject(manifest.prettier) && typeof manifest.prettier.printWidth === 'number') {
|
|
366
370
|
return manifest.prettier.printWidth;
|
|
367
371
|
}
|
|
368
372
|
const present = probe.listFiles(rootDir);
|
|
369
|
-
for (const file of present.filter(name => name === '.prettierrc' || name === '.prettierrc.json')) {
|
|
373
|
+
for (const file of present.filter(name => name === '.oxfmtrc.json' || name === '.prettierrc' || name === '.prettierrc.json')) {
|
|
370
374
|
const parsed = probe.readJson(path.join(rootDir, file));
|
|
371
375
|
if (isJsonObject(parsed) && typeof parsed.printWidth === 'number') {
|
|
372
376
|
return parsed.printWidth;
|
|
373
377
|
}
|
|
374
378
|
}
|
|
375
|
-
for (const file of present.filter(name =>
|
|
379
|
+
for (const file of present.filter(name =>
|
|
380
|
+
/^(\.prettierrc\.[cm]?[jt]s|prettier\.config\.[cm]?[jt]s|oxfmt\.config\.[cm]?[jt]s)$/.test(name)
|
|
381
|
+
)) {
|
|
376
382
|
const width = /\bprintWidth\s*:\s*(\d+)/.exec(probe.readText(path.join(rootDir, file)) ?? '');
|
|
377
383
|
if (width) {
|
|
378
384
|
return Number(width[1]);
|
|
@@ -398,6 +404,22 @@ export function findEslintConfig(rootDir: string, probe: WorkspaceProbe): string
|
|
|
398
404
|
return probe.listFiles(rootDir).find(name => /^eslint\.config\.[cm]?[jt]s$/.test(name) || /^\.eslintrc(\..+)?$/.test(name));
|
|
399
405
|
}
|
|
400
406
|
|
|
407
|
+
/** Detect Oxlint without evaluating executable configuration files. */
|
|
408
|
+
export function findOxlintConfig(rootDir: string, probe: WorkspaceProbe): string | undefined {
|
|
409
|
+
return probe.listFiles(rootDir).find(name => /^(oxlint\.config\.[cm]?[jt]s|\.oxlintrc\.jsonc?)$/.test(name));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/** The npm version the root's `packageManager` field declares (`npm@11.15.0` gives `11.15.0`), when it names npm. */
|
|
413
|
+
export function findPackageManagerNpm(rootDir: string, probe: WorkspaceProbe): string | undefined {
|
|
414
|
+
const manifest = probe.readJson(path.join(rootDir, 'package.json'));
|
|
415
|
+
return parseNpmVersion(isJsonObject(manifest) && typeof manifest.packageManager === 'string' ? manifest.packageManager : undefined);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** The npm version, prerelease included, of a `packageManager` field (`npm@…`) or a user agent (`npm/…`); undefined for another tool. */
|
|
419
|
+
export function parseNpmVersion(spec: string | undefined): string | undefined {
|
|
420
|
+
return /^npm[@/](\d+\.\d+\.\d+(?:-[\w.]+)?)/.exec(spec ?? '')?.[1];
|
|
421
|
+
}
|
|
422
|
+
|
|
401
423
|
/** POSIX-style relative path, which is what both `extends` and `--prefix` want on every platform. */
|
|
402
424
|
function posixRelative(from: string, to: string): string {
|
|
403
425
|
return path.relative(from, to).split(path.sep).join('/');
|
|
@@ -436,7 +458,9 @@ export function detectWorkspace(targetDir: string, probe: WorkspaceProbe): Works
|
|
|
436
458
|
scope: inferPackageScope(rootDir, workspaces, probe),
|
|
437
459
|
baseTsconfig: base && posixRelative(absoluteTarget, path.join(rootDir, base.file)),
|
|
438
460
|
baseCompilerOptions: base?.compilerOptions,
|
|
439
|
-
printWidth:
|
|
440
|
-
eslintConfig: findEslintConfig(rootDir, probe)
|
|
461
|
+
printWidth: findFormatterPrintWidth(rootDir, probe),
|
|
462
|
+
eslintConfig: findEslintConfig(rootDir, probe),
|
|
463
|
+
oxlintConfig: findOxlintConfig(rootDir, probe),
|
|
464
|
+
packageManagerNpm: findPackageManagerNpm(rootDir, probe)
|
|
441
465
|
};
|
|
442
466
|
}
|
package/src/commands/init.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import * as fs from 'node:fs';
|
|
11
11
|
import * as path from 'node:path';
|
|
12
|
-
import { buildInitTemplates, readFrameworkVersion,
|
|
13
|
-
import { createNodeWorkspaceProbe, detectWorkspace, type JsonValue, type WorkspaceProbe } from './init-workspace.js';
|
|
12
|
+
import { buildInitTemplates, readFrameworkVersion, workspaceRootPins } from './init-templates.js';
|
|
13
|
+
import { createNodeWorkspaceProbe, detectWorkspace, parseNpmVersion, type JsonValue, type WorkspaceProbe } from './init-workspace.js';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* The protocol heads a scaffold can start, in composition order.
|
|
@@ -55,10 +55,9 @@ export interface InitGrammarSpec {
|
|
|
55
55
|
/**
|
|
56
56
|
* Scaffold a GLSP diagram for this grammar. Requires the `glsp` head.
|
|
57
57
|
*
|
|
58
|
-
* Per grammar rather than per project because
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* with no diagram sitting on the same server is the normal case.
|
|
58
|
+
* Per grammar rather than per project because the scaffolded diagram is typed
|
|
59
|
+
* over one grammar's model, and a grammar with no diagram sitting on the same
|
|
60
|
+
* server is the normal case.
|
|
62
61
|
*/
|
|
63
62
|
readonly diagram?: boolean;
|
|
64
63
|
}
|
|
@@ -128,10 +127,16 @@ export interface InitWorkspacePlacement {
|
|
|
128
127
|
readonly baseTsconfig?: string;
|
|
129
128
|
/** That tsconfig's `compilerOptions`, so the emitted one can omit what it would inherit unchanged. */
|
|
130
129
|
readonly baseCompilerOptions?: Readonly<Record<string, JsonValue>>;
|
|
131
|
-
/** The workspace's
|
|
130
|
+
/** The workspace's formatter `printWidth`, so emitted sources wrap where the repo wraps. */
|
|
132
131
|
readonly printWidth?: number;
|
|
133
132
|
/** Filename of the workspace's eslint config; its presence is what makes the scaffold emit a `lint` script. */
|
|
134
133
|
readonly eslintConfig?: string;
|
|
134
|
+
/** Filename of the workspace Oxlint config, when present. */
|
|
135
|
+
readonly oxlintConfig?: string;
|
|
136
|
+
/** The npm version the workspace root's `packageManager` declares; with {@link npmVersion} it decides the scaffold's `vitest` range. */
|
|
137
|
+
readonly packageManagerNpm?: string;
|
|
138
|
+
/** The npm running `init`, when known. npm does not enforce `packageManager`, so a declaration alone cannot lift `vitest`. */
|
|
139
|
+
readonly npmVersion?: string;
|
|
135
140
|
}
|
|
136
141
|
|
|
137
142
|
/**
|
|
@@ -226,10 +231,9 @@ export interface InitCommandOptions {
|
|
|
226
231
|
readonly force?: boolean;
|
|
227
232
|
/**
|
|
228
233
|
* Scaffold a member of the surrounding npm workspace: extend its base
|
|
229
|
-
* tsconfig
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* project the caller did not ask for.
|
|
234
|
+
* tsconfig and address the package by `--prefix` in the scripts it prints
|
|
235
|
+
* back at itself. Errors when no ancestor declares `workspaces`, rather than
|
|
236
|
+
* silently degrading to a standalone project the caller did not ask for.
|
|
233
237
|
*/
|
|
234
238
|
readonly monorepo?: boolean;
|
|
235
239
|
/** npm scope for the package name, e.g. `@acme`. */
|
|
@@ -298,8 +302,9 @@ function resolveGrammar(spec: InitGrammarSpec, projectId: string, qualify: boole
|
|
|
298
302
|
*
|
|
299
303
|
* With the `glsp` head on and nothing marked, a lone grammar is unambiguous and
|
|
300
304
|
* is taken as the diagram's; with several it is a real choice, so it is required
|
|
301
|
-
* rather than guessed —
|
|
302
|
-
*
|
|
305
|
+
* rather than guessed — the scaffolded state, storage and GModel factory are
|
|
306
|
+
* typed over the chosen grammar's model, so a wrong guess emits a diagram of
|
|
307
|
+
* the wrong model.
|
|
303
308
|
*/
|
|
304
309
|
function resolveDiagrams(specs: readonly InitGrammarSpec[], heads: readonly InitHead[]): boolean[] {
|
|
305
310
|
const marked = specs.map(spec => spec.diagram === true);
|
|
@@ -432,6 +437,8 @@ export interface InitPackagingOptions {
|
|
|
432
437
|
readonly scope?: string;
|
|
433
438
|
readonly public?: boolean;
|
|
434
439
|
readonly probe?: WorkspaceProbe;
|
|
440
|
+
/** The npm running `init`. Defaults to the one `npm_config_user_agent` names, which `npx` and `npm run` set. */
|
|
441
|
+
readonly npmVersion?: string;
|
|
435
442
|
}
|
|
436
443
|
|
|
437
444
|
/**
|
|
@@ -466,7 +473,10 @@ export function resolveInitPackaging(targetDir: string, options: InitPackagingOp
|
|
|
466
473
|
baseTsconfig: detection.baseTsconfig,
|
|
467
474
|
baseCompilerOptions: detection.baseCompilerOptions,
|
|
468
475
|
printWidth: detection.printWidth,
|
|
469
|
-
eslintConfig: detection.eslintConfig
|
|
476
|
+
eslintConfig: detection.eslintConfig,
|
|
477
|
+
oxlintConfig: detection.oxlintConfig,
|
|
478
|
+
packageManagerNpm: detection.packageManagerNpm,
|
|
479
|
+
npmVersion: options.npmVersion ?? parseNpmVersion(process.env.npm_config_user_agent)
|
|
470
480
|
}
|
|
471
481
|
};
|
|
472
482
|
}
|
|
@@ -513,12 +523,13 @@ export function runInit(options: InitCommandOptions): void {
|
|
|
513
523
|
} else {
|
|
514
524
|
write(' No root tsconfig carries compilerOptions, so the emitted one stands alone.\n');
|
|
515
525
|
}
|
|
516
|
-
write(" .gitignore holds `syntaxes/` only — the workspace root's covers the rest.\n");
|
|
517
526
|
if (detection.printWidth !== undefined) {
|
|
518
|
-
write(` Sources wrapped at ${detection.printWidth} columns, from ${detection.rootDir}'s
|
|
527
|
+
write(` Sources wrapped at ${detection.printWidth} columns, from ${detection.rootDir}'s formatter config.\n`);
|
|
519
528
|
}
|
|
520
|
-
if (detection.eslintConfig !== undefined) {
|
|
521
|
-
write(
|
|
529
|
+
if (detection.oxlintConfig !== undefined || detection.eslintConfig !== undefined) {
|
|
530
|
+
write(
|
|
531
|
+
` A lint script was added — ${detection.oxlintConfig ?? detection.eslintConfig} says this repo lints. Adjust it if your invocation differs.\n`
|
|
532
|
+
);
|
|
522
533
|
}
|
|
523
534
|
// Printed rather than applied: `init` writes inside the target directory
|
|
524
535
|
// and nowhere else, so a scaffold can never surprise-edit a manifest that
|
|
@@ -527,8 +538,13 @@ export function runInit(options: InitCommandOptions): void {
|
|
|
527
538
|
write(` Add this to "workspaces" in ${path.join(detection.rootDir, 'package.json')}:\n`);
|
|
528
539
|
write(` "${detection.targetPath}"\n`);
|
|
529
540
|
} else {
|
|
530
|
-
write(` Already covered by the "${detection.coveredBy}" workspaces entry
|
|
541
|
+
write(` Already covered by the "${detection.coveredBy}" workspaces entry.\n`);
|
|
531
542
|
}
|
|
543
|
+
const pins = workspaceRootPins(composition.heads).map(([name, version]) => ` "${name}": "${version}"`);
|
|
544
|
+
write(
|
|
545
|
+
` Add these to "devDependencies" in ${path.join(detection.rootDir, 'package.json')}, so another member's version of one ` +
|
|
546
|
+
`cannot displace the copy this package shares with the framework:\n${pins.join(',\n')}\n`
|
|
547
|
+
);
|
|
532
548
|
if (composition.packaging.scope === undefined && detection.scope !== undefined) {
|
|
533
549
|
write(` Sibling packages all use the "${detection.scope}" scope; pass --scope ${detection.scope} to match them.\n`);
|
|
534
550
|
}
|
|
@@ -536,13 +552,7 @@ export function runInit(options: InitCommandOptions): void {
|
|
|
536
552
|
write('\n');
|
|
537
553
|
write('Next steps:\n');
|
|
538
554
|
write(` cd ${options.targetDir}\n`);
|
|
539
|
-
|
|
540
|
-
// `UNPUBLISHED_FRAMEWORK_VERSION`.
|
|
541
|
-
write(
|
|
542
|
-
composition.frameworkVersion === UNPUBLISHED_FRAMEWORK_VERSION
|
|
543
|
-
? ' npm install # 404s until @hydranium/* is published — see README\n'
|
|
544
|
-
: ' npm install\n'
|
|
545
|
-
);
|
|
555
|
+
write(' npm install\n');
|
|
546
556
|
write(' npm run build # langium generate + tsc\n');
|
|
547
557
|
write(' npm test # the scaffolded DI-composition test\n');
|
|
548
558
|
// `npx`, not a bare invocation: `@hydranium/cli` is a devDependency of the
|
|
@@ -9,34 +9,36 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
exitWithUsage,
|
|
12
|
+
HARNESS_VALUE_FLAGS,
|
|
12
13
|
helpRequested,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
importHelpLines,
|
|
15
|
+
LOG_VALUE_FLAGS,
|
|
16
|
+
logHelpLines,
|
|
17
|
+
logOptions,
|
|
16
18
|
parseHarnessArgs,
|
|
17
19
|
printHelp,
|
|
18
|
-
SERVICES_FLAG,
|
|
19
20
|
type UsageError
|
|
20
21
|
} from './harness-args.js';
|
|
21
22
|
import { runLintGrammar, type LintGrammarCommandOptions } from './lint-grammar.js';
|
|
22
23
|
|
|
23
|
-
const VALUE_FLAGS = [
|
|
24
|
+
const VALUE_FLAGS = [...LOG_VALUE_FLAGS] as const;
|
|
24
25
|
const BOOL_FLAGS = ['--strict', '--json'] as const;
|
|
25
26
|
const REPEATABLE_VALUE_FLAGS = ['--name-property'] as const;
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Every flag `lint-grammar` accepts, derived from the sets the parser is handed
|
|
29
|
-
* so the list cannot claim a flag the parser would reject.
|
|
30
|
-
* consumed by the shared harness parser itself,
|
|
30
|
+
* so the list cannot claim a flag the parser would reject.
|
|
31
|
+
* {@link HARNESS_VALUE_FLAGS} are consumed by the shared harness parser itself,
|
|
32
|
+
* so they are in neither set.
|
|
31
33
|
*/
|
|
32
|
-
export const LINT_GRAMMAR_FLAGS: readonly string[] = [
|
|
34
|
+
export const LINT_GRAMMAR_FLAGS: readonly string[] = [...HARNESS_VALUE_FLAGS, ...REPEATABLE_VALUE_FLAGS, ...VALUE_FLAGS, ...BOOL_FLAGS];
|
|
33
35
|
|
|
34
36
|
/** The subset that takes a value, so `--help` in a value position reads as data. */
|
|
35
|
-
export const LINT_GRAMMAR_VALUE_FLAGS: readonly string[] = [
|
|
37
|
+
export const LINT_GRAMMAR_VALUE_FLAGS: readonly string[] = [...HARNESS_VALUE_FLAGS, ...REPEATABLE_VALUE_FLAGS, ...VALUE_FLAGS];
|
|
36
38
|
|
|
37
39
|
/** The `--help` text, as data, held to {@link LINT_GRAMMAR_FLAGS} by a test. */
|
|
38
40
|
export const LINT_GRAMMAR_HELP: readonly string[] = [
|
|
39
|
-
'Usage: hydranium-cli lint-grammar --services <module> [--name-property <p>]... [--strict] [--json] [--log-level <lvl>]',
|
|
41
|
+
'Usage: hydranium-cli lint-grammar --services <module> [--import <specifier>]... [--name-property <p>]... [--strict] [--json] [--log-level <lvl>] [--log-file <file>] [--log-file-level <lvl>]',
|
|
40
42
|
'',
|
|
41
43
|
"Check a head's grammar against the framework's conventions — a CI gate: the",
|
|
42
44
|
'process exits non-zero when a violation is found. Read-only: no workspace is',
|
|
@@ -48,25 +50,27 @@ export const LINT_GRAMMAR_HELP: readonly string[] = [
|
|
|
48
50
|
'',
|
|
49
51
|
'Options:',
|
|
50
52
|
' --services <module> ESM module exporting `createServices(): { shared }` (required).',
|
|
53
|
+
...importHelpLines(23),
|
|
51
54
|
' --name-property <p> Property that satisfies the nameability convention',
|
|
52
55
|
' (repeatable). Default: name.',
|
|
53
56
|
' --strict Also fail (non-zero exit) on warnings, not only errors.',
|
|
54
57
|
' --json Emit the raw JSON result instead of the human report.',
|
|
55
|
-
|
|
58
|
+
...logHelpLines(23)
|
|
56
59
|
];
|
|
57
60
|
|
|
58
61
|
export function parseLintGrammarArgs(args: string[], onError: UsageError = exitWithUsage): LintGrammarCommandOptions {
|
|
59
|
-
const { servicesModule, options, values } = parseHarnessArgs(args, 'lint-grammar', VALUE_FLAGS, BOOL_FLAGS, {
|
|
62
|
+
const { servicesModule, imports, options, values } = parseHarnessArgs(args, 'lint-grammar', VALUE_FLAGS, BOOL_FLAGS, {
|
|
60
63
|
requireWorkspace: false,
|
|
61
64
|
repeatableValueFlags: REPEATABLE_VALUE_FLAGS,
|
|
62
65
|
onError
|
|
63
66
|
});
|
|
64
67
|
return {
|
|
65
68
|
servicesModule,
|
|
69
|
+
imports,
|
|
66
70
|
nameProperties: values['--name-property'],
|
|
67
71
|
strict: options['--strict'] === 'true',
|
|
68
72
|
json: options['--json'] === 'true',
|
|
69
|
-
|
|
73
|
+
...logOptions(options)
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* only spawned.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { describeError } from '@hydranium/protocol';
|
|
19
20
|
import { loadHeadlessContext } from './headless-harness.js';
|
|
20
21
|
import { formatLintReport, lintExitCode } from './lint-grammar-report.js';
|
|
21
22
|
|
|
@@ -78,6 +79,6 @@ async function main(argv: string[]): Promise<number> {
|
|
|
78
79
|
main(process.argv.slice(2))
|
|
79
80
|
.then(code => process.exit(code))
|
|
80
81
|
.catch((error: unknown) => {
|
|
81
|
-
console.error(
|
|
82
|
+
console.error(describeError(error));
|
|
82
83
|
process.exit(1);
|
|
83
84
|
});
|
|
@@ -53,5 +53,5 @@ export function buildLintGrammarDriverArgs(options: LintGrammarCommandOptions):
|
|
|
53
53
|
* `createServices` module, keeping the binary language-agnostic.
|
|
54
54
|
*/
|
|
55
55
|
export function runLintGrammar(options: LintGrammarCommandOptions): Promise<void> {
|
|
56
|
-
return runDriverChild([
|
|
56
|
+
return runDriverChild([DRIVER, ...buildLintGrammarDriverArgs(options)], options);
|
|
57
57
|
}
|
|
@@ -7,16 +7,19 @@
|
|
|
7
7
|
* SPDX-License-Identifier: MIT
|
|
8
8
|
********************************************************************************/
|
|
9
9
|
|
|
10
|
+
import { describeError } from '@hydranium/protocol';
|
|
10
11
|
import {
|
|
11
12
|
exitWithUsage,
|
|
13
|
+
HARNESS_VALUE_FLAGS,
|
|
12
14
|
helpRequested,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
importHelpLines,
|
|
16
|
+
LOG_FILE_FLAG,
|
|
17
|
+
LOG_VALUE_FLAGS,
|
|
18
|
+
logHelpLines,
|
|
19
|
+
logOptions,
|
|
16
20
|
numericOption,
|
|
17
21
|
parseHarnessArgs,
|
|
18
22
|
printHelp,
|
|
19
|
-
SERVICES_FLAG,
|
|
20
23
|
type UsageError
|
|
21
24
|
} from './harness-args.js';
|
|
22
25
|
import { parseProfileDimensions, runMeasureMemory, type MeasureMemoryCommandOptions } from './measure-memory.js';
|
|
@@ -29,23 +32,24 @@ const VALUE_FLAGS = [
|
|
|
29
32
|
'--snapshot-path',
|
|
30
33
|
'--profile',
|
|
31
34
|
'--session-out',
|
|
32
|
-
|
|
35
|
+
...LOG_VALUE_FLAGS
|
|
33
36
|
] as const;
|
|
34
37
|
const BOOL_FLAGS = ['--snapshot', '--json'] as const;
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
40
|
* Every flag `measure-memory` accepts, derived from the sets the parser is
|
|
38
|
-
* handed so the list cannot claim a flag the parser would reject.
|
|
39
|
-
*
|
|
41
|
+
* handed so the list cannot claim a flag the parser would reject.
|
|
42
|
+
* {@link HARNESS_VALUE_FLAGS} are consumed by the shared harness parser itself,
|
|
43
|
+
* so they are in neither set.
|
|
40
44
|
*/
|
|
41
|
-
export const MEASURE_MEMORY_FLAGS: readonly string[] = [
|
|
45
|
+
export const MEASURE_MEMORY_FLAGS: readonly string[] = [...HARNESS_VALUE_FLAGS, ...VALUE_FLAGS, ...BOOL_FLAGS];
|
|
42
46
|
|
|
43
47
|
/** The subset that takes a value, so `--help` in a value position reads as data. */
|
|
44
|
-
export const MEASURE_MEMORY_VALUE_FLAGS: readonly string[] = [
|
|
48
|
+
export const MEASURE_MEMORY_VALUE_FLAGS: readonly string[] = [...HARNESS_VALUE_FLAGS, ...VALUE_FLAGS];
|
|
45
49
|
|
|
46
50
|
/** The `--help` text, as data, held to {@link MEASURE_MEMORY_FLAGS} by a test. */
|
|
47
51
|
export const MEASURE_MEMORY_HELP: readonly string[] = [
|
|
48
|
-
'Usage: hydranium-cli measure-memory --services <module> <workspace> [options]',
|
|
52
|
+
'Usage: hydranium-cli measure-memory --services <module> [--import <specifier>]... <workspace> [options]',
|
|
49
53
|
'',
|
|
50
54
|
'Measure model-store memory for a workspace. `<module>` is an ESM module that',
|
|
51
55
|
'exports a zero-arg `createServices(): { shared }` thunk (the head wires its own',
|
|
@@ -54,6 +58,7 @@ export const MEASURE_MEMORY_HELP: readonly string[] = [
|
|
|
54
58
|
'',
|
|
55
59
|
'Options:',
|
|
56
60
|
' --services <module> ESM module exporting `createServices(): { shared }` (required).',
|
|
61
|
+
...importHelpLines(22),
|
|
57
62
|
' <workspace> Workspace root (path or file URI) to build (required).',
|
|
58
63
|
' --edits <N> Rebuild-churn cycles to probe for retention. Default: 0 (skip).',
|
|
59
64
|
' --edit-docs <N> Documents to churn per cycle. Default: 25.',
|
|
@@ -67,11 +72,13 @@ export const MEASURE_MEMORY_HELP: readonly string[] = [
|
|
|
67
72
|
' --profile <dims> Capture sampled profiles around the build (+churn) into a',
|
|
68
73
|
' profiling session. Comma-separated: cpu,alloc,gc,eld,heap.',
|
|
69
74
|
' --session-out <dir> Parent directory for the profiling session folder (with --profile).',
|
|
75
|
+
' The session logs to its server.log at --log-file-level, else at',
|
|
76
|
+
' --log-level, else info; --log-file is refused beside --profile.',
|
|
70
77
|
' --json Emit the measurement as one JSON document instead of the',
|
|
71
78
|
' progress lines: documentCount, buildMs, emptyHeapBytes,',
|
|
72
79
|
' afterBuildHeapBytes, and churnGrowthBytes / snapshotPath /',
|
|
73
80
|
' profilingSession where the run produced them.',
|
|
74
|
-
|
|
81
|
+
...logHelpLines(22)
|
|
75
82
|
];
|
|
76
83
|
|
|
77
84
|
/**
|
|
@@ -91,15 +98,21 @@ function validatedProfile(csv: string | undefined, onError: UsageError): string
|
|
|
91
98
|
try {
|
|
92
99
|
parseProfileDimensions(csv);
|
|
93
100
|
} catch (err: unknown) {
|
|
94
|
-
onError(`Option --profile: ${
|
|
101
|
+
onError(`Option --profile: ${describeError(err)}`);
|
|
95
102
|
}
|
|
96
103
|
return csv;
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
export function parseMeasureMemoryArgs(args: string[], onError: UsageError = exitWithUsage): MeasureMemoryCommandOptions {
|
|
100
|
-
const { servicesModule, workspace, options } = parseHarnessArgs(args, 'measure-memory', VALUE_FLAGS, BOOL_FLAGS, { onError });
|
|
107
|
+
const { servicesModule, imports, workspace, options } = parseHarnessArgs(args, 'measure-memory', VALUE_FLAGS, BOOL_FLAGS, { onError });
|
|
108
|
+
// The profiling session points the log at its own `server.log`, which would
|
|
109
|
+
// replace the requested file without a word.
|
|
110
|
+
if (options['--profile'] !== undefined && options[LOG_FILE_FLAG] !== undefined) {
|
|
111
|
+
onError(`${LOG_FILE_FLAG} cannot be combined with --profile, which logs to the session's server.log`);
|
|
112
|
+
}
|
|
101
113
|
return {
|
|
102
114
|
servicesModule,
|
|
115
|
+
imports,
|
|
103
116
|
workspace,
|
|
104
117
|
editCycles: numericOption(options['--edits'], '--edits', onError),
|
|
105
118
|
editDocs: numericOption(options['--edit-docs'], '--edit-docs', onError),
|
|
@@ -110,7 +123,7 @@ export function parseMeasureMemoryArgs(args: string[], onError: UsageError = exi
|
|
|
110
123
|
profile: validatedProfile(options['--profile'], onError),
|
|
111
124
|
sessionOut: options['--session-out'],
|
|
112
125
|
json: options['--json'] === 'true',
|
|
113
|
-
|
|
126
|
+
...logOptions(options)
|
|
114
127
|
};
|
|
115
128
|
}
|
|
116
129
|
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
/*
|
|
11
11
|
* Spawned child of the `measure-memory` subcommand. Launched by the parent with
|
|
12
|
-
* `node --expose-gc
|
|
13
|
-
* so the underlying harness gets post-GC readings.
|
|
12
|
+
* `node [heap ceiling] --expose-gc <this> --services <module> <workspace> ...`
|
|
13
|
+
* so the underlying harness gets post-GC readings. The ceiling is whatever
|
|
14
|
+
* `driverHeapArgs` decides, which is nothing at all inside a container. It dynamic-imports the head's
|
|
14
15
|
* services module and runs the framework's `measureModelMemory`, streaming the
|
|
15
16
|
* baseline / after-build / churn lines to stdout. Never imported — only spawned.
|
|
16
17
|
*/
|
|
17
18
|
|
|
19
|
+
import { describeError } from '@hydranium/protocol';
|
|
18
20
|
import { loadHeadlessContext } from './headless-harness.js';
|
|
19
21
|
import { parseProfileDimensions } from './measure-memory.js';
|
|
20
22
|
|
|
@@ -123,6 +125,6 @@ async function main(argv: string[]): Promise<void> {
|
|
|
123
125
|
main(process.argv.slice(2))
|
|
124
126
|
.then(() => process.exit(0))
|
|
125
127
|
.catch((error: unknown) => {
|
|
126
|
-
console.error(
|
|
128
|
+
console.error(describeError(error));
|
|
127
129
|
process.exit(1);
|
|
128
130
|
});
|
|
@@ -139,5 +139,5 @@ export function buildDriverArgs(options: MeasureMemoryCommandOptions): string[]
|
|
|
139
139
|
* module and reports the baseline / after-build / churn lines on stdout.
|
|
140
140
|
*/
|
|
141
141
|
export function runMeasureMemory(options: MeasureMemoryCommandOptions): Promise<void> {
|
|
142
|
-
return runDriverChild(['--expose-gc',
|
|
142
|
+
return runDriverChild(['--expose-gc', DRIVER, ...buildDriverArgs(options)], options);
|
|
143
143
|
}
|
|
@@ -9,33 +9,35 @@
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
exitWithUsage,
|
|
12
|
+
HARNESS_VALUE_FLAGS,
|
|
12
13
|
helpRequested,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
importHelpLines,
|
|
15
|
+
LOG_VALUE_FLAGS,
|
|
16
|
+
logHelpLines,
|
|
17
|
+
logOptions,
|
|
16
18
|
parseHarnessArgs,
|
|
17
19
|
printHelp,
|
|
18
|
-
SERVICES_FLAG,
|
|
19
20
|
type UsageError
|
|
20
21
|
} from './harness-args.js';
|
|
21
22
|
import { OUT_FILE_FLAG } from './headless-harness.js';
|
|
22
23
|
import { runModelDocs, type ModelDocsCommandOptions } from './model-docs.js';
|
|
23
24
|
|
|
24
|
-
const VALUE_FLAGS = [OUT_FILE_FLAG,
|
|
25
|
+
const VALUE_FLAGS = [OUT_FILE_FLAG, ...LOG_VALUE_FLAGS] as const;
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
* Every flag `model-docs` accepts, derived from the sets the parser is handed
|
|
28
|
-
* the list cannot claim a flag the parser would reject.
|
|
29
|
-
* by the shared harness parser itself,
|
|
28
|
+
* Every flag `model-docs` accepts, derived from the sets the parser is handed
|
|
29
|
+
* so the list cannot claim a flag the parser would reject.
|
|
30
|
+
* {@link HARNESS_VALUE_FLAGS} are consumed by the shared harness parser itself,
|
|
31
|
+
* so they are in neither set.
|
|
30
32
|
*/
|
|
31
|
-
export const MODEL_DOCS_FLAGS: readonly string[] = [
|
|
33
|
+
export const MODEL_DOCS_FLAGS: readonly string[] = [...HARNESS_VALUE_FLAGS, ...VALUE_FLAGS];
|
|
32
34
|
|
|
33
35
|
/** The subset that takes a value, so `--help` in a value position reads as data. */
|
|
34
36
|
export const MODEL_DOCS_VALUE_FLAGS: readonly string[] = MODEL_DOCS_FLAGS;
|
|
35
37
|
|
|
36
38
|
/** The `--help` text, as data, held to {@link MODEL_DOCS_FLAGS} by a test. */
|
|
37
39
|
export const MODEL_DOCS_HELP: readonly string[] = [
|
|
38
|
-
'Usage: hydranium-cli model-docs --services <module> [--out-file <file>] [--log-level <lvl>]',
|
|
40
|
+
'Usage: hydranium-cli model-docs --services <module> [--import <specifier>]... [--out-file <file>] [--log-level <lvl>] [--log-file <file>] [--log-file-level <lvl>]',
|
|
39
41
|
'',
|
|
40
42
|
'Generate a navigable Markdown reference of every AST node type — a type index,',
|
|
41
43
|
'cross-linked super/sub types, a reverse "referenced by" index, and a per-language',
|
|
@@ -46,18 +48,19 @@ export const MODEL_DOCS_HELP: readonly string[] = [
|
|
|
46
48
|
'',
|
|
47
49
|
'Options:',
|
|
48
50
|
' --services <module> ESM module exporting `createServices(): { shared }` (required).',
|
|
51
|
+
...importHelpLines(22),
|
|
49
52
|
' --out-file <file> Write the Markdown to this file instead of stdout. Written',
|
|
50
53
|
' only once the report exists, unlike a shell redirection,',
|
|
51
54
|
' which truncates the file before the head is even booted.',
|
|
52
|
-
|
|
55
|
+
...logHelpLines(22)
|
|
53
56
|
];
|
|
54
57
|
|
|
55
58
|
export function parseModelDocsArgs(args: string[], onError: UsageError = exitWithUsage): ModelDocsCommandOptions {
|
|
56
|
-
const { servicesModule, options } = parseHarnessArgs(args, 'model-docs', VALUE_FLAGS, [], {
|
|
59
|
+
const { servicesModule, imports, options } = parseHarnessArgs(args, 'model-docs', VALUE_FLAGS, [], {
|
|
57
60
|
requireWorkspace: false,
|
|
58
61
|
onError
|
|
59
62
|
});
|
|
60
|
-
return { servicesModule, outFile: options[OUT_FILE_FLAG],
|
|
63
|
+
return { servicesModule, imports, outFile: options[OUT_FILE_FLAG], ...logOptions(options) };
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
export function runModelDocsCommand(args: string[]): Promise<void> {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* head throws. Never imported — only spawned.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { describeError } from '@hydranium/protocol';
|
|
19
20
|
import { emitReport, loadHeadlessContext, OUT_FILE_FLAG } from './headless-harness.js';
|
|
20
21
|
import { formatModelDocs } from './model-docs-report.js';
|
|
21
22
|
|
|
@@ -63,6 +64,6 @@ async function main(argv: string[]): Promise<number> {
|
|
|
63
64
|
main(process.argv.slice(2))
|
|
64
65
|
.then(code => process.exit(code))
|
|
65
66
|
.catch((error: unknown) => {
|
|
66
|
-
console.error(
|
|
67
|
+
console.error(describeError(error));
|
|
67
68
|
process.exit(1);
|
|
68
69
|
});
|
|
@@ -44,5 +44,5 @@ export function buildModelDocsDriverArgs(options: ModelDocsCommandOptions): stri
|
|
|
44
44
|
* module, keeping the binary language-agnostic.
|
|
45
45
|
*/
|
|
46
46
|
export function runModelDocs(options: ModelDocsCommandOptions): Promise<void> {
|
|
47
|
-
return runDriverChild([
|
|
47
|
+
return runDriverChild([DRIVER, ...buildModelDocsDriverArgs(options)], options);
|
|
48
48
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import {
|
|
11
11
|
exitWithUsage,
|
|
12
12
|
helpRequested,
|
|
13
|
+
logHelpLines,
|
|
13
14
|
parseFlagOptions,
|
|
14
15
|
parseServerSpawnOptions,
|
|
15
16
|
printHelp,
|
|
@@ -32,7 +33,7 @@ export const PROJECTS_VALUE_FLAGS: readonly string[] = PROJECTS_FLAGS;
|
|
|
32
33
|
|
|
33
34
|
/** The `--help` text, as data, held to {@link PROJECTS_FLAGS} by a test. */
|
|
34
35
|
export const PROJECTS_HELP: readonly string[] = [
|
|
35
|
-
'Usage: hydranium-cli projects --server "<cmd> [args...]" [--cwd <dir>] [--log-level <level>]',
|
|
36
|
+
'Usage: hydranium-cli projects --server "<cmd> [args...]" [--cwd <dir>] [--log-level <lvl>] [--log-file <file>] [--log-file-level <lvl>]',
|
|
36
37
|
'',
|
|
37
38
|
'List projects exposed by the data-server subprocess. Output is newline-delimited',
|
|
38
39
|
'JSON — one project envelope per line.',
|
|
@@ -40,17 +41,17 @@ export const PROJECTS_HELP: readonly string[] = [
|
|
|
40
41
|
'Options:',
|
|
41
42
|
' --server "<cmd>" Command-line for the data-server subprocess (required).',
|
|
42
43
|
' --cwd <dir> Working directory for the spawned child. Default: cwd.',
|
|
43
|
-
'
|
|
44
|
+
...logHelpLines(19, 'the spawned server')
|
|
44
45
|
];
|
|
45
46
|
|
|
46
47
|
export function parseProjectsArgs(args: string[], onError: UsageError = exitWithUsage): ProjectsCommandOptions {
|
|
47
|
-
const { serverCommand, serverArgs, cwd, logLevel, extra } = parseServerSpawnOptions(args, 'projects', onError);
|
|
48
|
+
const { serverCommand, serverArgs, cwd, logLevel, logFile, logFileLevel, extra } = parseServerSpawnOptions(args, 'projects', onError);
|
|
48
49
|
// `projects` declares no options beyond the shared ones, so nothing may
|
|
49
50
|
// survive the spawn parser. Draining `extra` against an empty set is what
|
|
50
51
|
// makes a typo an error here rather than a flag that silently did nothing —
|
|
51
52
|
// the siblings get this from the option list they pass.
|
|
52
53
|
parseFlagOptions(extra, 'projects', [], onError);
|
|
53
|
-
return { serverCommand, serverArgs, cwd, logLevel };
|
|
54
|
+
return { serverCommand, serverArgs, cwd, logLevel, logFile, logFileLevel };
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
export function runProjectsCommand(args: string[]): Promise<void> {
|