behavior-contracts 0.8.6 → 0.8.8
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/cli-contract.yaml +189 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +76 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/codegen.d.ts +6 -0
- package/dist/commands/codegen.d.ts.map +1 -0
- package/dist/commands/codegen.js +39 -0
- package/dist/commands/codegen.js.map +1 -0
- package/dist/generated/commands.d.ts +8 -0
- package/dist/generated/commands.d.ts.map +1 -0
- package/dist/generated/commands.js +55 -0
- package/dist/generated/commands.js.map +1 -0
- package/dist/generated/contract.d.ts +3 -0
- package/dist/generated/contract.d.ts.map +1 -0
- package/dist/generated/contract.js +5 -0
- package/dist/generated/contract.js.map +1 -0
- package/dist/generated/index.d.ts +7 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +7 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/program.d.ts +17 -0
- package/dist/generated/program.d.ts.map +1 -0
- package/dist/generated/program.js +117 -0
- package/dist/generated/program.js.map +1 -0
- package/dist/generated/schemas.d.ts +2 -0
- package/dist/generated/schemas.d.ts.map +1 -0
- package/dist/generated/schemas.js +3 -0
- package/dist/generated/schemas.js.map +1 -0
- package/dist/generated/types.d.ts +35 -0
- package/dist/generated/types.d.ts.map +1 -0
- package/dist/generated/types.js +3 -0
- package/dist/generated/types.js.map +1 -0
- package/dist/generator/core.d.ts +28 -0
- package/dist/generator/core.d.ts.map +1 -1
- package/dist/generator/core.js +7 -0
- package/dist/generator/core.js.map +1 -1
- package/dist/generator/emit-shared-debox.d.ts +108 -0
- package/dist/generator/emit-shared-debox.d.ts.map +1 -0
- package/dist/generator/emit-shared-debox.js +117 -0
- package/dist/generator/emit-shared-debox.js.map +1 -0
- package/dist/generator/emit-typed-native-go.d.ts.map +1 -1
- package/dist/generator/emit-typed-native-go.js +436 -1078
- package/dist/generator/emit-typed-native-go.js.map +1 -1
- package/dist/generator/emit-typed-native-rust.d.ts +9 -7
- package/dist/generator/emit-typed-native-rust.d.ts.map +1 -1
- package/dist/generator/emit-typed-native-rust.js +313 -844
- package/dist/generator/emit-typed-native-rust.js.map +1 -1
- package/dist/generator/typed.d.ts +4 -2
- package/dist/generator/typed.d.ts.map +1 -1
- package/dist/generator/typed.js +4 -2
- package/dist/generator/typed.js.map +1 -1
- package/package.json +12 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# yaml-language-server: $schema=./node_modules/cli-contracts/schemas/cli-contract.schema.json
|
|
2
|
+
cli_contracts: 0.1.0
|
|
3
|
+
|
|
4
|
+
info:
|
|
5
|
+
title: behavior-contracts CLI
|
|
6
|
+
version: 0.1.0
|
|
7
|
+
description: >-
|
|
8
|
+
bc — the build-time codegen CLI over behavior-contracts' public API.
|
|
9
|
+
Reads a serialized ComponentGraphIRDoc (the unbranded JSON IR), adopts it
|
|
10
|
+
via loadCompiledIR, and runs the same generateModule the in-process API runs
|
|
11
|
+
to emit a runtime-free native module (data baked as literals). The IR doc is
|
|
12
|
+
a build-time input only; nothing reads it at runtime.
|
|
13
|
+
license:
|
|
14
|
+
name: MIT
|
|
15
|
+
contact:
|
|
16
|
+
name: foo-ogawa
|
|
17
|
+
url: https://github.com/foo-ogawa/behavior-contracts
|
|
18
|
+
|
|
19
|
+
artifact_slots:
|
|
20
|
+
ir-doc:
|
|
21
|
+
direction: read
|
|
22
|
+
description: Serialized ComponentGraphIRDoc (unbranded JSON IR) — the codegen input.
|
|
23
|
+
generated-module:
|
|
24
|
+
direction: write
|
|
25
|
+
description: Generated native module source (baked-literal, runtime-free).
|
|
26
|
+
|
|
27
|
+
command_sets:
|
|
28
|
+
bc:
|
|
29
|
+
summary: build-time codegen CLI over behavior-contracts' public API.
|
|
30
|
+
executable: bc
|
|
31
|
+
|
|
32
|
+
global_options:
|
|
33
|
+
- name: version
|
|
34
|
+
aliases: [V]
|
|
35
|
+
description: Print version and exit.
|
|
36
|
+
schema:
|
|
37
|
+
type: boolean
|
|
38
|
+
|
|
39
|
+
- name: help
|
|
40
|
+
aliases: [h]
|
|
41
|
+
description: Show help and exit.
|
|
42
|
+
schema:
|
|
43
|
+
type: boolean
|
|
44
|
+
|
|
45
|
+
commands:
|
|
46
|
+
# ── generate ─────────────────────────────────────────
|
|
47
|
+
generate:
|
|
48
|
+
summary: Emit a native module from a serialized IR doc.
|
|
49
|
+
description: >-
|
|
50
|
+
Reads the --in ComponentGraphIRDoc, adopts it via loadCompiledIR, and
|
|
51
|
+
runs generateModule for the --lang emitter. Writes the module source
|
|
52
|
+
to --out if given, else to stdout. Rejects an unregistered --lang.
|
|
53
|
+
usage:
|
|
54
|
+
- bc generate --lang rust-typed-native --in ir-doc.json
|
|
55
|
+
- bc generate --lang go-typed-native --in ir-doc.json --out gen.go
|
|
56
|
+
- bc generate --lang typescript-typed --in ir-doc.json --runtime-import ./runtime.js
|
|
57
|
+
|
|
58
|
+
options:
|
|
59
|
+
- name: lang
|
|
60
|
+
required: true
|
|
61
|
+
description: >-
|
|
62
|
+
Target emitter (must be a registered language, e.g.
|
|
63
|
+
rust-typed-native, go-typed-native, typescript-typed).
|
|
64
|
+
value_name: emitter
|
|
65
|
+
schema:
|
|
66
|
+
type: string
|
|
67
|
+
|
|
68
|
+
- name: in
|
|
69
|
+
required: true
|
|
70
|
+
description: Path to the serialized ComponentGraphIRDoc JSON file.
|
|
71
|
+
value_name: ir-doc.json
|
|
72
|
+
schema:
|
|
73
|
+
type: string
|
|
74
|
+
file:
|
|
75
|
+
mode: read
|
|
76
|
+
exists: true
|
|
77
|
+
media_type: application/json
|
|
78
|
+
encoding: utf-8
|
|
79
|
+
|
|
80
|
+
- name: out
|
|
81
|
+
required: false
|
|
82
|
+
description: Write the generated module here instead of stdout.
|
|
83
|
+
value_name: file
|
|
84
|
+
schema:
|
|
85
|
+
type: string
|
|
86
|
+
file:
|
|
87
|
+
mode: write
|
|
88
|
+
|
|
89
|
+
- name: runtime-import
|
|
90
|
+
required: false
|
|
91
|
+
description: Override the runtime import specifier baked into the module.
|
|
92
|
+
value_name: spec
|
|
93
|
+
schema:
|
|
94
|
+
type: string
|
|
95
|
+
|
|
96
|
+
exits:
|
|
97
|
+
'0':
|
|
98
|
+
description: Module generated (written to --out, or printed to stdout).
|
|
99
|
+
stdout:
|
|
100
|
+
format: text
|
|
101
|
+
'1':
|
|
102
|
+
description: >-
|
|
103
|
+
Generation failed (unreadable/invalid --in, or --lang is not a
|
|
104
|
+
registered emitter).
|
|
105
|
+
stderr:
|
|
106
|
+
format: text
|
|
107
|
+
'2':
|
|
108
|
+
description: Usage error — a required option (--lang or --in) was omitted.
|
|
109
|
+
stderr:
|
|
110
|
+
format: text
|
|
111
|
+
|
|
112
|
+
x-agent:
|
|
113
|
+
riskLevel: low
|
|
114
|
+
requiresConfirmation: false
|
|
115
|
+
idempotent: true
|
|
116
|
+
sideEffects:
|
|
117
|
+
- file_write
|
|
118
|
+
sideEffectNote: >-
|
|
119
|
+
Writes to the filesystem only when --out is specified; otherwise
|
|
120
|
+
output goes to stdout.
|
|
121
|
+
|
|
122
|
+
# ── check ────────────────────────────────────────────
|
|
123
|
+
check:
|
|
124
|
+
summary: Verify a committed module matches a fresh generation (drift gate).
|
|
125
|
+
description: >-
|
|
126
|
+
Regenerates the module from --in for --lang and byte-compares it
|
|
127
|
+
against the committed --out file. Exits non-zero on drift. This is the
|
|
128
|
+
build's codegen drift gate.
|
|
129
|
+
usage:
|
|
130
|
+
- bc check --lang rust-typed-native --in ir-doc.json --out gen.rs
|
|
131
|
+
|
|
132
|
+
options:
|
|
133
|
+
- name: lang
|
|
134
|
+
required: true
|
|
135
|
+
description: Target emitter (must be a registered language).
|
|
136
|
+
value_name: emitter
|
|
137
|
+
schema:
|
|
138
|
+
type: string
|
|
139
|
+
|
|
140
|
+
- name: in
|
|
141
|
+
required: true
|
|
142
|
+
description: Path to the serialized ComponentGraphIRDoc JSON file.
|
|
143
|
+
value_name: ir-doc.json
|
|
144
|
+
schema:
|
|
145
|
+
type: string
|
|
146
|
+
file:
|
|
147
|
+
mode: read
|
|
148
|
+
exists: true
|
|
149
|
+
media_type: application/json
|
|
150
|
+
encoding: utf-8
|
|
151
|
+
|
|
152
|
+
- name: out
|
|
153
|
+
required: true
|
|
154
|
+
description: The committed module file to diff a fresh generation against.
|
|
155
|
+
value_name: file
|
|
156
|
+
schema:
|
|
157
|
+
type: string
|
|
158
|
+
file:
|
|
159
|
+
mode: read
|
|
160
|
+
exists: true
|
|
161
|
+
|
|
162
|
+
- name: runtime-import
|
|
163
|
+
required: false
|
|
164
|
+
description: Override the runtime import specifier baked into the module.
|
|
165
|
+
value_name: spec
|
|
166
|
+
schema:
|
|
167
|
+
type: string
|
|
168
|
+
|
|
169
|
+
exits:
|
|
170
|
+
'0':
|
|
171
|
+
description: Up to date — the committed --out matches a fresh generation.
|
|
172
|
+
stdout:
|
|
173
|
+
format: text
|
|
174
|
+
'1':
|
|
175
|
+
description: >-
|
|
176
|
+
Drift detected (--out differs or does not exist), or generation
|
|
177
|
+
failed (unreadable/invalid --in, or unregistered --lang).
|
|
178
|
+
stderr:
|
|
179
|
+
format: text
|
|
180
|
+
'2':
|
|
181
|
+
description: Usage error — a required option (--lang or --in) was omitted.
|
|
182
|
+
stderr:
|
|
183
|
+
format: text
|
|
184
|
+
|
|
185
|
+
x-agent:
|
|
186
|
+
riskLevel: low
|
|
187
|
+
requiresConfirmation: false
|
|
188
|
+
idempotent: true
|
|
189
|
+
sideEffects: []
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
3
|
+
// bc — the build-time codegen CLI over behavior-contracts' public API.
|
|
4
|
+
//
|
|
5
|
+
// The arg parsing / dispatch / validation is GENERATED from cli-contract.yaml
|
|
6
|
+
// (./generated/program.ts, via cli-contracts). This entry only implements the
|
|
7
|
+
// per-command handlers (I/O + exit semantics) and runs the program; the actual
|
|
8
|
+
// codegen core lives in ./commands/codegen.ts (a thin wrapper over the public
|
|
9
|
+
// API — no emit logic reimplemented).
|
|
10
|
+
//
|
|
11
|
+
// bc generate --lang <emitter> --in <ir-doc.json> [--out <file>] [--runtime-import <spec>]
|
|
12
|
+
// bc check --lang <emitter> --in <ir-doc.json> --out <file> [--runtime-import <spec>]
|
|
13
|
+
//
|
|
14
|
+
// generate → emit the native module (to --out, or stdout if omitted).
|
|
15
|
+
// check → regenerate + byte-diff against --out; exit 1 on drift (the build's drift gate).
|
|
16
|
+
//
|
|
17
|
+
// The IR doc is a BUILD-TIME input only; nothing reads it at runtime. The generated module is a
|
|
18
|
+
// runtime-free native module with its data baked as literals.
|
|
19
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
20
|
+
import { createRequire } from "node:module";
|
|
21
|
+
import { createProgram } from "./generated/program.js";
|
|
22
|
+
import { generateFromDoc, readDoc } from "./commands/codegen.js";
|
|
23
|
+
const require = createRequire(import.meta.url);
|
|
24
|
+
const pkg = require("../package.json");
|
|
25
|
+
/** Validate required options + generate. Exits the process on any failure (2=usage, 1=generation). */
|
|
26
|
+
function generateOrExit(opts) {
|
|
27
|
+
if (!opts.lang) {
|
|
28
|
+
process.stderr.write("bc: --lang <emitter> is required\n");
|
|
29
|
+
process.exit(2);
|
|
30
|
+
}
|
|
31
|
+
if (!opts.in) {
|
|
32
|
+
process.stderr.write("bc: --in <ir-doc.json> is required\n");
|
|
33
|
+
process.exit(2);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return generateFromDoc(readDoc(opts.in), opts.lang, opts.runtimeImport);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
process.stderr.write(`bc: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const handlers = {
|
|
44
|
+
// ── generate ─────────────────────────────────────────────────────────────
|
|
45
|
+
generate: async (opts) => {
|
|
46
|
+
const code = generateOrExit(opts);
|
|
47
|
+
if (opts.out)
|
|
48
|
+
writeFileSync(opts.out, code);
|
|
49
|
+
else
|
|
50
|
+
process.stdout.write(code);
|
|
51
|
+
},
|
|
52
|
+
// ── check ────────────────────────────────────────────────────────────────
|
|
53
|
+
check: async (opts) => {
|
|
54
|
+
if (!opts.out) {
|
|
55
|
+
process.stderr.write("bc: check requires --out <file> to diff against\n");
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
const code = generateOrExit(opts);
|
|
59
|
+
let committed;
|
|
60
|
+
try {
|
|
61
|
+
committed = readFileSync(opts.out, "utf8");
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
process.stderr.write(`bc: DRIFT — --out '${opts.out}' does not exist (nothing to check against)\n`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (committed !== code) {
|
|
68
|
+
process.stderr.write(`bc: DRIFT — ${opts.out} differs from a fresh generation. Re-bake with: ` +
|
|
69
|
+
`bc generate --lang ${opts.lang} --in ${opts.in} --out ${opts.out}\n`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
process.stdout.write(`bc: up to date — ${opts.out}\n`);
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
createProgram(handlers, pkg.version).parse();
|
|
76
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ComponentGraphIRDoc } from "../index.js";
|
|
2
|
+
/** A serialized IR doc → the native module source (same path as the in-process API). */
|
|
3
|
+
export declare function generateFromDoc(doc: ComponentGraphIRDoc, language: string, runtimeImport?: string): string;
|
|
4
|
+
/** Read + parse a serialized ComponentGraphIRDoc from disk. */
|
|
5
|
+
export declare function readDoc(inPath: string): ComponentGraphIRDoc;
|
|
6
|
+
//# sourceMappingURL=codegen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/commands/codegen.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAErB,wFAAwF;AACxF,wBAAgB,eAAe,CAC7B,GAAG,EAAE,mBAAmB,EACxB,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,CAYR;AAED,+DAA+D;AAC/D,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAY3D"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// codegen — the pure core behind `bc generate` / `bc check`.
|
|
3
|
+
//
|
|
4
|
+
// A thin wrapper over the EXISTING public API (../index.ts): NO emit logic is
|
|
5
|
+
// reimplemented here. `generateFromDoc` runs the SAME `loadCompiledIR` →
|
|
6
|
+
// `generateModule` path the in-process API runs, so the CLI emits the exact
|
|
7
|
+
// module the in-process API does from the same doc.
|
|
8
|
+
//
|
|
9
|
+
// Pure (throws on error, no process/stream side effects) so it is unit-testable
|
|
10
|
+
// in-process; the cli.ts handlers add I/O + exit semantics around it.
|
|
11
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { loadCompiledIR, generateModule, registeredLanguages, } from "../index.js";
|
|
14
|
+
/** A serialized IR doc → the native module source (same path as the in-process API). */
|
|
15
|
+
export function generateFromDoc(doc, language, runtimeImport) {
|
|
16
|
+
if (!registeredLanguages().includes(language)) {
|
|
17
|
+
throw new Error(`--lang '${language}' is not a registered emitter (registered: ${registeredLanguages().join(", ")})`);
|
|
18
|
+
}
|
|
19
|
+
const compiled = loadCompiledIR(doc); // adopt the unbranded doc (recomputes + mints the provenance token)
|
|
20
|
+
const module = generateModule(compiled, runtimeImport === undefined ? { language } : { language, runtimeImport });
|
|
21
|
+
return module.code;
|
|
22
|
+
}
|
|
23
|
+
/** Read + parse a serialized ComponentGraphIRDoc from disk. */
|
|
24
|
+
export function readDoc(inPath) {
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = readFileSync(inPath, "utf8");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error(`cannot read --in '${inPath}'`);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(raw);
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
throw new Error(`--in '${inPath}' is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=codegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/commands/codegen.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6DAA6D;AAC7D,EAAE;AACF,8EAA8E;AAC9E,yEAAyE;AACzE,4EAA4E;AAC5E,oDAAoD;AACpD,EAAE;AACF,gFAAgF;AAChF,sEAAsE;AACtE,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACL,cAAc,EACd,cAAc,EACd,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AAErB,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAC7B,GAAwB,EACxB,QAAgB,EAChB,aAAsB;IAEtB,IAAI,CAAC,mBAAmB,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,WAAW,QAAQ,8CAA8C,mBAAmB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACrG,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,oEAAoE;IAC1G,MAAM,MAAM,GAAG,cAAc,CAC3B,QAAQ,EACR,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,CACzE,CAAC;IACF,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,GAAG,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;IAChD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,SAAS,MAAM,wBAAwB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ExecResult {
|
|
2
|
+
exitCode: number;
|
|
3
|
+
stdout: string;
|
|
4
|
+
stderr: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function bcGenerate(executable: string, options?: Partial<import("./types.js").GenerateOptions>): Promise<ExecResult>;
|
|
7
|
+
export declare function bcCheck(executable: string, options?: Partial<import("./types.js").CheckOptions>): Promise<ExecResult>;
|
|
8
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/generated/commands.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,YAAY,EAAE,eAAe,CAAC,GACtD,OAAO,CAAC,UAAU,CAAC,CAoBrB;AAED,wBAAsB,OAAO,CAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,YAAY,EAAE,YAAY,CAAC,GACnD,OAAO,CAAC,UAAU,CAAC,CAoBrB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Auto-generated by cli-contracts. Do not edit.
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export async function bcGenerate(executable, options) {
|
|
6
|
+
const cmdArgs = ["generate"];
|
|
7
|
+
if (options) {
|
|
8
|
+
if (options.lang !== undefined)
|
|
9
|
+
cmdArgs.push("--lang", String(options.lang));
|
|
10
|
+
if (options.in !== undefined)
|
|
11
|
+
cmdArgs.push("--in", String(options.in));
|
|
12
|
+
if (options.out !== undefined)
|
|
13
|
+
cmdArgs.push("--out", String(options.out));
|
|
14
|
+
if (options.runtimeImport !== undefined)
|
|
15
|
+
cmdArgs.push("--runtime-import", String(options.runtimeImport));
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
const result = await execFileAsync(executable, cmdArgs);
|
|
19
|
+
return { exitCode: 0, stdout: result.stdout, stderr: result.stderr };
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
const e = err;
|
|
23
|
+
return {
|
|
24
|
+
exitCode: typeof e.code === 'number' ? e.code : 1,
|
|
25
|
+
stdout: e.stdout ?? '',
|
|
26
|
+
stderr: e.stderr ?? '',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function bcCheck(executable, options) {
|
|
31
|
+
const cmdArgs = ["check"];
|
|
32
|
+
if (options) {
|
|
33
|
+
if (options.lang !== undefined)
|
|
34
|
+
cmdArgs.push("--lang", String(options.lang));
|
|
35
|
+
if (options.in !== undefined)
|
|
36
|
+
cmdArgs.push("--in", String(options.in));
|
|
37
|
+
if (options.out !== undefined)
|
|
38
|
+
cmdArgs.push("--out", String(options.out));
|
|
39
|
+
if (options.runtimeImport !== undefined)
|
|
40
|
+
cmdArgs.push("--runtime-import", String(options.runtimeImport));
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const result = await execFileAsync(executable, cmdArgs);
|
|
44
|
+
return { exitCode: 0, stdout: result.stdout, stderr: result.stderr };
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const e = err;
|
|
48
|
+
return {
|
|
49
|
+
exitCode: typeof e.code === 'number' ? e.code : 1,
|
|
50
|
+
stdout: e.stdout ?? '',
|
|
51
|
+
stderr: e.stderr ?? '',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/generated/commands.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAQ1C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAkB,EAClB,OAAuD;IAEvD,MAAM,OAAO,GAAa,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3G,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACvE,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAA0D,CAAC;QACrE,OAAO;YACL,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;YACtB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;SACvB,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,UAAkB,EAClB,OAAoD;IAEpD,MAAM,OAAO,GAAa,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;QACvE,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1E,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS;YAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3G,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACvE,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAA0D,CAAC;QACrE,OAAO;YACL,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;YACtB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;SACvB,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/generated/contract.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,EAAE,MAA6tM,CAAC;AAE1vM,eAAO,MAAM,iBAAiB,EAAE,MAAqiQ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Auto-generated by cli-contracts. Do not edit.
|
|
2
|
+
// Embedded contract for the extract subcommand.
|
|
3
|
+
export const CONTRACT_YAML = "# yaml-language-server: $schema=./node_modules/cli-contracts/schemas/cli-contract.schema.json\ncli_contracts: 0.1.0\n\ninfo:\n title: behavior-contracts CLI\n version: 0.1.0\n description: >-\n bc — the build-time codegen CLI over behavior-contracts' public API.\n Reads a serialized ComponentGraphIRDoc (the unbranded JSON IR), adopts it\n via loadCompiledIR, and runs the same generateModule the in-process API runs\n to emit a runtime-free native module (data baked as literals). The IR doc is\n a build-time input only; nothing reads it at runtime.\n license:\n name: MIT\n contact:\n name: foo-ogawa\n url: https://github.com/foo-ogawa/behavior-contracts\n\nartifact_slots:\n ir-doc:\n direction: read\n description: Serialized ComponentGraphIRDoc (unbranded JSON IR) — the codegen input.\n generated-module:\n direction: write\n description: Generated native module source (baked-literal, runtime-free).\n\ncommand_sets:\n bc:\n summary: build-time codegen CLI over behavior-contracts' public API.\n executable: bc\n\n global_options:\n - name: version\n aliases: [V]\n description: Print version and exit.\n schema:\n type: boolean\n\n - name: help\n aliases: [h]\n description: Show help and exit.\n schema:\n type: boolean\n\n commands:\n # ── generate ─────────────────────────────────────────\n generate:\n summary: Emit a native module from a serialized IR doc.\n description: >-\n Reads the --in ComponentGraphIRDoc, adopts it via loadCompiledIR, and\n runs generateModule for the --lang emitter. Writes the module source\n to --out if given, else to stdout. Rejects an unregistered --lang.\n usage:\n - bc generate --lang rust-typed-native --in ir-doc.json\n - bc generate --lang go-typed-native --in ir-doc.json --out gen.go\n - bc generate --lang typescript-typed --in ir-doc.json --runtime-import ./runtime.js\n\n options:\n - name: lang\n required: true\n description: >-\n Target emitter (must be a registered language, e.g.\n rust-typed-native, go-typed-native, typescript-typed).\n value_name: emitter\n schema:\n type: string\n\n - name: in\n required: true\n description: Path to the serialized ComponentGraphIRDoc JSON file.\n value_name: ir-doc.json\n schema:\n type: string\n file:\n mode: read\n exists: true\n media_type: application/json\n encoding: utf-8\n\n - name: out\n required: false\n description: Write the generated module here instead of stdout.\n value_name: file\n schema:\n type: string\n file:\n mode: write\n\n - name: runtime-import\n required: false\n description: Override the runtime import specifier baked into the module.\n value_name: spec\n schema:\n type: string\n\n exits:\n '0':\n description: Module generated (written to --out, or printed to stdout).\n stdout:\n format: text\n '1':\n description: >-\n Generation failed (unreadable/invalid --in, or --lang is not a\n registered emitter).\n stderr:\n format: text\n '2':\n description: Usage error — a required option (--lang or --in) was omitted.\n stderr:\n format: text\n\n x-agent:\n riskLevel: low\n requiresConfirmation: false\n idempotent: true\n sideEffects:\n - file_write\n sideEffectNote: >-\n Writes to the filesystem only when --out is specified; otherwise\n output goes to stdout.\n\n # ── check ────────────────────────────────────────────\n check:\n summary: Verify a committed module matches a fresh generation (drift gate).\n description: >-\n Regenerates the module from --in for --lang and byte-compares it\n against the committed --out file. Exits non-zero on drift. This is the\n build's codegen drift gate.\n usage:\n - bc check --lang rust-typed-native --in ir-doc.json --out gen.rs\n\n options:\n - name: lang\n required: true\n description: Target emitter (must be a registered language).\n value_name: emitter\n schema:\n type: string\n\n - name: in\n required: true\n description: Path to the serialized ComponentGraphIRDoc JSON file.\n value_name: ir-doc.json\n schema:\n type: string\n file:\n mode: read\n exists: true\n media_type: application/json\n encoding: utf-8\n\n - name: out\n required: true\n description: The committed module file to diff a fresh generation against.\n value_name: file\n schema:\n type: string\n file:\n mode: read\n exists: true\n\n - name: runtime-import\n required: false\n description: Override the runtime import specifier baked into the module.\n value_name: spec\n schema:\n type: string\n\n exits:\n '0':\n description: Up to date — the committed --out matches a fresh generation.\n stdout:\n format: text\n '1':\n description: >-\n Drift detected (--out differs or does not exist), or generation\n failed (unreadable/invalid --in, or unregistered --lang).\n stderr:\n format: text\n '2':\n description: Usage error — a required option (--lang or --in) was omitted.\n stderr:\n format: text\n\n x-agent:\n riskLevel: low\n requiresConfirmation: false\n idempotent: true\n sideEffects: []\n";
|
|
4
|
+
export const CONTRACT_JSON_STR = "{\n \"cli_contracts\": \"0.1.0\",\n \"info\": {\n \"title\": \"behavior-contracts CLI\",\n \"version\": \"0.1.0\",\n \"description\": \"bc — the build-time codegen CLI over behavior-contracts' public API. Reads a serialized ComponentGraphIRDoc (the unbranded JSON IR), adopts it via loadCompiledIR, and runs the same generateModule the in-process API runs to emit a runtime-free native module (data baked as literals). The IR doc is a build-time input only; nothing reads it at runtime.\",\n \"license\": {\n \"name\": \"MIT\"\n },\n \"contact\": {\n \"name\": \"foo-ogawa\",\n \"url\": \"https://github.com/foo-ogawa/behavior-contracts\"\n }\n },\n \"artifact_slots\": {\n \"ir-doc\": {\n \"direction\": \"read\",\n \"description\": \"Serialized ComponentGraphIRDoc (unbranded JSON IR) — the codegen input.\"\n },\n \"generated-module\": {\n \"direction\": \"write\",\n \"description\": \"Generated native module source (baked-literal, runtime-free).\"\n }\n },\n \"command_sets\": {\n \"bc\": {\n \"summary\": \"build-time codegen CLI over behavior-contracts' public API.\",\n \"executable\": \"bc\",\n \"global_options\": [\n {\n \"name\": \"version\",\n \"aliases\": [\n \"V\"\n ],\n \"description\": \"Print version and exit.\",\n \"schema\": {\n \"type\": \"boolean\"\n }\n },\n {\n \"name\": \"help\",\n \"aliases\": [\n \"h\"\n ],\n \"description\": \"Show help and exit.\",\n \"schema\": {\n \"type\": \"boolean\"\n }\n }\n ],\n \"commands\": {\n \"generate\": {\n \"summary\": \"Emit a native module from a serialized IR doc.\",\n \"description\": \"Reads the --in ComponentGraphIRDoc, adopts it via loadCompiledIR, and runs generateModule for the --lang emitter. Writes the module source to --out if given, else to stdout. Rejects an unregistered --lang.\",\n \"usage\": [\n \"bc generate --lang rust-typed-native --in ir-doc.json\",\n \"bc generate --lang go-typed-native --in ir-doc.json --out gen.go\",\n \"bc generate --lang typescript-typed --in ir-doc.json --runtime-import ./runtime.js\"\n ],\n \"options\": [\n {\n \"name\": \"lang\",\n \"required\": true,\n \"description\": \"Target emitter (must be a registered language, e.g. rust-typed-native, go-typed-native, typescript-typed).\",\n \"value_name\": \"emitter\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"in\",\n \"required\": true,\n \"description\": \"Path to the serialized ComponentGraphIRDoc JSON file.\",\n \"value_name\": \"ir-doc.json\",\n \"schema\": {\n \"type\": \"string\"\n },\n \"file\": {\n \"mode\": \"read\",\n \"exists\": true,\n \"media_type\": \"application/json\",\n \"encoding\": \"utf-8\"\n }\n },\n {\n \"name\": \"out\",\n \"required\": false,\n \"description\": \"Write the generated module here instead of stdout.\",\n \"value_name\": \"file\",\n \"schema\": {\n \"type\": \"string\"\n },\n \"file\": {\n \"mode\": \"write\"\n }\n },\n {\n \"name\": \"runtime-import\",\n \"required\": false,\n \"description\": \"Override the runtime import specifier baked into the module.\",\n \"value_name\": \"spec\",\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"exits\": {\n \"0\": {\n \"description\": \"Module generated (written to --out, or printed to stdout).\",\n \"stdout\": {\n \"format\": \"text\"\n }\n },\n \"1\": {\n \"description\": \"Generation failed (unreadable/invalid --in, or --lang is not a registered emitter).\",\n \"stderr\": {\n \"format\": \"text\"\n }\n },\n \"2\": {\n \"description\": \"Usage error — a required option (--lang or --in) was omitted.\",\n \"stderr\": {\n \"format\": \"text\"\n }\n }\n },\n \"x-agent\": {\n \"riskLevel\": \"low\",\n \"requiresConfirmation\": false,\n \"idempotent\": true,\n \"sideEffects\": [\n \"file_write\"\n ],\n \"sideEffectNote\": \"Writes to the filesystem only when --out is specified; otherwise output goes to stdout.\"\n }\n },\n \"check\": {\n \"summary\": \"Verify a committed module matches a fresh generation (drift gate).\",\n \"description\": \"Regenerates the module from --in for --lang and byte-compares it against the committed --out file. Exits non-zero on drift. This is the build's codegen drift gate.\",\n \"usage\": [\n \"bc check --lang rust-typed-native --in ir-doc.json --out gen.rs\"\n ],\n \"options\": [\n {\n \"name\": \"lang\",\n \"required\": true,\n \"description\": \"Target emitter (must be a registered language).\",\n \"value_name\": \"emitter\",\n \"schema\": {\n \"type\": \"string\"\n }\n },\n {\n \"name\": \"in\",\n \"required\": true,\n \"description\": \"Path to the serialized ComponentGraphIRDoc JSON file.\",\n \"value_name\": \"ir-doc.json\",\n \"schema\": {\n \"type\": \"string\"\n },\n \"file\": {\n \"mode\": \"read\",\n \"exists\": true,\n \"media_type\": \"application/json\",\n \"encoding\": \"utf-8\"\n }\n },\n {\n \"name\": \"out\",\n \"required\": true,\n \"description\": \"The committed module file to diff a fresh generation against.\",\n \"value_name\": \"file\",\n \"schema\": {\n \"type\": \"string\"\n },\n \"file\": {\n \"mode\": \"read\",\n \"exists\": true\n }\n },\n {\n \"name\": \"runtime-import\",\n \"required\": false,\n \"description\": \"Override the runtime import specifier baked into the module.\",\n \"value_name\": \"spec\",\n \"schema\": {\n \"type\": \"string\"\n }\n }\n ],\n \"exits\": {\n \"0\": {\n \"description\": \"Up to date — the committed --out matches a fresh generation.\",\n \"stdout\": {\n \"format\": \"text\"\n }\n },\n \"1\": {\n \"description\": \"Drift detected (--out differs or does not exist), or generation failed (unreadable/invalid --in, or unregistered --lang).\",\n \"stderr\": {\n \"format\": \"text\"\n }\n },\n \"2\": {\n \"description\": \"Usage error — a required option (--lang or --in) was omitted.\",\n \"stderr\": {\n \"format\": \"text\"\n }\n }\n },\n \"x-agent\": {\n \"riskLevel\": \"low\",\n \"requiresConfirmation\": false,\n \"idempotent\": true,\n \"sideEffects\": []\n }\n }\n }\n }\n }\n}";
|
|
5
|
+
//# sourceMappingURL=contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/generated/contract.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,gDAAgD;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAW,otMAAotM,CAAC;AAE1vM,MAAM,CAAC,MAAM,iBAAiB,GAAW,4hQAA4hQ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
2
|
+
export * from "./commands.js";
|
|
3
|
+
export * from "./schemas.js";
|
|
4
|
+
export { createProgram } from "./program.js";
|
|
5
|
+
export type { CommandHandlers } from "./program.js";
|
|
6
|
+
export { CONTRACT_YAML, CONTRACT_JSON_STR } from "./contract.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generated/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Auto-generated by cli-contracts. Do not edit.
|
|
2
|
+
export * from "./types.js";
|
|
3
|
+
export * from "./commands.js";
|
|
4
|
+
export * from "./schemas.js";
|
|
5
|
+
export { createProgram } from "./program.js";
|
|
6
|
+
export { CONTRACT_YAML, CONTRACT_JSON_STR } from "./contract.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generated/index.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export interface CommandHandlers {
|
|
3
|
+
generate: (options: {
|
|
4
|
+
lang?: string;
|
|
5
|
+
in?: string;
|
|
6
|
+
out?: string;
|
|
7
|
+
runtimeImport?: string;
|
|
8
|
+
}, parentOpts: Record<string, unknown>) => Promise<void>;
|
|
9
|
+
check: (options: {
|
|
10
|
+
lang?: string;
|
|
11
|
+
in?: string;
|
|
12
|
+
out?: string;
|
|
13
|
+
runtimeImport?: string;
|
|
14
|
+
}, parentOpts: Record<string, unknown>) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function createProgram(handlers: CommandHandlers, version: string): Command;
|
|
17
|
+
//# sourceMappingURL=program.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/generated/program.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChJ,KAAK,EAAE,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9I;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAmHT"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Auto-generated by cli-contracts. Do not edit.
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { CONTRACT_YAML, CONTRACT_JSON_STR } from "./contract.js";
|
|
4
|
+
export function createProgram(handlers, version) {
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name("bc")
|
|
8
|
+
.version(version, "-V, --version")
|
|
9
|
+
.description("build-time codegen CLI over behavior-contracts' public API.");
|
|
10
|
+
program
|
|
11
|
+
.command("generate")
|
|
12
|
+
.description("Emit a native module from a serialized IR doc.")
|
|
13
|
+
.option("--lang <emitter>", "Target emitter (must be a registered language, e.g. rust-typed-native, go-typed-native, typescript-typed).")
|
|
14
|
+
.option("--in <ir-doc.json>", "Path to the serialized ComponentGraphIRDoc JSON file.")
|
|
15
|
+
.option("--out <file>", "Write the generated module here instead of stdout.")
|
|
16
|
+
.option("--runtime-import <spec>", "Override the runtime import specifier baked into the module.")
|
|
17
|
+
.action(async (opts, cmd) => {
|
|
18
|
+
await handlers.generate(opts, cmd.optsWithGlobals());
|
|
19
|
+
});
|
|
20
|
+
program
|
|
21
|
+
.command("check")
|
|
22
|
+
.description("Verify a committed module matches a fresh generation (drift gate).")
|
|
23
|
+
.option("--lang <emitter>", "Target emitter (must be a registered language).")
|
|
24
|
+
.option("--in <ir-doc.json>", "Path to the serialized ComponentGraphIRDoc JSON file.")
|
|
25
|
+
.option("--out <file>", "The committed module file to diff a fresh generation against.")
|
|
26
|
+
.option("--runtime-import <spec>", "Override the runtime import specifier baked into the module.")
|
|
27
|
+
.action(async (opts, cmd) => {
|
|
28
|
+
await handlers.check(opts, cmd.optsWithGlobals());
|
|
29
|
+
});
|
|
30
|
+
// Built-in extract command (auto-injected by cli-contracts)
|
|
31
|
+
program
|
|
32
|
+
.command("extract")
|
|
33
|
+
.description("Extract contract specification for this CLI tool.")
|
|
34
|
+
.argument("[commands...]", "Command IDs to extract. Use dot notation.")
|
|
35
|
+
.option("-a, --all", "Extract all commands.", false)
|
|
36
|
+
.option("--include-meta", "Include extraction metadata.", true)
|
|
37
|
+
.option("-F, --format <format>", "Output format (yaml or json).", "yaml")
|
|
38
|
+
.action(async (commands, opts, cmd) => {
|
|
39
|
+
if (commands.length === 0 && !opts.all) {
|
|
40
|
+
process.stderr.write(JSON.stringify({ code: "INVALID_ARGS", message: "Specify command IDs or use --all" }) + "\n");
|
|
41
|
+
process.exit(2);
|
|
42
|
+
}
|
|
43
|
+
const format = opts.format || "yaml";
|
|
44
|
+
const doc = JSON.parse(CONTRACT_JSON_STR);
|
|
45
|
+
const cmdIds = opts.all ? [] : commands;
|
|
46
|
+
if (cmdIds.length === 0) {
|
|
47
|
+
// --all: output full contract
|
|
48
|
+
if (format === "json") {
|
|
49
|
+
const out = {};
|
|
50
|
+
if (opts.includeMeta) {
|
|
51
|
+
out._meta = {
|
|
52
|
+
source: "embedded",
|
|
53
|
+
type: "cli-contracts/extract",
|
|
54
|
+
extractedAt: new Date().toISOString(),
|
|
55
|
+
specVersion: doc.cli_contracts ?? "0.1.0",
|
|
56
|
+
commands: ["bc.generate", "bc.check"],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
Object.assign(out, doc);
|
|
60
|
+
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// YAML output
|
|
64
|
+
const yamlLines = [];
|
|
65
|
+
yamlLines.push("# bc extract");
|
|
66
|
+
yamlLines.push("# source: embedded");
|
|
67
|
+
yamlLines.push("# type: cli-contracts/command-extract");
|
|
68
|
+
if (opts.includeMeta) {
|
|
69
|
+
yamlLines.push("---");
|
|
70
|
+
yamlLines.push("source: embedded");
|
|
71
|
+
yamlLines.push("type: cli-contracts/command-extract");
|
|
72
|
+
yamlLines.push("extractedAt: " + new Date().toISOString());
|
|
73
|
+
yamlLines.push("spec_version: " + (doc.cli_contracts ?? "0.1.0"));
|
|
74
|
+
yamlLines.push("commands:");
|
|
75
|
+
for (const id of ["bc.generate", "bc.check"]) {
|
|
76
|
+
yamlLines.push(" - " + id);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
yamlLines.push("---");
|
|
80
|
+
yamlLines.push(CONTRACT_YAML);
|
|
81
|
+
process.stdout.write(yamlLines.join("\n") + "\n");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Filter specific commands
|
|
86
|
+
const filtered = {
|
|
87
|
+
cli_contracts: doc.cli_contracts,
|
|
88
|
+
info: doc.info,
|
|
89
|
+
command_sets: {},
|
|
90
|
+
};
|
|
91
|
+
const fcs = filtered.command_sets;
|
|
92
|
+
for (const [setId, cs] of Object.entries(doc.command_sets ?? {})) {
|
|
93
|
+
const cmds = cs.commands;
|
|
94
|
+
if (!cmds)
|
|
95
|
+
continue;
|
|
96
|
+
const matched = {};
|
|
97
|
+
for (const [cmdId, cmdDef] of Object.entries(cmds)) {
|
|
98
|
+
const fullId = setId + "." + cmdId;
|
|
99
|
+
if (cmdIds.some((id) => id === cmdId || id === fullId || cmdId.startsWith(id + "."))) {
|
|
100
|
+
matched[cmdId] = cmdDef;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (Object.keys(matched).length > 0) {
|
|
104
|
+
const setCopy = { ...cs };
|
|
105
|
+
setCopy.commands = matched;
|
|
106
|
+
fcs[setId] = setCopy;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (doc.components)
|
|
110
|
+
filtered.components = doc.components;
|
|
111
|
+
process.stdout.write(JSON.stringify(filtered, null, 2) + "\n");
|
|
112
|
+
}
|
|
113
|
+
process.exit(0);
|
|
114
|
+
});
|
|
115
|
+
return program;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=program.js.map
|