@altopelago/aeon-cli 0.9.0 → 0.9.2

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AltoPelago
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,390 @@
1
+ # AEON CLI Output Contract (v1)
2
+
3
+ **Status:** Normative for v1 snapshots/tests
4
+
5
+ This document is the single source of truth for the AEON CLI’s observable behavior. Tests MUST be written against this contract.
6
+
7
+ ## 1) Commands
8
+
9
+ The CLI MUST support these commands:
10
+
11
+ - `aeon check <file>`
12
+ - `aeon inspect <file>`
13
+ - `aeon inspect <file> --json`
14
+ - `aeon inspect <file> --json --annotations`
15
+ - `aeon inspect <file> --json --annotations-only`
16
+ - `aeon inspect <file> --json --annotations-only --sort-annotations`
17
+ - `aeon finalize <file>`
18
+ - `aeon finalize <file> --json`
19
+ - `aeon finalize <file> --map`
20
+ - `aeon bind <file> --schema <schema.json> --annotations`
21
+ - `--recovery` flag (tooling-only)
22
+
23
+ ## 2) Exit Codes
24
+
25
+ Exit codes are stable and MUST be:
26
+
27
+ - `0` — no errors
28
+ - `1` — errors present (including when `--recovery` is used)
29
+ - `2` — CLI usage error (bad args / missing file / unreadable file)
30
+
31
+ ## 3) Output Streams
32
+
33
+ - Human-readable output MUST be written to `stdout`.
34
+ - Fatal CLI usage errors (exit code `2`) MUST be written to `stderr`.
35
+
36
+ ## 4) Core Semantics
37
+
38
+ ### 4.1 Fail-Closed Default
39
+
40
+ By default, the CLI MUST behave fail-closed:
41
+
42
+ - If `compile().errors.length > 0`, the CLI MUST NOT show any events.
43
+ - Errors MUST still be shown.
44
+
45
+ This matches the canonical fail-closed contract of `@altopelago/aeon-core`.
46
+
47
+ ### 4.2 Recovery Mode (`--recovery`)
48
+
49
+ When `--recovery` is provided:
50
+
51
+ - Partial events MAY be shown.
52
+ - Errors MUST always be shown.
53
+ - The CLI MUST print a visible warning banner in human-readable output.
54
+
55
+ Recovery mode remains exit code `1` if any errors exist.
56
+
57
+ ### 4.3 Non-goals (MUST NOT)
58
+
59
+ The CLI MUST NOT (except as explicitly required by `aeon finalize`):
60
+
61
+ - Default to JSON output
62
+ - Implement AEON → JSON conversion semantics outside `aeon finalize`
63
+ - Resolve references
64
+ - Coerce values
65
+ - Perform hidden inference
66
+ - Materialize application-level objects
67
+
68
+ The CLI is an inspection/validation tool that only exposes events + errors.
69
+
70
+ ## 5) `aeon check <file>` (human)
71
+
72
+ ### 5.1 Purpose
73
+
74
+ Validate the document and report errors.
75
+
76
+ ### 5.2 Output
77
+
78
+ - Output MUST be plain text on `stdout`.
79
+ - If there are no errors, output SHOULD be a single line:
80
+ - `OK`
81
+ - If there are errors, output MUST list each error on its own line using the same error line format as in `inspect` (see §6.3).
82
+
83
+ ## 6) `aeon inspect <file>` (default Markdown)
84
+
85
+ ### 6.1 Determinism
86
+
87
+ Markdown output MUST be deterministic:
88
+
89
+ - No timestamps
90
+ - No absolute file paths (only basename)
91
+ - Stable ordering for lists
92
+ - Stable span formatting
93
+
94
+ ### 6.2 Section Order and Headings
95
+
96
+ The output MUST follow this structure.
97
+
98
+ 1. `# AEON Inspect`
99
+ 2. `## Summary`
100
+ 3. `## Errors` (only if `Errors > 0`)
101
+ 4. `## Assignment Events` (only if `Events > 0`)
102
+ 5. `## References` (OPTIONAL; if present, MUST be last)
103
+
104
+ ### 6.3 Summary Fields (exact order)
105
+
106
+ In `## Summary`, render bullets in this exact order:
107
+
108
+ - `File:` `<basename>`
109
+ - `Version:` `<value | —>`
110
+ - `Mode:` `<transport|strict>`
111
+ - `Profile:` `<string | —>`
112
+ - `Schema:` `<string | —>`
113
+ - `Recovery:` `<true|false>`
114
+ - `Events:` `<N>`
115
+ - `Errors:` `<M>`
116
+
117
+ ### 6.4 Recovery Banner
118
+
119
+ If `--recovery` is used, emit this banner immediately after `# AEON Inspect`:
120
+
121
+ - `> WARNING: recovery mode enabled (tooling-only); output may be partial`
122
+
123
+ ### 6.5 Error List Format (exact)
124
+
125
+ In `## Errors`, render one bullet per error in this exact shape:
126
+
127
+ - `- Phase Label: message [CODE] path=$.x.y span=3:5-3:12`
128
+
129
+ Rules:
130
+
131
+ - `Phase Label` SHOULD be present when the CLI can determine a stable phase name.
132
+ - `CODE` MUST be the error code.
133
+ - `path` MUST be a canonical path (or `$` if not applicable).
134
+ - `span` MUST be formatted as `line:col-line:col`.
135
+ - `message` MUST be the error message (single-line).
136
+
137
+ Example:
138
+
139
+ - `- Parsing: Expected '}' to close object [SYNTAX_ERROR] path=$ span=2:1-2:1`
140
+
141
+ ### 6.6 Assignment Event Line Format (exact)
142
+
143
+ In `## Assignment Events`, render one event per line:
144
+
145
+ - `- $.contacts.a1.name :s = "John"`
146
+
147
+ Rules:
148
+
149
+ - Path first.
150
+ - Then a single space.
151
+ - Then datatype (if present) as `:<type>`; if absent, omit the datatype segment entirely.
152
+ - Then ` = `.
153
+ - Then the value rendered in an AST-ish representation:
154
+ - No JS coercion
155
+ - No reference resolution
156
+ - References remain symbolic (e.g., `~x`, `~>x`)
157
+
158
+ ## 7) `aeon inspect <file> --json`
159
+
160
+ ### 7.1 Top-level shape (exact)
161
+
162
+ Output MUST be exactly:
163
+
164
+ ```json
165
+ { "events": [...], "errors": [...] }
166
+ ```
167
+
168
+ ### 7.2 Determinism
169
+
170
+ - No timestamps
171
+ - No absolute paths
172
+ - Deterministic ordering
173
+
174
+ ### 7.2.1 Diagnostic Metadata
175
+
176
+ Inspect JSON diagnostics SHOULD preserve:
177
+
178
+ - stable `code`
179
+ - canonical `path`
180
+ - `span` when available
181
+ - `phaseLabel` when a stable human-readable phase name is available
182
+
183
+ `phase` MAY be omitted for core compile diagnostics when only the label can be inferred.
184
+
185
+ ### 7.3 Values
186
+
187
+ Values MUST remain AST-like and MUST NOT be coerced into application-level types.
188
+
189
+ ## 7.4 Annotation Debug Extensions
190
+
191
+ For inspect-mode debugging, the CLI MAY include annotation stream records.
192
+
193
+ - `--annotations` adds an `annotations` array to the standard inspect JSON shape.
194
+ - `--annotations-only` emits only `{ "annotations": [...] }`.
195
+ - `--sort-annotations` applies deterministic record sorting before emitting annotations.
196
+
197
+ When `--annotations` or `--annotations-only` is used, implementation SHOULD compile in core v1 mode to surface annotation records.
198
+
199
+ ### 7.4.1 Deterministic Annotation Sort
200
+
201
+ When `--sort-annotations` is present, annotation records MUST be sorted by:
202
+
203
+ 1. `span.start.offset` (ascending)
204
+ 2. `span.end.offset` (ascending)
205
+ 3. `kind` (lexicographic)
206
+ 4. `form` (lexicographic)
207
+ 5. `raw` (lexicographic)
208
+ 6. original source order (stable tie-break)
209
+
210
+ ### 7.4.2 Snapshot-Recommended Commands
211
+
212
+ For stable snapshot workflows, prefer one of:
213
+
214
+ - `aeon inspect <file> --json --annotations-only --sort-annotations`
215
+ - `aeon inspect <file> --annotations-only --sort-annotations`
216
+
217
+ ## 8) `aeon finalize <file>` (JSON)
218
+
219
+ ### 8.1 Purpose
220
+
221
+ Finalize AES into a JSON-compatible document shape for tooling.
222
+
223
+ ### 8.2 Top-level shape (exact)
224
+
225
+ Output MUST be exactly:
226
+
227
+ ```json
228
+ { "document": { ... }, "meta": { "errors": [...], "warnings": [...] } }
229
+ ```
230
+
231
+ `meta` MAY be omitted when empty.
232
+
233
+ ### 8.3 Determinism
234
+
235
+ - No timestamps
236
+ - No absolute paths
237
+ - Deterministic ordering based on source order
238
+
239
+ ### 8.4 Diagnostics
240
+
241
+ - Errors MUST include compiler errors and finalization diagnostics.
242
+ - Warnings MUST include finalization warnings.
243
+ - If any errors are present, exit code MUST be `1`.
244
+
245
+ ### 8.5 Map Output (`--map`)
246
+
247
+ When `--map` is provided, the output MUST be:
248
+
249
+ ```json
250
+ { "document": { "entries": [ ... ] }, "meta": { "errors": [...], "warnings": [...] } }
251
+ ```
252
+
253
+ Each entry MUST include `path`, `value`, and `span`, with optional `datatype` and `annotations`.
254
+
255
+ ## 9) `aeon bind <file> --schema <schema.json> --annotations`
256
+
257
+ When `--annotations` is provided for `bind`, the CLI MAY include:
258
+
259
+ ```json
260
+ { "document": { ... }, "annotations": [ ... ], "meta": { ... } }
261
+ ```
262
+
263
+ Rules:
264
+ - `annotations` MUST be omitted when the flag is not supplied.
265
+ - `annotations` order follows runtime annotation stream order.
266
+ - Including annotations MUST NOT alter runtime phase behavior or diagnostics.
267
+
268
+ ## 10) `aeon integrity <...> --json`
269
+
270
+ ### 10.1 Top-level Shape
271
+
272
+ Integrity JSON output MUST start from:
273
+
274
+ ```json
275
+ { "ok": true, "errors": [], "warnings": [] }
276
+ ```
277
+
278
+ `receipt` and `verification` MAY be added depending on the subcommand.
279
+
280
+ ### 10.2 `integrity validate --json`
281
+
282
+ Validation JSON MUST be exactly:
283
+
284
+ ```json
285
+ { "ok": true|false, "errors": [...], "warnings": [...] }
286
+ ```
287
+
288
+ No `receipt` or `verification` object is required for validate.
289
+
290
+ ### 10.3 `integrity sign --json`
291
+
292
+ Signing JSON MUST include:
293
+
294
+ ```json
295
+ {
296
+ "ok": true,
297
+ "receipt": { ... },
298
+ "envelope": { ... }
299
+ }
300
+ ```
301
+
302
+ When `--write` is used, implementations MAY additionally include:
303
+
304
+ - `written`
305
+ - `replaced`
306
+ - `conventionsApplied`
307
+
308
+ Future sidecar-oriented signing behavior SHOULD follow:
309
+
310
+ - default receipt sidecar path: `<file>.receipt.json`
311
+ - explicit override flag: `--receipt <path>`
312
+ - sibling sidecar discovery only for v1
313
+
314
+ ### 10.4 `integrity verify --json`
315
+
316
+ Verification JSON MUST include:
317
+
318
+ ```json
319
+ {
320
+ "ok": true|false,
321
+ "errors": [...],
322
+ "warnings": [...],
323
+ "receipt": { ... },
324
+ "verification": { ... }
325
+ }
326
+ ```
327
+
328
+ Future sidecar-oriented verification behavior SHOULD follow:
329
+
330
+ - default receipt sidecar path: `<file>.receipt.json`
331
+ - explicit override flag: `--receipt <path>`
332
+ - if no sidecar is present, normal envelope verification remains valid unless a
333
+ receipt is explicitly required by the command mode
334
+
335
+ ### 10.5 Receipt Shape
336
+
337
+ When present, `receipt` MUST include:
338
+
339
+ - `source.mediaType = "text/aeon"`
340
+ - `source.encoding = "utf-8"`
341
+ - `source.digestAlgorithm = "sha-256"`
342
+ - `source.digest`
343
+ - `canonical.format = "aeon.canonical"`
344
+ - `canonical.spec = "AEON Core"`
345
+ - `canonical.specRelease = "v1"`
346
+ - `canonical.mode`
347
+ - `canonical.profile`
348
+ - `canonical.outputEncoding = "utf-8"`
349
+ - `canonical.digestAlgorithm = "sha-256"`
350
+ - `canonical.digest`
351
+ - `canonical.length`
352
+ - `producer.implementation`
353
+ - `producer.version`
354
+ - `generated.at`
355
+
356
+ Rules:
357
+
358
+ - `generated.at` MUST be an RFC 3339 / ISO 8601 UTC timestamp.
359
+ - `canonical.payload` SHOULD be included for `integrity sign --json`.
360
+ - `canonical.payload` SHOULD be omitted for `integrity verify --json`.
361
+ - `producer.implementation` MUST use a stable runtime identifier such as
362
+ `aeon-cli-ts` or `aeon-cli-rs`.
363
+
364
+ ### 10.6 Verification Shape
365
+
366
+ When present, `verification` MUST include:
367
+
368
+ - `canonical`
369
+ - `bytes`
370
+ - `checksum`
371
+ - `signature`
372
+ - `replay`
373
+ - `canonicalStream`
374
+
375
+ Rules:
376
+
377
+ - `canonicalStream.length` MUST be the canonical payload length.
378
+ - `replay.performed` MUST be boolean.
379
+ - `replay.status` MUST be one of `match`, `divergent`, or `unavailable`.
380
+ - `replay` status MUST remain separate from signature success/failure.
381
+
382
+ ### 10.7 Receipt Storage Rules
383
+
384
+ Recommended v1 receipt storage rules:
385
+
386
+ - receipt storage SHOULD use detached sibling JSON sidecars
387
+ - the canonical sibling filename is `<document-path>.receipt.json`
388
+ - sidecar discovery SHOULD be filename-based only
389
+ - manifest/index discovery is out of scope for v1
390
+ - envelope pointer fields are out of scope for v1
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @altopelago/aeon-cli
2
+
3
+ Command-line tools for parsing, checking, formatting, finalizing, and inspecting
4
+ AEON documents.
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pnpm add -D @altopelago/aeon-cli
10
+ ```
11
+
12
+ Or run a pinned release directly:
13
+
14
+ ```bash
15
+ npx @altopelago/aeon-cli@0.9.2 check ./document.aeon
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```bash
21
+ aeon check ./document.aeon
22
+ aeon inspect ./document.aeon --json
23
+ aeon finalize ./document.aeon --json
24
+ aeon fmt ./document.aeon --write
25
+ ```
26
+
27
+ ## Commands
28
+
29
+ - `aeon version` - show the CLI version
30
+ - `aeon check <file>` - validate an AEON document with CI-friendly exit codes
31
+ - `aeon doctor` - check environment and contract registry wiring
32
+ - `aeon fmt [file]` - format AEON source, writing to stdout unless `--write` is used
33
+ - `aeon inspect <file>` - inspect Assignment Events, diagnostics, and optional annotations
34
+ - `aeon finalize <file>` - materialize AEON into JSON, map, header, or full views
35
+ - `aeon bind <file>` - run the typed runtime binding pipeline with a schema
36
+ - `aeon integrity validate|verify|sign <file>` - work with integrity envelopes
37
+
38
+ ## Common Options
39
+
40
+ - `--json` - emit machine-readable JSON where supported
41
+ - `--annotations` - include annotation stream records
42
+ - `--annotations-only` - inspect only annotation stream records
43
+ - `--sort-annotations` - sort annotations deterministically
44
+ - `--scope payload|header|full` - choose finalization scope
45
+ - `--projected` and `--include-path <path>` - materialize selected canonical paths
46
+ - `--recovery` - emit partial tooling output while still reporting errors
47
+ - `--max-input-bytes <n>` - fail closed on oversized UTF-8 input
48
+ - `--datatype-policy reserved_only|allow_custom` - control custom datatype acceptance
49
+ - `--rich` - shortcut for `--datatype-policy allow_custom`
50
+
51
+ ## Exit Codes
52
+
53
+ - `0` - no errors
54
+ - `1` - AEON diagnostics or validation errors were present
55
+ - `2` - CLI usage error, missing file, bad option, or unreadable input
56
+
57
+ ## Output Contract
58
+
59
+ The CLI is designed for stable automation. Its observable command behavior is
60
+ tracked in [`OUTPUT_CONTRACT.md`](./OUTPUT_CONTRACT.md).
61
+
62
+ ## Notes
63
+
64
+ - The default processing path is fail-closed.
65
+ - `--recovery` is intended for editors and diagnostics, not production loading.
66
+ - The CLI does not execute AEON documents or coerce values into application
67
+ semantics.