@aid-framework/cli 0.0.0 → 0.1.48
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/LICENSE +201 -0
- package/README.md +225 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/args.d.ts +37 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +74 -0
- package/dist/args.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +26 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/eval.d.ts +44 -0
- package/dist/commands/eval.d.ts.map +1 -0
- package/dist/commands/eval.js +257 -0
- package/dist/commands/eval.js.map +1 -0
- package/dist/commands/gen.d.ts +42 -0
- package/dist/commands/gen.d.ts.map +1 -0
- package/dist/commands/gen.js +138 -0
- package/dist/commands/gen.js.map +1 -0
- package/dist/commands/ingest.d.ts +44 -0
- package/dist/commands/ingest.d.ts.map +1 -0
- package/dist/commands/ingest.js +238 -0
- package/dist/commands/ingest.js.map +1 -0
- package/dist/commands/init.d.ts +38 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +203 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +22 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +53 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/context.d.ts +37 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +36 -0
- package/dist/context.js.map +1 -0
- package/dist/diagnostics.d.ts +42 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +47 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/exit.d.ts +16 -0
- package/dist/exit.d.ts.map +1 -0
- package/dist/exit.js +15 -0
- package/dist/exit.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +25 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +155 -0
- package/dist/main.js.map +1 -0
- package/dist/output.d.ts +48 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +50 -0
- package/dist/output.js.map +1 -0
- package/dist/paths.d.ts +21 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +31 -0
- package/dist/paths.js.map +1 -0
- package/dist/pipeline.d.ts +74 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +113 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/python.d.ts +30 -0
- package/dist/python.d.ts.map +1 -0
- package/dist/python.js +57 -0
- package/dist/python.js.map +1 -0
- package/dist/targets.d.ts +75 -0
- package/dist/targets.d.ts.map +1 -0
- package/dist/targets.js +136 -0
- package/dist/targets.js.map +1 -0
- package/dist/usage.d.ts +20 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +49 -0
- package/dist/usage.js.map +1 -0
- package/package.json +49 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;IACrD,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compile pipeline: read the spec, lower it to the IR, run every build-time gate,
|
|
3
|
+
* then ask the target to compile it.
|
|
4
|
+
*
|
|
5
|
+
* This is the sequence `packages/generators/py-fastapi/scripts/generate-example.mjs`
|
|
6
|
+
* already performs for the example app, and it is deliberately the *same* sequence
|
|
7
|
+
* rather than a parallel one: every step is a call into `@aid-framework/spec`, `@aid-framework/ir`,
|
|
8
|
+
* `@aid-framework/generator-sdk` or `@aid-framework/generator-py-fastapi`. The CLI introduces no gate, no
|
|
9
|
+
* hash, no drift rule and no manifest reader of its own -- a second implementation of a
|
|
10
|
+
* gate is a defect, because the two can disagree and only one of them will be right.
|
|
11
|
+
*
|
|
12
|
+
* Two behaviours worth stating because they are choices, not accidents:
|
|
13
|
+
*
|
|
14
|
+
* - Stages stop at the first error. Lowering a spec whose own schema did not validate
|
|
15
|
+
* would report a cascade of consequences of the first mistake, which buries it.
|
|
16
|
+
* Warnings produced before the stop are kept, because the design emits some
|
|
17
|
+
* deliberately -- the eval-coverage gate warns rather than fails.
|
|
18
|
+
* - The target's compiler runs *before* its planner. `checkPlan` reports every problem
|
|
19
|
+
* at once; `plan` throws. Asking first is what lets `aid gen` print the target's own
|
|
20
|
+
* codes and paths instead of a stack trace with an exception dressed up as a
|
|
21
|
+
* diagnostic.
|
|
22
|
+
*/
|
|
23
|
+
import { type AidManifest, type AidManifestProvenance, type Plan, type RegenerationSink } from '@aid-framework/generator-sdk';
|
|
24
|
+
import type { IR } from '@aid-framework/ir';
|
|
25
|
+
import type { CliContext } from './context.js';
|
|
26
|
+
import type { CliDiagnostic } from './diagnostics.js';
|
|
27
|
+
import type { Target } from './targets.js';
|
|
28
|
+
/** A stage that judged the project and said no. */
|
|
29
|
+
export interface Failed {
|
|
30
|
+
readonly ok: false;
|
|
31
|
+
readonly diagnostics: readonly CliDiagnostic[];
|
|
32
|
+
}
|
|
33
|
+
export interface ReadSpec {
|
|
34
|
+
readonly ok: true;
|
|
35
|
+
readonly text: string;
|
|
36
|
+
}
|
|
37
|
+
/** A spec that reduced to an IR the gates accepted. `diagnostics` holds its warnings. */
|
|
38
|
+
export interface Lowered {
|
|
39
|
+
readonly ok: true;
|
|
40
|
+
readonly ir: IR;
|
|
41
|
+
readonly diagnostics: readonly CliDiagnostic[];
|
|
42
|
+
}
|
|
43
|
+
export type LowerOutcome = Lowered | Failed;
|
|
44
|
+
/** A spec the target accepted, with the plan it produced. */
|
|
45
|
+
export interface Compiled {
|
|
46
|
+
readonly ok: true;
|
|
47
|
+
readonly ir: IR;
|
|
48
|
+
readonly plan: Plan;
|
|
49
|
+
readonly diagnostics: readonly CliDiagnostic[];
|
|
50
|
+
}
|
|
51
|
+
export type CompileOutcome = Compiled | Failed;
|
|
52
|
+
/** A manifest read back from the tree, or the diagnostics explaining why it was not. */
|
|
53
|
+
export interface ReadManifest {
|
|
54
|
+
readonly ok: true;
|
|
55
|
+
readonly manifest: AidManifest | undefined;
|
|
56
|
+
}
|
|
57
|
+
export type ManifestOutcome = ReadManifest | Failed;
|
|
58
|
+
export declare function readSpec(context: CliContext, specPath: string): ReadSpec | Failed;
|
|
59
|
+
export declare function lowerSpec(text: string, file: string): LowerOutcome;
|
|
60
|
+
export declare function compile(text: string, file: string, target: Target): CompileOutcome;
|
|
61
|
+
/**
|
|
62
|
+
* The manifest the tree currently holds, read through the sink so that the path-escape
|
|
63
|
+
* guard and the "missing file is `undefined`" contract are the SDK's rather than this
|
|
64
|
+
* layer's. A manifest with an error in it is a failure, not a warning: generation
|
|
65
|
+
* cannot tell a hand edit from its own output without it.
|
|
66
|
+
*/
|
|
67
|
+
export declare function readManifest(sink: RegenerationSink, target: Target): ManifestOutcome;
|
|
68
|
+
/**
|
|
69
|
+
* What the next manifest records about the run that wrote it, read off the target's own
|
|
70
|
+
* manifest so that the generator identity in the manifest and the generator that ran
|
|
71
|
+
* cannot disagree.
|
|
72
|
+
*/
|
|
73
|
+
export declare function provenanceFor(target: Target, ir: IR): AidManifestProvenance;
|
|
74
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,IAAI,EAET,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AAI5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,mDAAmD;AACnD,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,yFAAyF;AACzF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5C,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAC;CAChD;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE/C,wFAAwF;AACxF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,MAAM,eAAe,GAAG,YAAY,GAAG,MAAM,CAAC;AAMpD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,CAgBjF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAwBlE;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc,CASlF;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,CAYpF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,GAAG,qBAAqB,CAM3E"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compile pipeline: read the spec, lower it to the IR, run every build-time gate,
|
|
3
|
+
* then ask the target to compile it.
|
|
4
|
+
*
|
|
5
|
+
* This is the sequence `packages/generators/py-fastapi/scripts/generate-example.mjs`
|
|
6
|
+
* already performs for the example app, and it is deliberately the *same* sequence
|
|
7
|
+
* rather than a parallel one: every step is a call into `@aid-framework/spec`, `@aid-framework/ir`,
|
|
8
|
+
* `@aid-framework/generator-sdk` or `@aid-framework/generator-py-fastapi`. The CLI introduces no gate, no
|
|
9
|
+
* hash, no drift rule and no manifest reader of its own -- a second implementation of a
|
|
10
|
+
* gate is a defect, because the two can disagree and only one of them will be right.
|
|
11
|
+
*
|
|
12
|
+
* Two behaviours worth stating because they are choices, not accidents:
|
|
13
|
+
*
|
|
14
|
+
* - Stages stop at the first error. Lowering a spec whose own schema did not validate
|
|
15
|
+
* would report a cascade of consequences of the first mistake, which buries it.
|
|
16
|
+
* Warnings produced before the stop are kept, because the design emits some
|
|
17
|
+
* deliberately -- the eval-coverage gate warns rather than fails.
|
|
18
|
+
* - The target's compiler runs *before* its planner. `checkPlan` reports every problem
|
|
19
|
+
* at once; `plan` throws. Asking first is what lets `aid gen` print the target's own
|
|
20
|
+
* codes and paths instead of a stack trace with an exception dressed up as a
|
|
21
|
+
* diagnostic.
|
|
22
|
+
*/
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
import { parseAidManifestJson, } from '@aid-framework/generator-sdk';
|
|
25
|
+
import { buildIR, runGates } from '@aid-framework/ir';
|
|
26
|
+
import { checkSpecText, hasErrors, sortDiagnostics } from '@aid-framework/spec';
|
|
27
|
+
import { CLI_DIAGNOSTIC_CODES, cliError } from './diagnostics.js';
|
|
28
|
+
import { absolutePath } from './paths.js';
|
|
29
|
+
import { targetCapabilities } from './targets.js';
|
|
30
|
+
function describeError(error) {
|
|
31
|
+
return error instanceof Error ? error.message : String(error);
|
|
32
|
+
}
|
|
33
|
+
export function readSpec(context, specPath) {
|
|
34
|
+
try {
|
|
35
|
+
return { ok: true, text: readFileSync(absolutePath(context.cwd, specPath), 'utf8') };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
ok: false,
|
|
40
|
+
diagnostics: [
|
|
41
|
+
cliError({
|
|
42
|
+
code: CLI_DIAGNOSTIC_CODES.specUnreadable,
|
|
43
|
+
message: `Cannot read the spec at "${specPath}": ${describeError(error)}`,
|
|
44
|
+
path: [specPath],
|
|
45
|
+
hint: 'Run `aid init` to scaffold a project, or pass the path to an existing spec.',
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function lowerSpec(text, file) {
|
|
52
|
+
const diagnostics = [];
|
|
53
|
+
const parsed = checkSpecText(text, { file });
|
|
54
|
+
diagnostics.push(...parsed.diagnostics);
|
|
55
|
+
if (!parsed.ok || parsed.value === undefined) {
|
|
56
|
+
return { ok: false, diagnostics: sortDiagnostics(diagnostics) };
|
|
57
|
+
}
|
|
58
|
+
const built = buildIR(parsed.value, { file });
|
|
59
|
+
diagnostics.push(...built.diagnostics);
|
|
60
|
+
if (hasErrors(built.diagnostics)) {
|
|
61
|
+
return { ok: false, diagnostics: sortDiagnostics(diagnostics) };
|
|
62
|
+
}
|
|
63
|
+
// The gates take the *generators'* capability declarations, not the IR package's
|
|
64
|
+
// placeholder: a gate run against a placeholder passes every spec and is not a gate.
|
|
65
|
+
const gates = runGates(built.ir, { targetCapabilities: targetCapabilities(), file });
|
|
66
|
+
diagnostics.push(...gates.diagnostics);
|
|
67
|
+
if (hasErrors(gates.diagnostics)) {
|
|
68
|
+
return { ok: false, diagnostics: sortDiagnostics(diagnostics) };
|
|
69
|
+
}
|
|
70
|
+
return { ok: true, ir: built.ir, diagnostics: sortDiagnostics(diagnostics) };
|
|
71
|
+
}
|
|
72
|
+
export function compile(text, file, target) {
|
|
73
|
+
const lowered = lowerSpec(text, file);
|
|
74
|
+
if (!lowered.ok)
|
|
75
|
+
return lowered;
|
|
76
|
+
const problems = target.check(lowered.ir);
|
|
77
|
+
const diagnostics = sortDiagnostics([...lowered.diagnostics, ...problems]);
|
|
78
|
+
if (hasErrors(problems))
|
|
79
|
+
return { ok: false, diagnostics };
|
|
80
|
+
return { ok: true, ir: lowered.ir, plan: target.plan(lowered.ir), diagnostics };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The manifest the tree currently holds, read through the sink so that the path-escape
|
|
84
|
+
* guard and the "missing file is `undefined`" contract are the SDK's rather than this
|
|
85
|
+
* layer's. A manifest with an error in it is a failure, not a warning: generation
|
|
86
|
+
* cannot tell a hand edit from its own output without it.
|
|
87
|
+
*/
|
|
88
|
+
export function readManifest(sink, target) {
|
|
89
|
+
const text = sink.read(target.manifestPath);
|
|
90
|
+
if (text === undefined)
|
|
91
|
+
return { ok: true, manifest: undefined };
|
|
92
|
+
const parsed = parseAidManifestJson(text, {
|
|
93
|
+
generatedDir: target.generatedDir,
|
|
94
|
+
businessDir: target.businessDir,
|
|
95
|
+
});
|
|
96
|
+
if (parsed.manifest === undefined || hasErrors(parsed.diagnostics)) {
|
|
97
|
+
return { ok: false, diagnostics: sortDiagnostics(parsed.diagnostics) };
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, manifest: parsed.manifest };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* What the next manifest records about the run that wrote it, read off the target's own
|
|
103
|
+
* manifest so that the generator identity in the manifest and the generator that ran
|
|
104
|
+
* cannot disagree.
|
|
105
|
+
*/
|
|
106
|
+
export function provenanceFor(target, ir) {
|
|
107
|
+
return {
|
|
108
|
+
generator: target.manifest.name,
|
|
109
|
+
generatorVersion: target.manifest.version,
|
|
110
|
+
irVersion: ir.irVersion,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
package/dist/python.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Python toolchain the commands that run generated code have to find.
|
|
3
|
+
*
|
|
4
|
+
* `aid eval` and `aid ingest` both shell out to a module the generator emitted, so both
|
|
5
|
+
* need the same two answers: which interpreter can actually import the runtime, and how
|
|
6
|
+
* to spawn it. Keeping the discovery here means there is one definition of "a usable
|
|
7
|
+
* interpreter" -- if the two commands each carried their own, an environment could work
|
|
8
|
+
* for one and not the other without anything explaining why.
|
|
9
|
+
*
|
|
10
|
+
* The contract is deliberately narrow: the caller names the module, and this file only
|
|
11
|
+
* decides which program runs it and from where. It knows nothing about evals or ingest.
|
|
12
|
+
*/
|
|
13
|
+
import type { CliContext, SpawnResult } from './context.js';
|
|
14
|
+
/**
|
|
15
|
+
* Tried in order. The interpreter already active on this project comes first: it is the
|
|
16
|
+
* one the runtime was installed into. `uv` is last, and is kept because a uv-managed
|
|
17
|
+
* environment that has not been activated is a real setup where none of the others exist.
|
|
18
|
+
*/
|
|
19
|
+
export declare const INTERPRETERS: readonly ['python3', 'python', 'uv'];
|
|
20
|
+
/** `uv run python` is a different argv shape from `python`, so it is not a rename. */
|
|
21
|
+
export declare function interpreterCommand(interpreter: string): readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* Spawn, or `undefined` when the program could not be executed at all. `spawnSync` reports
|
|
24
|
+
* a missing binary as `error` with a `null` status, and collapsing those two into one
|
|
25
|
+
* `undefined` is what lets discovery and the real run share a code path.
|
|
26
|
+
*/
|
|
27
|
+
export declare function invoke(context: CliContext, command: readonly string[], stdin?: string): SpawnResult | undefined;
|
|
28
|
+
/** The first interpreter that can import the runtime, or `undefined` when none can. */
|
|
29
|
+
export declare function discoverInterpreter(context: CliContext): string | undefined;
|
|
30
|
+
//# sourceMappingURL=python.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../src/python.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,YAAY,YAAI,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAU,CAAC;AAWjE,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,CAAC,EAAE,MAAM,GACb,WAAW,GAAG,SAAS,CAUzB;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAM3E"}
|
package/dist/python.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Python toolchain the commands that run generated code have to find.
|
|
3
|
+
*
|
|
4
|
+
* `aid eval` and `aid ingest` both shell out to a module the generator emitted, so both
|
|
5
|
+
* need the same two answers: which interpreter can actually import the runtime, and how
|
|
6
|
+
* to spawn it. Keeping the discovery here means there is one definition of "a usable
|
|
7
|
+
* interpreter" -- if the two commands each carried their own, an environment could work
|
|
8
|
+
* for one and not the other without anything explaining why.
|
|
9
|
+
*
|
|
10
|
+
* The contract is deliberately narrow: the caller names the module, and this file only
|
|
11
|
+
* decides which program runs it and from where. It knows nothing about evals or ingest.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Tried in order. The interpreter already active on this project comes first: it is the
|
|
15
|
+
* one the runtime was installed into. `uv` is last, and is kept because a uv-managed
|
|
16
|
+
* environment that has not been activated is a real setup where none of the others exist.
|
|
17
|
+
*/
|
|
18
|
+
export const INTERPRETERS = ['python3', 'python', 'uv'];
|
|
19
|
+
/**
|
|
20
|
+
* Discovery asks whether a candidate can import the runtime, not merely whether it
|
|
21
|
+
* exists. A machine with a system `python` beside a project virtualenv has several
|
|
22
|
+
* interpreters, and picking the one that cannot `import aid_runtime` reports a missing
|
|
23
|
+
* dependency as a broken generated module. The probe is the import itself, so it cannot
|
|
24
|
+
* disagree with what the run will do a moment later.
|
|
25
|
+
*/
|
|
26
|
+
const RUNTIME_PROBE = 'import aid_runtime.evals';
|
|
27
|
+
/** `uv run python` is a different argv shape from `python`, so it is not a rename. */
|
|
28
|
+
export function interpreterCommand(interpreter) {
|
|
29
|
+
return interpreter === 'uv' ? ['uv', 'run', 'python'] : [interpreter];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Spawn, or `undefined` when the program could not be executed at all. `spawnSync` reports
|
|
33
|
+
* a missing binary as `error` with a `null` status, and collapsing those two into one
|
|
34
|
+
* `undefined` is what lets discovery and the real run share a code path.
|
|
35
|
+
*/
|
|
36
|
+
export function invoke(context, command, stdin) {
|
|
37
|
+
const [program, ...args] = command;
|
|
38
|
+
if (program === undefined)
|
|
39
|
+
return undefined;
|
|
40
|
+
const result = context.spawn(program, args, {
|
|
41
|
+
cwd: context.cwd,
|
|
42
|
+
stdio: 'pipe',
|
|
43
|
+
env: context.env,
|
|
44
|
+
...(stdin === undefined ? {} : { stdin }),
|
|
45
|
+
});
|
|
46
|
+
return result.error === undefined ? result : undefined;
|
|
47
|
+
}
|
|
48
|
+
/** The first interpreter that can import the runtime, or `undefined` when none can. */
|
|
49
|
+
export function discoverInterpreter(context) {
|
|
50
|
+
for (const interpreter of INTERPRETERS) {
|
|
51
|
+
const probe = invoke(context, [...interpreterCommand(interpreter), '-c', RUNTIME_PROBE]);
|
|
52
|
+
if (probe !== undefined && probe.status === 0)
|
|
53
|
+
return interpreter;
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python.js","sourceRoot":"","sources":["../src/python.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAU,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,0BAA0B,CAAC;AAEjD,sFAAsF;AACtF,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CACpB,OAAmB,EACnB,OAA0B,EAC1B,KAAc;IAEd,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC;IACnC,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;QAC1C,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KAC1C,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,OAAmB;IACrD,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,kBAAkB,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;QACzF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,WAAW,CAAC;IACpE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The target registry: the one place the CLI learns what a target *is*.
|
|
3
|
+
*
|
|
4
|
+
* A target is a generator plus the layout it declares. Nothing here restates that
|
|
5
|
+
* layout -- the spec path, the generated root, the business root, the manifest path and
|
|
6
|
+
* the eval module names all come from `@aid-framework/generator-sdk`'s `managedRoots` and
|
|
7
|
+
* `@aid-framework/generator-py-fastapi`'s path helpers, so a generator that moves a file moves
|
|
8
|
+
* every command with it, without the CLI being edited.
|
|
9
|
+
*
|
|
10
|
+
* The capability declarations are the SDK's `phase0TargetCapabilities`, not `@aid-framework/ir`'s
|
|
11
|
+
* placeholder of the same name. The placeholder exists so the gate could be written
|
|
12
|
+
* before a real generator existed; feeding it to the gate would make the capability gate
|
|
13
|
+
* pass vacuously for every spec, which is the one failure mode a gate must not have.
|
|
14
|
+
*/
|
|
15
|
+
import { type Generator, type GeneratorManifest, type Plan } from '@aid-framework/generator-sdk';
|
|
16
|
+
import type { IR, TargetCapabilityDeclarations } from '@aid-framework/ir';
|
|
17
|
+
import type { CliDiagnostic } from './diagnostics.js';
|
|
18
|
+
/**
|
|
19
|
+
* How `aid eval` and `aid ingest` run a target's generated entry points.
|
|
20
|
+
*
|
|
21
|
+
* Both commands used to assume CPython: they discover an interpreter and run `-m`. A
|
|
22
|
+
* target whose emitted modules are not Python has no such entry point, and the honest
|
|
23
|
+
* answer is a diagnostic, not a Python traceback about a missing module.
|
|
24
|
+
*/
|
|
25
|
+
export type TargetRunner = 'python' | 'node';
|
|
26
|
+
export interface Target {
|
|
27
|
+
/** The target id, as a spec's `project.targets` spells it. */
|
|
28
|
+
readonly name: string;
|
|
29
|
+
/** The spec this target's project is expected to keep, repo-relative. */
|
|
30
|
+
readonly specPath: string;
|
|
31
|
+
readonly generatedDir: string;
|
|
32
|
+
readonly businessDir: string;
|
|
33
|
+
readonly manifestPath: string;
|
|
34
|
+
/** The generated evals package, repo-relative. */
|
|
35
|
+
readonly evalsDir: string;
|
|
36
|
+
readonly manifest: GeneratorManifest;
|
|
37
|
+
readonly generator: Generator;
|
|
38
|
+
/** Which toolchain `aid eval` and `aid ingest` would need to run this target. */
|
|
39
|
+
readonly runner: TargetRunner;
|
|
40
|
+
/** Everything that stops this target compiling the IR, as diagnostics. */
|
|
41
|
+
check(ir: IR): readonly CliDiagnostic[];
|
|
42
|
+
plan(ir: IR): Plan;
|
|
43
|
+
/** The dotted module path of the generated eval module for `evalId`. */
|
|
44
|
+
evalModule(evalId: string): string;
|
|
45
|
+
/** The repo-relative file the generated eval module for `evalId` lives in. */
|
|
46
|
+
evalModuleFile(evalId: string): string;
|
|
47
|
+
/** The dotted module path of the generated ingest module for `retrieverId`. */
|
|
48
|
+
retrievalIngestModule(retrieverId: string): string;
|
|
49
|
+
/** The repo-relative file the generated ingest module for `retrieverId` lives in. */
|
|
50
|
+
retrievalIngestModuleFile(retrieverId: string): string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The registry. Order matters only for the default: the first entry is what `aid gen`,
|
|
54
|
+
* `aid validate` and `aid init` use when the caller names no target, and that has been
|
|
55
|
+
* `py-fastapi` since Phase 0.
|
|
56
|
+
*/
|
|
57
|
+
export declare const TARGETS: readonly Target[];
|
|
58
|
+
export declare const DEFAULT_TARGET: string;
|
|
59
|
+
/** Where `aid validate` and `aid gen` look when the caller names no spec. */
|
|
60
|
+
export declare const DEFAULT_SPEC_PATH: string;
|
|
61
|
+
export declare function targetNames(): string[];
|
|
62
|
+
/** The named target, the default when `name` is absent, or `undefined` when unknown. */
|
|
63
|
+
export declare function resolveTarget(name: string | undefined): Target | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* The capability declarations the build-time gates are run against.
|
|
66
|
+
*
|
|
67
|
+
* Derived from this registry rather than from the SDK's own `phase0Generators`, because
|
|
68
|
+
* the registry is the list of generators this binary can actually run: a spec targeting
|
|
69
|
+
* `ts-vercel` must be judged against `ts-vercel`'s declaration, and the SDK cannot name
|
|
70
|
+
* a generator that depends on the SDK.
|
|
71
|
+
*/
|
|
72
|
+
export declare function targetCapabilities(): TargetCapabilityDeclarations;
|
|
73
|
+
/** Diagnostics for a target id the registry does not know. */
|
|
74
|
+
export declare function unknownTargetDiagnostic(name: string): CliDiagnostic;
|
|
75
|
+
//# sourceMappingURL=targets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.d.ts","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAUH,OAAO,EACL,KAAK,SAAS,EACd,KAAK,iBAAiB,EAEtB,KAAK,IAAI,EAEV,MAAM,8BAA8B,CAAC;AAStC,OAAO,KAAK,EAAE,EAAE,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAG1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAiBtD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,MAAM;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,SAAS,aAAa,EAAE,CAAC;IACxC,IAAI,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IACnB,wEAAwE;IACxE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,8EAA8E;IAC9E,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,+EAA+E;IAC/E,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IACnD,qFAAqF;IACrF,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;CACxD;AA2ED;;;;GAIG;AACH,eAAO,MAAM,OAAO,EAAE,SAAS,MAAM,EAuBpC,CAAC;AAOF,eAAO,MAAM,cAAc,QAAe,CAAC;AAE3C,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,QAAmB,CAAC;AAElD,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,4BAA4B,CAEjE;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAOnE"}
|
package/dist/targets.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The target registry: the one place the CLI learns what a target *is*.
|
|
3
|
+
*
|
|
4
|
+
* A target is a generator plus the layout it declares. Nothing here restates that
|
|
5
|
+
* layout -- the spec path, the generated root, the business root, the manifest path and
|
|
6
|
+
* the eval module names all come from `@aid-framework/generator-sdk`'s `managedRoots` and
|
|
7
|
+
* `@aid-framework/generator-py-fastapi`'s path helpers, so a generator that moves a file moves
|
|
8
|
+
* every command with it, without the CLI being edited.
|
|
9
|
+
*
|
|
10
|
+
* The capability declarations are the SDK's `phase0TargetCapabilities`, not `@aid-framework/ir`'s
|
|
11
|
+
* placeholder of the same name. The placeholder exists so the gate could be written
|
|
12
|
+
* before a real generator existed; feeding it to the gate would make the capability gate
|
|
13
|
+
* pass vacuously for every spec, which is the one failure mode a gate must not have.
|
|
14
|
+
*/
|
|
15
|
+
import { checkPlan as checkPyFastApi, EVALS_INIT_PATH, PY_FASTAPI_MANIFEST, evalModulePath as pyFastApiEvalModulePath, pyFastApiGenerator, retrievalIngestModulePath as pyFastApiIngestModulePath, } from '@aid-framework/generator-py-fastapi';
|
|
16
|
+
import { managedRoots, targetCapabilityDeclarations, } from '@aid-framework/generator-sdk';
|
|
17
|
+
import { checkPlan as checkTsVercel, TS_VERCEL_MANIFEST, evalModulePath as tsVercelEvalModulePath, tsVercelGenerator, retrievalIngestModulePath as tsVercelIngestModulePath, paths as tsVercelPaths, } from '@aid-framework/generator-ts-vercel';
|
|
18
|
+
import { errorDiagnostic } from '@aid-framework/spec';
|
|
19
|
+
import { CLI_DIAGNOSTIC_CODES } from './diagnostics.js';
|
|
20
|
+
import { parentPath } from './paths.js';
|
|
21
|
+
function dotted(path, extension) {
|
|
22
|
+
return path
|
|
23
|
+
.replace(new RegExp(`${extension.replace('.', '\\.')}$`), '')
|
|
24
|
+
.split('/')
|
|
25
|
+
.join('.');
|
|
26
|
+
}
|
|
27
|
+
function targetFor(module) {
|
|
28
|
+
const { manifest } = module;
|
|
29
|
+
const roots = managedRoots(manifest);
|
|
30
|
+
return {
|
|
31
|
+
name: manifest.target,
|
|
32
|
+
specPath: `${manifest.output.root}/app.spec.yaml`,
|
|
33
|
+
generatedDir: roots.generatedDir,
|
|
34
|
+
businessDir: roots.businessDir,
|
|
35
|
+
manifestPath: roots.manifestFilename,
|
|
36
|
+
evalsDir: parentPath(module.evalsIndexPath),
|
|
37
|
+
manifest,
|
|
38
|
+
generator: module.generator,
|
|
39
|
+
runner: module.runner,
|
|
40
|
+
// `checkPlan` is the target's own compiler, and it throws the same problems
|
|
41
|
+
// `plan` does. Reporting them through it means the CLI prints the target's codes
|
|
42
|
+
// and paths verbatim: no catching, no renaming, no second opinion about what is
|
|
43
|
+
// wrong with a spec.
|
|
44
|
+
check(ir) {
|
|
45
|
+
return module.checkPlan(ir).map((problem) => errorDiagnostic({
|
|
46
|
+
code: problem.code,
|
|
47
|
+
message: problem.message,
|
|
48
|
+
path: [problem.path],
|
|
49
|
+
}));
|
|
50
|
+
},
|
|
51
|
+
plan(ir) {
|
|
52
|
+
return module.generator.plan(ir, {
|
|
53
|
+
generatorVersion: manifest.version,
|
|
54
|
+
root: manifest.output.root,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
evalModuleFile(evalId) {
|
|
58
|
+
return module.evalModulePath(evalId);
|
|
59
|
+
},
|
|
60
|
+
evalModule(evalId) {
|
|
61
|
+
return dotted(module.evalModulePath(evalId), module.extension);
|
|
62
|
+
},
|
|
63
|
+
retrievalIngestModuleFile(retrieverId) {
|
|
64
|
+
return module.retrievalIngestModulePath(retrieverId);
|
|
65
|
+
},
|
|
66
|
+
retrievalIngestModule(retrieverId) {
|
|
67
|
+
return dotted(module.retrievalIngestModulePath(retrieverId), module.extension);
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The registry. Order matters only for the default: the first entry is what `aid gen`,
|
|
73
|
+
* `aid validate` and `aid init` use when the caller names no target, and that has been
|
|
74
|
+
* `py-fastapi` since Phase 0.
|
|
75
|
+
*/
|
|
76
|
+
export const TARGETS = [
|
|
77
|
+
targetFor({
|
|
78
|
+
manifest: PY_FASTAPI_MANIFEST,
|
|
79
|
+
generator: pyFastApiGenerator,
|
|
80
|
+
runner: 'python',
|
|
81
|
+
extension: '.py',
|
|
82
|
+
evalsIndexPath: EVALS_INIT_PATH,
|
|
83
|
+
evalModulePath: pyFastApiEvalModulePath,
|
|
84
|
+
retrievalIngestModulePath: pyFastApiIngestModulePath,
|
|
85
|
+
checkPlan: checkPyFastApi,
|
|
86
|
+
}),
|
|
87
|
+
targetFor({
|
|
88
|
+
manifest: TS_VERCEL_MANIFEST,
|
|
89
|
+
generator: tsVercelGenerator,
|
|
90
|
+
runner: 'node',
|
|
91
|
+
// The generated modules are `.ts` on disk and `.js` once compiled; the dotted name
|
|
92
|
+
// is the same either way, and the path helpers hand back the file that exists.
|
|
93
|
+
extension: '.ts',
|
|
94
|
+
evalsIndexPath: tsVercelPaths.evalsIndex,
|
|
95
|
+
evalModulePath: tsVercelEvalModulePath,
|
|
96
|
+
retrievalIngestModulePath: tsVercelIngestModulePath,
|
|
97
|
+
checkPlan: checkTsVercel,
|
|
98
|
+
}),
|
|
99
|
+
];
|
|
100
|
+
const [primary] = TARGETS;
|
|
101
|
+
if (primary === undefined) {
|
|
102
|
+
throw new Error('No Phase 0 target is registered.');
|
|
103
|
+
}
|
|
104
|
+
export const DEFAULT_TARGET = primary.name;
|
|
105
|
+
/** Where `aid validate` and `aid gen` look when the caller names no spec. */
|
|
106
|
+
export const DEFAULT_SPEC_PATH = primary.specPath;
|
|
107
|
+
export function targetNames() {
|
|
108
|
+
return TARGETS.map((target) => target.name);
|
|
109
|
+
}
|
|
110
|
+
/** The named target, the default when `name` is absent, or `undefined` when unknown. */
|
|
111
|
+
export function resolveTarget(name) {
|
|
112
|
+
if (name === undefined)
|
|
113
|
+
return primary;
|
|
114
|
+
return TARGETS.find((target) => target.name === name);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The capability declarations the build-time gates are run against.
|
|
118
|
+
*
|
|
119
|
+
* Derived from this registry rather than from the SDK's own `phase0Generators`, because
|
|
120
|
+
* the registry is the list of generators this binary can actually run: a spec targeting
|
|
121
|
+
* `ts-vercel` must be judged against `ts-vercel`'s declaration, and the SDK cannot name
|
|
122
|
+
* a generator that depends on the SDK.
|
|
123
|
+
*/
|
|
124
|
+
export function targetCapabilities() {
|
|
125
|
+
return targetCapabilityDeclarations(TARGETS.map((target) => target.manifest));
|
|
126
|
+
}
|
|
127
|
+
/** Diagnostics for a target id the registry does not know. */
|
|
128
|
+
export function unknownTargetDiagnostic(name) {
|
|
129
|
+
return errorDiagnostic({
|
|
130
|
+
code: CLI_DIAGNOSTIC_CODES.unknownTarget,
|
|
131
|
+
message: `Unknown target \`${name}\`.`,
|
|
132
|
+
path: [],
|
|
133
|
+
hint: `Known targets: ${targetNames().join(', ')}.`,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=targets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"targets.js","sourceRoot":"","sources":["../src/targets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,SAAS,IAAI,cAAc,EAC3B,eAAe,EACf,mBAAmB,EACnB,cAAc,IAAI,uBAAuB,EACzC,kBAAkB,EAClB,yBAAyB,IAAI,yBAAyB,GACvD,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAGL,YAAY,EAEZ,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,SAAS,IAAI,aAAa,EAC1B,kBAAkB,EAClB,cAAc,IAAI,sBAAsB,EACxC,iBAAiB,EACjB,yBAAyB,IAAI,wBAAwB,EACrD,KAAK,IAAI,aAAa,GACvB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAsExC,SAAS,MAAM,CAAC,IAAY,EAAE,SAAiB;IAC7C,OAAO,IAAI;SACR,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;SAC5D,KAAK,CAAC,GAAG,CAAC;SACV,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,SAAS,SAAS,CAAC,MAAoB;IACrC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAC5B,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrC,OAAO;QACL,IAAI,EAAE,QAAQ,CAAC,MAAM;QACrB,QAAQ,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,gBAAgB;QACjD,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,YAAY,EAAE,KAAK,CAAC,gBAAgB;QACpC,QAAQ,EAAE,UAAU,CAAC,MAAM,CAAC,cAAc,CAAC;QAC3C,QAAQ;QACR,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,4EAA4E;QAC5E,iFAAiF;QACjF,gFAAgF;QAChF,qBAAqB;QACrB,KAAK,CAAC,EAAE;YACN,OAAO,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAC1C,eAAe,CAAC;gBACd,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;aACrB,CAAC,CACH,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,EAAE;YACL,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE;gBAC/B,gBAAgB,EAAE,QAAQ,CAAC,OAAO;gBAClC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI;aAC3B,CAAC,CAAC;QACL,CAAC;QACD,cAAc,CAAC,MAAM;YACnB,OAAO,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;QACD,UAAU,CAAC,MAAM;YACf,OAAO,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACjE,CAAC;QACD,yBAAyB,CAAC,WAAW;YACnC,OAAO,MAAM,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAAC;QACvD,CAAC;QACD,qBAAqB,CAAC,WAAW;YAC/B,OAAO,MAAM,CAAC,MAAM,CAAC,yBAAyB,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACjF,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAsB;IACxC,SAAS,CAAC;QACR,QAAQ,EAAE,mBAAmB;QAC7B,SAAS,EAAE,kBAAkB;QAC7B,MAAM,EAAE,QAAQ;QAChB,SAAS,EAAE,KAAK;QAChB,cAAc,EAAE,eAAe;QAC/B,cAAc,EAAE,uBAAuB;QACvC,yBAAyB,EAAE,yBAAyB;QACpD,SAAS,EAAE,cAAc;KAC1B,CAAC;IACF,SAAS,CAAC;QACR,QAAQ,EAAE,kBAAkB;QAC5B,SAAS,EAAE,iBAAiB;QAC5B,MAAM,EAAE,MAAM;QACd,mFAAmF;QACnF,+EAA+E;QAC/E,SAAS,EAAE,KAAK;QAChB,cAAc,EAAE,aAAa,CAAC,UAAU;QACxC,cAAc,EAAE,sBAAsB;QACtC,yBAAyB,EAAE,wBAAwB;QACnD,SAAS,EAAE,aAAa;KACzB,CAAC;CACH,CAAC;AAEF,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAC1B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;IAC1B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;AAE3C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC;AAElD,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,aAAa,CAAC,IAAwB;IACpD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,4BAA4B,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,eAAe,CAAC;QACrB,IAAI,EAAE,oBAAoB,CAAC,aAAa;QACxC,OAAO,EAAE,oBAAoB,IAAI,KAAK;QACtC,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,kBAAkB,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;KACpD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage text, rendered from the same flag specs the parser enforces.
|
|
3
|
+
*
|
|
4
|
+
* Help that is written by hand drifts from the parser the first time a flag is added, and
|
|
5
|
+
* a help text listing a flag that does not exist is worse than no help. So one command
|
|
6
|
+
* table is the single source: `main.ts` registers each command with its flags, the parser
|
|
7
|
+
* validates against those flags, and these functions render them.
|
|
8
|
+
*/
|
|
9
|
+
import type { FlagSpec } from './args.js';
|
|
10
|
+
export interface CommandSpec {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
/** One line, shown in the global listing. */
|
|
13
|
+
readonly summary: string;
|
|
14
|
+
/** The invocation shape, as the user would type it. */
|
|
15
|
+
readonly usage: string;
|
|
16
|
+
readonly flags: readonly FlagSpec[];
|
|
17
|
+
}
|
|
18
|
+
export declare function commandUsage(command: CommandSpec): string;
|
|
19
|
+
export declare function globalUsage(commands: readonly CommandSpec[]): string;
|
|
20
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;CACrC;AAaD,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAYzD;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAiBpE"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage text, rendered from the same flag specs the parser enforces.
|
|
3
|
+
*
|
|
4
|
+
* Help that is written by hand drifts from the parser the first time a flag is added, and
|
|
5
|
+
* a help text listing a flag that does not exist is worse than no help. So one command
|
|
6
|
+
* table is the single source: `main.ts` registers each command with its flags, the parser
|
|
7
|
+
* validates against those flags, and these functions render them.
|
|
8
|
+
*/
|
|
9
|
+
/** The parser treats `help` specially; the help text still has to mention it. */
|
|
10
|
+
const HELP = {
|
|
11
|
+
name: 'help',
|
|
12
|
+
kind: 'boolean',
|
|
13
|
+
summary: "print this command's usage",
|
|
14
|
+
};
|
|
15
|
+
function flagLabel(flag) {
|
|
16
|
+
return flag.kind === 'value' ? `--${flag.name} <${flag.value ?? 'value'}>` : `--${flag.name}`;
|
|
17
|
+
}
|
|
18
|
+
export function commandUsage(command) {
|
|
19
|
+
const flags = [...command.flags, HELP];
|
|
20
|
+
const width = Math.max(...flags.map((flag) => flagLabel(flag).length));
|
|
21
|
+
return [
|
|
22
|
+
`Usage: aid ${command.usage}`,
|
|
23
|
+
'',
|
|
24
|
+
command.summary,
|
|
25
|
+
'',
|
|
26
|
+
'Options:',
|
|
27
|
+
...flags.map((flag) => ` ${flagLabel(flag).padEnd(width)} ${flag.summary}`),
|
|
28
|
+
'',
|
|
29
|
+
].join('\n');
|
|
30
|
+
}
|
|
31
|
+
export function globalUsage(commands) {
|
|
32
|
+
const width = Math.max(...commands.map((command) => command.name.length));
|
|
33
|
+
return [
|
|
34
|
+
'aid - the AID Framework CLI.',
|
|
35
|
+
'',
|
|
36
|
+
'Usage: aid <command> [arguments] [options]',
|
|
37
|
+
'',
|
|
38
|
+
'Commands:',
|
|
39
|
+
...commands.map((command) => ` ${command.name.padEnd(width)} ${command.summary}`),
|
|
40
|
+
'',
|
|
41
|
+
'Every command answers `--json` with one JSON document on stdout and `-h` with its',
|
|
42
|
+
'usage. Exit codes: 0 the project is as asked, 1 the spec, a gate, the target or the',
|
|
43
|
+
'working tree said no, 2 the invocation was wrong or the CLI failed internally.',
|
|
44
|
+
'',
|
|
45
|
+
"Run `aid <command> --help` for a command's options.",
|
|
46
|
+
'',
|
|
47
|
+
].join('\n');
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,iFAAiF;AACjF,MAAM,IAAI,GAAa;IACrB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,4BAA4B;CACtC,CAAC;AAEF,SAAS,SAAS,CAAC,IAAc;IAC/B,OAAO,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAoB;IAC/C,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACvE,OAAO;QACL,cAAc,OAAO,CAAC,KAAK,EAAE;QAC7B,EAAE;QACF,OAAO,CAAC,OAAO;QACf,EAAE;QACF,UAAU;QACV,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7E,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgC;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1E,OAAO;QACL,8BAA8B;QAC9B,EAAE;QACF,4CAA4C;QAC5C,EAAE;QACF,WAAW;QACX,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;QACnF,EAAE;QACF,mFAAmF;QACnF,qFAAqF;QACrF,gFAAgF;QAChF,EAAE;QACF,qDAAqD;QACrD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|