aontu 0.55.0 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/agentsmd.d.ts +1 -0
- package/dist/agentsmd.js +10 -3
- package/dist/agentsmd.js.map +1 -1
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +5 -2
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +10 -3
- package/dist/cli.js +311 -53
- package/dist/cli.js.map +1 -1
- package/dist/diff.d.ts +1 -0
- package/dist/diff.js +3 -2
- package/dist/diff.js.map +1 -1
- package/dist/escape.d.ts +5 -0
- package/dist/escape.js +455 -0
- package/dist/escape.js.map +1 -0
- package/dist/format.d.ts +26 -0
- package/dist/format.js +1489 -0
- package/dist/format.js.map +1 -0
- package/dist/hints.js +39 -1
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +1 -0
- package/dist/jsonschema.js +3 -2
- package/dist/jsonschema.js.map +1 -1
- package/dist/lang.js +84 -6
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +2 -1
- package/dist/lsp.js +4 -4
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +6 -4
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +8 -7
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +6 -6
- package/dist/mod.js.map +1 -1
- package/dist/patch.d.ts +1 -0
- package/dist/patch.js +1 -0
- package/dist/patch.js.map +1 -1
- package/dist/query.d.ts +1 -0
- package/dist/query.js +4 -3
- package/dist/query.js.map +1 -1
- package/dist/reach.d.ts +1 -0
- package/dist/reach.js +3 -2
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +1 -0
- package/dist/relation.js +3 -2
- package/dist/relation.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/std.js +2 -1
- package/dist/std.js.map +1 -1
- package/dist/subsume.d.ts +1 -0
- package/dist/subsume.js +3 -2
- package/dist/subsume.js.map +1 -1
- package/dist/trim.d.ts +1 -0
- package/dist/trim.js +3 -2
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +1 -0
- package/dist/type.js.map +1 -1
- package/dist/utility.d.ts +8 -2
- package/dist/utility.js +9 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/EachFuncVal.js +1 -2
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +23 -0
- package/dist/val/EmitFuncVal.js +261 -0
- package/dist/val/EmitFuncVal.js.map +1 -0
- package/dist/val/FilterFuncVal.js +1 -2
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +16 -0
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +1 -2
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PlaceVal.d.ts +3 -1
- package/dist/val/PlaceVal.js +8 -6
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/StrFuncVal.d.ts +32 -0
- package/dist/val/StrFuncVal.js +292 -0
- package/dist/val/StrFuncVal.js.map +1 -0
- package/dist/vet.d.ts +1 -0
- package/dist/vet.js +1 -1
- package/dist/vet.js.map +1 -1
- package/dist/view.d.ts +2 -1
- package/dist/view.js +379 -8
- package/dist/view.js.map +1 -1
- package/grammar/aontu.abnf +156 -0
- package/grammar/aontu.gbnf +4 -3
- package/grammar/aontu.lark +4 -3
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +2 -1
- package/skill/grammar-card.md +5 -2
- package/src/agentsmd.ts +15 -3
- package/src/aontu.ts +8 -1
- package/src/cli.ts +365 -58
- package/src/diff.ts +7 -2
- package/src/escape.ts +371 -0
- package/src/format.ts +1728 -0
- package/src/hints.ts +53 -1
- package/src/jsonschema.ts +7 -1
- package/src/lang.ts +93 -6
- package/src/lsp.ts +8 -6
- package/src/mcp-server.ts +3 -2
- package/src/mcp.ts +6 -4
- package/src/mod-tool.ts +9 -8
- package/src/mod.ts +6 -6
- package/src/patch.ts +7 -0
- package/src/query.ts +8 -4
- package/src/reach.ts +7 -2
- package/src/relation.ts +7 -2
- package/src/sigdecl.ts +1 -1
- package/src/std.ts +2 -1
- package/src/subsume.ts +7 -2
- package/src/trim.ts +7 -2
- package/src/type.ts +8 -0
- package/src/utility.ts +27 -2
- package/src/val/EachFuncVal.ts +1 -3
- package/src/val/EmitFuncVal.ts +401 -0
- package/src/val/FilterFuncVal.ts +1 -3
- package/src/val/FuncBaseVal.ts +18 -0
- package/src/val/PackFuncVal.ts +1 -3
- package/src/val/PlaceVal.ts +8 -6
- package/src/val/StrFuncVal.ts +334 -0
- package/src/vet.ts +9 -3
- package/src/view.ts +442 -9
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ exports.runWhy = runWhy;
|
|
|
20
20
|
exports.renderWhyText = renderWhyText;
|
|
21
21
|
exports.runSet = runSet;
|
|
22
22
|
exports.runAgentsMd = runAgentsMd;
|
|
23
|
+
exports.runFmt = runFmt;
|
|
23
24
|
exports.watchChange = watchChange;
|
|
24
25
|
exports.watchSignature = watchSignature;
|
|
25
26
|
exports.deprecatedAt = deprecatedAt;
|
|
@@ -39,6 +40,8 @@ const node_os_1 = require("node:os");
|
|
|
39
40
|
const node_readline_1 = require("node:readline");
|
|
40
41
|
const aontu_1 = require("./aontu");
|
|
41
42
|
const report_sarif_1 = require("./report-sarif");
|
|
43
|
+
const lsp_server_1 = require("./lsp-server");
|
|
44
|
+
const mcp_server_1 = require("./mcp-server");
|
|
42
45
|
const jsonschema_1 = require("./jsonschema");
|
|
43
46
|
const mod_tool_1 = require("./mod-tool");
|
|
44
47
|
const mod_1 = require("./mod");
|
|
@@ -46,6 +49,8 @@ const vet_1 = require("./vet");
|
|
|
46
49
|
const reach_1 = require("./reach");
|
|
47
50
|
const view_1 = require("./view");
|
|
48
51
|
const agentsmd_1 = require("./agentsmd");
|
|
52
|
+
const format_1 = require("./format");
|
|
53
|
+
const utility_1 = require("./utility");
|
|
49
54
|
const HELP = `Usage: aontu [options] [file]
|
|
50
55
|
aontu vet [options] <schema> <data> [more-data...]
|
|
51
56
|
aontu subsume [options] <general> <specific>
|
|
@@ -62,6 +67,9 @@ const HELP = `Usage: aontu [options] [file]
|
|
|
62
67
|
aontu why <path> [options] <file>
|
|
63
68
|
aontu set <path>=<value>... --entry <file> --overlay <file>
|
|
64
69
|
aontu agentsmd [--write <AGENTS.md>] <file>
|
|
70
|
+
aontu fmt [-w|-l|--check|-d|--lint] <file>...
|
|
71
|
+
aontu lsp
|
|
72
|
+
aontu mcp [--root <dir>]
|
|
65
73
|
|
|
66
74
|
Evaluate an Aontu source file and print the result as JSON.
|
|
67
75
|
With no file on an interactive terminal, start a REPL.
|
|
@@ -84,6 +92,10 @@ Options:
|
|
|
84
92
|
Every verb takes it too, and a bare root means the
|
|
85
93
|
document's own directory
|
|
86
94
|
--include-root <dir> Shorthand for --trust root:<dir>
|
|
95
|
+
--text-ext <e> Read these extensions as text too, comma-separated
|
|
96
|
+
and without dots (md,sql). .txt needs no flag; a
|
|
97
|
+
named format keeps its meaning, and .js stays
|
|
98
|
+
refused. Every verb takes it
|
|
87
99
|
|
|
88
100
|
Mod options:
|
|
89
101
|
--format <f> text (default) or json
|
|
@@ -91,10 +103,10 @@ Mod options:
|
|
|
91
103
|
|
|
92
104
|
Mod subcommands:
|
|
93
105
|
tidy Resolve the module closure by minimum version selection and
|
|
94
|
-
rewrite mod-lock.aon in canonical form
|
|
95
|
-
verify Check every locked module still means what
|
|
106
|
+
rewrite aontu_meta/mod-lock.aon in canonical form
|
|
107
|
+
verify Check every locked module still means what the lockfile
|
|
96
108
|
pins, and change nothing (the CI gate; tidy rewrites)
|
|
97
|
-
vendor Materialise the locked closure into
|
|
109
|
+
vendor Materialise the locked closure into aontu_meta/vendor/
|
|
98
110
|
manifest Print the OCI artifact a publish would push, gated on the
|
|
99
111
|
breaking check against --against
|
|
100
112
|
|
|
@@ -175,8 +187,8 @@ Why options:
|
|
|
175
187
|
Why exit codes mirror get's: 0 explained, 1 the path names nothing,
|
|
176
188
|
2 usage, 4 the document does not stand up on its own.
|
|
177
189
|
|
|
178
|
-
View kinds: tree, matrix, graph, layer, sets, layers,
|
|
179
|
-
(the poset takes several files). The figure goes to stdout, the loss
|
|
190
|
+
View kinds: doc, lattice, tree, matrix, graph, layer, sets, layers,
|
|
191
|
+
ladder, poset (the poset takes several files). The figure goes to stdout, the loss
|
|
180
192
|
report to stderr. With --views it draws every figure a document
|
|
181
193
|
declares as data, from one evaluation: each declaration names its own
|
|
182
194
|
kind and out file, nothing is written unless every figure rendered,
|
|
@@ -184,13 +196,13 @@ and --check gates the committed set.
|
|
|
184
196
|
|
|
185
197
|
View options:
|
|
186
198
|
--as <profile> text | mermaid | dot | er | svg, per kind: doc,
|
|
187
|
-
tree, matrix, sets and layers draw text
|
|
188
|
-
or svg; graph draws mermaid (default),
|
|
189
|
-
layer draws text (default), mermaid or
|
|
190
|
-
and poset draw mermaid (default) or dot
|
|
199
|
+
lattice, tree, matrix, sets and layers draw text
|
|
200
|
+
(default) or svg; graph draws mermaid (default),
|
|
201
|
+
dot or er; layer draws text (default), mermaid or
|
|
202
|
+
svg; ladder and poset draw mermaid (default) or dot
|
|
191
203
|
--at <path> Restrict the figure to nodes under this path; the
|
|
192
|
-
subtree doc draws; the
|
|
193
|
-
where the poset compares
|
|
204
|
+
subtree doc draws; the subtree the lattice counts;
|
|
205
|
+
the path the ladder draws; where the poset compares
|
|
194
206
|
--views <path> Draw every figure the document declares at this
|
|
195
207
|
path, one evaluation, all or nothing; each
|
|
196
208
|
declaration names its own kind and out file
|
|
@@ -269,6 +281,32 @@ Agentsmd options:
|
|
|
269
281
|
Agentsmd exit codes: 0 generated, 2 usage, 4 the document does not
|
|
270
282
|
stand up on its own.
|
|
271
283
|
|
|
284
|
+
Fmt options:
|
|
285
|
+
-w, --write Rewrite each file in place, when its form would change
|
|
286
|
+
-l, --list Print the name of each file whose form would change
|
|
287
|
+
--check Like --list, and exit 1 when any would: the CI gate
|
|
288
|
+
-d, --diff Print a unified diff for each file whose form would
|
|
289
|
+
change
|
|
290
|
+
--lint Report the style findings, key case and repeated
|
|
291
|
+
shapes, on standard error, and print nothing else
|
|
292
|
+
--strict With --lint, and exit 1 when there is a finding
|
|
293
|
+
|
|
294
|
+
The fmt verb prints one document in the agreed form; with no file it
|
|
295
|
+
reads standard input. Several files need one of the options above.
|
|
296
|
+
|
|
297
|
+
Fmt exit codes: 0 formatted or clean, 1 a --check file would change or
|
|
298
|
+
a --strict finding, 2 usage, 4 a document does not parse.
|
|
299
|
+
|
|
300
|
+
The lsp verb runs the language server over standard input and output
|
|
301
|
+
(LSP: JSON-RPC with Content-Length framing) until the client exits;
|
|
302
|
+
editors launch it with no arguments. The standalone aontu-lsp binary
|
|
303
|
+
runs the same server.
|
|
304
|
+
|
|
305
|
+
The mcp verb runs the Model Context Protocol server over standard
|
|
306
|
+
input and output (newline-delimited JSON-RPC), confined below --root
|
|
307
|
+
when one is given. It is part of the npm build, as the standalone
|
|
308
|
+
aontu-mcp binary is.
|
|
309
|
+
|
|
272
310
|
REPL commands:
|
|
273
311
|
:help Show REPL help
|
|
274
312
|
:load <file> Evaluate a document and hold it for the commands below
|
|
@@ -333,15 +371,16 @@ function makeTrustWarn() {
|
|
|
333
371
|
// entryRoot (the entry file's directory, or the working directory for
|
|
334
372
|
// stdin/REPL).
|
|
335
373
|
function trustOpts(trust, entryRoot) {
|
|
374
|
+
const text = 0 === trust.textExt.length ? {} : { textExt: trust.textExt };
|
|
336
375
|
switch (trust.kind) {
|
|
337
376
|
case 'none':
|
|
338
|
-
return { trust: { include: 'none' } };
|
|
377
|
+
return { ...text, trust: { include: 'none' } };
|
|
339
378
|
case 'root':
|
|
340
|
-
return { trust: { include: { root: trust.dir ?? entryRoot } } };
|
|
379
|
+
return { ...text, trust: { include: { root: trust.dir ?? entryRoot } } };
|
|
341
380
|
case 'system':
|
|
342
|
-
return {};
|
|
381
|
+
return { ...text };
|
|
343
382
|
default: // system-warn: today's default plus the warning window
|
|
344
|
-
return { trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
|
|
383
|
+
return { ...text, trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
|
|
345
384
|
}
|
|
346
385
|
}
|
|
347
386
|
// EVERY VERB honours the include capability, not just the bare
|
|
@@ -356,7 +395,8 @@ function trustOpts(trust, entryRoot) {
|
|
|
356
395
|
// already printed: the caller answers the usage class.
|
|
357
396
|
function takeTrust(argv) {
|
|
358
397
|
const rest = [];
|
|
359
|
-
let trust = { kind: 'system-warn' };
|
|
398
|
+
let trust = { kind: 'system-warn', textExt: [] };
|
|
399
|
+
let textExt = [];
|
|
360
400
|
for (let i = 0; i < argv.length; i++) {
|
|
361
401
|
const arg = argv[i];
|
|
362
402
|
if ('--trust' === arg) {
|
|
@@ -373,18 +413,42 @@ function takeTrust(argv) {
|
|
|
373
413
|
process.stderr.write('aontu: --include-root needs a directory\n');
|
|
374
414
|
return undefined;
|
|
375
415
|
}
|
|
376
|
-
trust = { kind: 'root', dir };
|
|
416
|
+
trust = { kind: 'root', dir, textExt };
|
|
417
|
+
}
|
|
418
|
+
else if ('--text-ext' === arg) {
|
|
419
|
+
const list = null == argv[i + 1] ? undefined : parseTextExt(argv[++i]);
|
|
420
|
+
if (null == list) {
|
|
421
|
+
process.stderr.write('aontu: --text-ext needs extensions, without dots' +
|
|
422
|
+
' (--text-ext md,sql)\n');
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
textExt = [...textExt, ...list];
|
|
377
426
|
}
|
|
378
427
|
else {
|
|
379
428
|
rest.push(arg);
|
|
380
429
|
}
|
|
381
430
|
}
|
|
382
|
-
return { argv: rest, trust };
|
|
431
|
+
return { argv: rest, trust: { ...trust, textExt } };
|
|
432
|
+
}
|
|
433
|
+
// `md,sql` or `.md,.sql` -- the dot is accepted and dropped, because a
|
|
434
|
+
// reader who has just written `@"notes.txt"` reaches for one. An empty
|
|
435
|
+
// element, or anything that is not an extension, is a usage error
|
|
436
|
+
// rather than a silently ignored word: a flag that quietly does
|
|
437
|
+
// nothing is how a document ends up refused with no reason visible.
|
|
438
|
+
function parseTextExt(arg) {
|
|
439
|
+
const out = [];
|
|
440
|
+
for (const raw of arg.split(',')) {
|
|
441
|
+
const ext = raw.trim().replace(/^\./, '').toLowerCase();
|
|
442
|
+
if ('' === ext || !/^[a-z0-9]+$/.test(ext)) {
|
|
443
|
+
return undefined;
|
|
444
|
+
}
|
|
445
|
+
out.push(ext);
|
|
446
|
+
}
|
|
447
|
+
return out;
|
|
383
448
|
}
|
|
384
449
|
// The evaluator options a REPL session's capability means.
|
|
385
450
|
function replTrust(state, entryRoot) {
|
|
386
|
-
|
|
387
|
-
return null == capability ? {} : { trust: capability };
|
|
451
|
+
return verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRoot);
|
|
388
452
|
}
|
|
389
453
|
// The capability a verb's engine runs under. `system` and the staged
|
|
390
454
|
// warning default both mean today's behaviour (no option); the warning
|
|
@@ -400,6 +464,18 @@ function verbTrust(trust, entryRoot) {
|
|
|
400
464
|
return undefined;
|
|
401
465
|
}
|
|
402
466
|
}
|
|
467
|
+
// THE INCLUDE OPTIONS A VERB RUNS UNDER, spread into its engine call:
|
|
468
|
+
// the capability above, and the extensions `--text-ext` widened. Both
|
|
469
|
+
// are absent when unset rather than present-and-undefined, so a verb's
|
|
470
|
+
// options bag is byte-identical to what it was before either flag
|
|
471
|
+
// existed and no engine sees a key it has to ignore.
|
|
472
|
+
function verbOpts(trust, entryRoot) {
|
|
473
|
+
const include = verbTrust(trust, entryRoot);
|
|
474
|
+
return {
|
|
475
|
+
...(undefined === include ? {} : { trust: include }),
|
|
476
|
+
...(0 === trust.textExt.length ? {} : { textExt: trust.textExt }),
|
|
477
|
+
};
|
|
478
|
+
}
|
|
403
479
|
// The directory a bare `--trust root` confines to for a verb: the
|
|
404
480
|
// primary document's own, matching the bare command's entry root.
|
|
405
481
|
function entryRootOf(file) {
|
|
@@ -505,7 +581,7 @@ function replCommand(state, line, read) {
|
|
|
505
581
|
if (':why' === cmd) {
|
|
506
582
|
const report = (0, aontu_1.why)(src, path, {
|
|
507
583
|
path: state.name,
|
|
508
|
-
|
|
584
|
+
...verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRootOf(state.name)),
|
|
509
585
|
});
|
|
510
586
|
return report.ok
|
|
511
587
|
? answer(renderWhyText(report.record))
|
|
@@ -515,7 +591,7 @@ function replCommand(state, line, read) {
|
|
|
515
591
|
? 'keys' : 'canon' === state.mode ? 'canon' : 'json';
|
|
516
592
|
const report = (0, aontu_1.get)(src, path, {
|
|
517
593
|
view, path: state.name,
|
|
518
|
-
|
|
594
|
+
...verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRootOf(state.name)),
|
|
519
595
|
});
|
|
520
596
|
return report.ok
|
|
521
597
|
? answer(report.out)
|
|
@@ -746,7 +822,7 @@ function vetOnce(args, trust) {
|
|
|
746
822
|
const findings = [];
|
|
747
823
|
for (const source of sources) {
|
|
748
824
|
const report = (0, aontu_1.vet)(schemaSrc, source.src, {
|
|
749
|
-
|
|
825
|
+
...verbOpts(trust, entryRootOf(args.schema)),
|
|
750
826
|
at: args.at,
|
|
751
827
|
closed: args.closed,
|
|
752
828
|
partial: args.partial,
|
|
@@ -985,7 +1061,7 @@ function runSubsume(argv) {
|
|
|
985
1061
|
return 2;
|
|
986
1062
|
}
|
|
987
1063
|
const report = (0, aontu_1.subsume)(generalSrc, specificSrc, {
|
|
988
|
-
|
|
1064
|
+
...verbOpts(trust, entryRootOf(args.general)),
|
|
989
1065
|
profile: args.profile,
|
|
990
1066
|
at: args.at,
|
|
991
1067
|
generalUrl: args.general,
|
|
@@ -1165,15 +1241,17 @@ function oldVersion(spec, file) {
|
|
|
1165
1241
|
// The document's own compatibility declaration: `$.aontu_policy.compat`,
|
|
1166
1242
|
// a disjunction whose default is the declared mode. Undefined when the
|
|
1167
1243
|
// key is absent or does not spell a mode.
|
|
1168
|
-
function policyCompat(newSrc, path,
|
|
1244
|
+
function policyCompat(newSrc, path, include) {
|
|
1169
1245
|
const aontu = new aontu_1.Aontu();
|
|
1170
1246
|
const ctx = aontu.ctx({ collect: true });
|
|
1171
1247
|
// The declaration is read by EVALUATING the document, so this leg
|
|
1172
|
-
// runs the include resolver too and has to run it under the
|
|
1173
|
-
//
|
|
1174
|
-
// through an unconfined resolver would confine the
|
|
1175
|
-
// not the question (use-cases/REVIEW.md finding G)
|
|
1176
|
-
|
|
1248
|
+
// runs the include resolver too and has to run it under BOTH of the
|
|
1249
|
+
// verb's include options -- a `breaking --trust none` that read its
|
|
1250
|
+
// own mode through an unconfined resolver would confine the
|
|
1251
|
+
// comparison and not the question (use-cases/REVIEW.md finding G),
|
|
1252
|
+
// and one that took the capability alone read no mode at all when
|
|
1253
|
+
// the declaration arrived through a `--text-ext` include.
|
|
1254
|
+
const v = aontu.unify(newSrc, { path, ...(0, utility_1.includeOpts)(include) }, ctx);
|
|
1177
1255
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
1178
1256
|
return undefined;
|
|
1179
1257
|
}
|
|
@@ -1266,7 +1344,7 @@ function runBreaking(argv) {
|
|
|
1266
1344
|
// neither means backward, the index's framing (v1-valid documents
|
|
1267
1345
|
// stay valid).
|
|
1268
1346
|
const mode = args.mode ??
|
|
1269
|
-
policyCompat(newSrc, args.file,
|
|
1347
|
+
policyCompat(newSrc, args.file, verbOpts(trust, entryRootOf(args.file))) ??
|
|
1270
1348
|
'backward';
|
|
1271
1349
|
if ('none' === mode) {
|
|
1272
1350
|
// The document declares no compatibility promise: nothing to check.
|
|
@@ -1309,7 +1387,7 @@ function runBreaking(argv) {
|
|
|
1309
1387
|
const oldPath = old.path;
|
|
1310
1388
|
for (const check of checks) {
|
|
1311
1389
|
const report = (0, aontu_1.subsume)(check.general[0], check.specific[0], {
|
|
1312
|
-
|
|
1390
|
+
...verbOpts(trust, entryRootOf(args.file)),
|
|
1313
1391
|
at: args.at,
|
|
1314
1392
|
generalUrl: check.general[1],
|
|
1315
1393
|
specificUrl: check.specific[1],
|
|
@@ -1439,7 +1517,7 @@ function runTrim(argv) {
|
|
|
1439
1517
|
return 2;
|
|
1440
1518
|
}
|
|
1441
1519
|
const report = (0, aontu_1.trimCheck)(src, {
|
|
1442
|
-
path: files[0],
|
|
1520
|
+
path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
1443
1521
|
});
|
|
1444
1522
|
const text = 'json' === format
|
|
1445
1523
|
? renderTrimJson(report)
|
|
@@ -1490,8 +1568,8 @@ const REACHES_EXIT = {
|
|
|
1490
1568
|
error: 4,
|
|
1491
1569
|
};
|
|
1492
1570
|
const VIEW_HELP = 'aontu view <kind> [options] <file>... (try --help)';
|
|
1493
|
-
const VIEW_KINDS = ['doc', 'tree', 'matrix', 'graph', 'layer', 'sets', 'layers',
|
|
1494
|
-
'poset'];
|
|
1571
|
+
const VIEW_KINDS = ['doc', 'lattice', 'tree', 'matrix', 'graph', 'layer', 'sets', 'layers',
|
|
1572
|
+
'ladder', 'poset'];
|
|
1495
1573
|
const VIEW_PROFILES = ['text', 'mermaid', 'dot', 'er', 'svg'];
|
|
1496
1574
|
const VIEW_EDGES = ['upward', 'all', 'none'];
|
|
1497
1575
|
// The styles the CLI accepts (VIEWS.0.md, "7. Styling"). `auto` is
|
|
@@ -1605,6 +1683,14 @@ function runMod(argv) {
|
|
|
1605
1683
|
process.stderr.write(`aontu: mod needs tidy, verify, vendor or manifest\n${MOD_HELP}\n`);
|
|
1606
1684
|
return 2;
|
|
1607
1685
|
}
|
|
1686
|
+
// THE OLD LAYOUT IS NAMED, NOT READ. The lockfile and the vendored
|
|
1687
|
+
// closure moved under aontu_meta/; a project that still carries them
|
|
1688
|
+
// at its root would otherwise look untouched by any of these verbs,
|
|
1689
|
+
// which is the one silence worth breaking.
|
|
1690
|
+
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'aon_vendor')) || (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'mod-lock.aon'))) {
|
|
1691
|
+
process.stderr.write('aontu: aon_vendor/ and mod-lock.aon now live under aontu_meta/: ' +
|
|
1692
|
+
'move them, or run aontu mod tidy and aontu mod vendor\n');
|
|
1693
|
+
}
|
|
1608
1694
|
// `--against` gates a manifest and means nothing to the other two;
|
|
1609
1695
|
// accepting it there would say it had been honoured.
|
|
1610
1696
|
if (null != against && 'manifest' !== sub) {
|
|
@@ -1764,7 +1850,7 @@ function runRelations(argv) {
|
|
|
1764
1850
|
return 2;
|
|
1765
1851
|
}
|
|
1766
1852
|
const report = (0, aontu_1.relationCheck)(src, {
|
|
1767
|
-
path: files[0],
|
|
1853
|
+
path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
1768
1854
|
});
|
|
1769
1855
|
const text = 'json' === format
|
|
1770
1856
|
? renderRelationsJson(report)
|
|
@@ -1825,7 +1911,7 @@ function runReaches(argv) {
|
|
|
1825
1911
|
}
|
|
1826
1912
|
const report = (0, reach_1.reachCheck)(src, rest[0], rest[1], {
|
|
1827
1913
|
path: rest[2], relation,
|
|
1828
|
-
|
|
1914
|
+
...verbOpts(trust, entryRootOf(rest[2])),
|
|
1829
1915
|
});
|
|
1830
1916
|
const text = 'json' === format
|
|
1831
1917
|
? renderReachesJson(report)
|
|
@@ -2052,7 +2138,7 @@ function runView(argv) {
|
|
|
2052
2138
|
kind,
|
|
2053
2139
|
path: files[0],
|
|
2054
2140
|
roots,
|
|
2055
|
-
|
|
2141
|
+
...verbOpts(trust, entryRootOf(files[0])),
|
|
2056
2142
|
docs: files.slice(1).map((path, i) => ({ src: srcs[i + 1], path })),
|
|
2057
2143
|
});
|
|
2058
2144
|
if ('json' === format) {
|
|
@@ -2122,7 +2208,7 @@ function runViewSet(rest, opts, trust, how) {
|
|
|
2122
2208
|
return 2;
|
|
2123
2209
|
}
|
|
2124
2210
|
const report = (0, view_1.viewSet)(src, {
|
|
2125
|
-
...opts, path: file,
|
|
2211
|
+
...opts, path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2126
2212
|
});
|
|
2127
2213
|
if ('json' === how.format) {
|
|
2128
2214
|
process.stdout.write(renderViewSetJson(report) + '\n');
|
|
@@ -2319,7 +2405,7 @@ function runJsonSchema(argv) {
|
|
|
2319
2405
|
return 2;
|
|
2320
2406
|
}
|
|
2321
2407
|
const report = (0, jsonschema_1.jsonSchema)(src, {
|
|
2322
|
-
at, path: files[0],
|
|
2408
|
+
at, path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
2323
2409
|
});
|
|
2324
2410
|
if ('json' === format) {
|
|
2325
2411
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2402,8 +2488,7 @@ function runHash(argv) {
|
|
|
2402
2488
|
}
|
|
2403
2489
|
// The file's own directory is the include base, as every verb
|
|
2404
2490
|
// resolves a named file (vet's aontuForPath rule).
|
|
2405
|
-
const
|
|
2406
|
-
const aontu = new aontu_1.Aontu(null == capability ? undefined : { trust: capability });
|
|
2491
|
+
const aontu = new aontu_1.Aontu(verbOpts(trust, entryRootOf(files[0])));
|
|
2407
2492
|
const ctx = aontu.ctx({ collect: true });
|
|
2408
2493
|
const v = aontu.unify(src, { path: files[0] }, ctx);
|
|
2409
2494
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
@@ -2507,7 +2592,7 @@ function runGet(argv) {
|
|
|
2507
2592
|
return 2;
|
|
2508
2593
|
}
|
|
2509
2594
|
const report = (0, aontu_1.get)(src, path, {
|
|
2510
|
-
view, depth, path: file,
|
|
2595
|
+
view, depth, path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2511
2596
|
});
|
|
2512
2597
|
if ('json' === format) {
|
|
2513
2598
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2582,7 +2667,7 @@ function runWhy(argv) {
|
|
|
2582
2667
|
return 2;
|
|
2583
2668
|
}
|
|
2584
2669
|
const report = (0, aontu_1.why)(src, path, {
|
|
2585
|
-
path: file,
|
|
2670
|
+
path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2586
2671
|
});
|
|
2587
2672
|
if ('json' === format) {
|
|
2588
2673
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2703,7 +2788,7 @@ function runSet(argv) {
|
|
|
2703
2788
|
}
|
|
2704
2789
|
}
|
|
2705
2790
|
const report = (0, aontu_1.patch)(entrySrc, overlaySrc, assignments, {
|
|
2706
|
-
|
|
2791
|
+
...verbOpts(trust, entryRootOf(entry)),
|
|
2707
2792
|
entryPath: entry,
|
|
2708
2793
|
overlayPath: overlayFile,
|
|
2709
2794
|
inPlace,
|
|
@@ -2823,7 +2908,7 @@ function runAgentsMd(argv) {
|
|
|
2823
2908
|
}
|
|
2824
2909
|
const report = (0, aontu_1.agentsMd)(src, {
|
|
2825
2910
|
name: files[0], path: files[0],
|
|
2826
|
-
|
|
2911
|
+
...verbOpts(trust, entryRootOf(files[0])),
|
|
2827
2912
|
});
|
|
2828
2913
|
if (!report.ok) {
|
|
2829
2914
|
process.stderr.write(report.findings.map(renderFinding).join('\n') + '\n');
|
|
@@ -2869,6 +2954,155 @@ function runAgentsMd(argv) {
|
|
|
2869
2954
|
// on the parity-probe discipline in AGENTS.md, which derives expected
|
|
2870
2955
|
// spec values by piping BOTH CLIs and comparing. A truncated pipe there
|
|
2871
2956
|
// reads as a port divergence.
|
|
2957
|
+
// ---------------------------------------------------------------------
|
|
2958
|
+
// The source formatter (docs/design/FMT.0.md): one agreed form, in the
|
|
2959
|
+
// tradition of gofmt. The verb prints, lists, checks, diffs or rewrites;
|
|
2960
|
+
// the form itself is the library's (ts/src/format.ts), and the two
|
|
2961
|
+
// ports agree on it row by row in test/spec/fmt.tsv.
|
|
2962
|
+
const FMT_HELP = 'aontu fmt [-w|-l|--check|-d|--lint] <file>... (try --help)';
|
|
2963
|
+
function runFmt(argv) {
|
|
2964
|
+
const files = [];
|
|
2965
|
+
const flags = {
|
|
2966
|
+
write: false, list: false, check: false, diff: false, lint: false, strict: false,
|
|
2967
|
+
};
|
|
2968
|
+
for (const arg of argv) {
|
|
2969
|
+
if ('-h' === arg || '--help' === arg) {
|
|
2970
|
+
process.stdout.write(HELP);
|
|
2971
|
+
return 0;
|
|
2972
|
+
}
|
|
2973
|
+
if ('-w' === arg || '--write' === arg) {
|
|
2974
|
+
flags.write = true;
|
|
2975
|
+
}
|
|
2976
|
+
else if ('-l' === arg || '--list' === arg) {
|
|
2977
|
+
flags.list = true;
|
|
2978
|
+
}
|
|
2979
|
+
else if ('--check' === arg) {
|
|
2980
|
+
flags.check = true;
|
|
2981
|
+
}
|
|
2982
|
+
else if ('-d' === arg || '--diff' === arg) {
|
|
2983
|
+
flags.diff = true;
|
|
2984
|
+
}
|
|
2985
|
+
else if ('--lint' === arg) {
|
|
2986
|
+
flags.lint = true;
|
|
2987
|
+
}
|
|
2988
|
+
else if ('--strict' === arg) {
|
|
2989
|
+
flags.lint = true;
|
|
2990
|
+
flags.strict = true;
|
|
2991
|
+
}
|
|
2992
|
+
else if (arg.startsWith('-')) {
|
|
2993
|
+
process.stderr.write(`aontu: unknown fmt option ${arg} (try --help)\n`);
|
|
2994
|
+
return 2;
|
|
2995
|
+
}
|
|
2996
|
+
else {
|
|
2997
|
+
files.push(arg);
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
if (0 === files.length) {
|
|
3001
|
+
// Standard input: formatted onto standard output, or listed,
|
|
3002
|
+
// checked and diffed under the name <stdin>. It cannot be written
|
|
3003
|
+
// back.
|
|
3004
|
+
if (flags.write) {
|
|
3005
|
+
process.stderr.write(`aontu: --write needs a file\n${FMT_HELP}\n`);
|
|
3006
|
+
return 2;
|
|
3007
|
+
}
|
|
3008
|
+
return new Promise((resolve) => {
|
|
3009
|
+
let src = '';
|
|
3010
|
+
process.stdin.setEncoding('utf8');
|
|
3011
|
+
process.stdin.on('data', (d) => (src += d));
|
|
3012
|
+
process.stdin.on('end', () => resolve(fmtOne('<stdin>', src, flags)));
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
3015
|
+
// Several files onto standard output would be one stream nobody can
|
|
3016
|
+
// split again (the note's X-6): the verb refuses unless an option
|
|
3017
|
+
// says what to do with each.
|
|
3018
|
+
if (1 < files.length && !fmtQuiet(flags)) {
|
|
3019
|
+
process.stderr.write(`aontu: fmt prints one file; with ${files.length}, say --write, ` +
|
|
3020
|
+
`--list, --check, --diff or --lint\n${FMT_HELP}\n`);
|
|
3021
|
+
return 2;
|
|
3022
|
+
}
|
|
3023
|
+
let worst = 0;
|
|
3024
|
+
for (const file of files) {
|
|
3025
|
+
let src;
|
|
3026
|
+
try {
|
|
3027
|
+
src = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
3028
|
+
}
|
|
3029
|
+
catch (err) {
|
|
3030
|
+
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
3031
|
+
return 2;
|
|
3032
|
+
}
|
|
3033
|
+
worst = Math.max(worst, fmtOne(file, src, flags));
|
|
3034
|
+
}
|
|
3035
|
+
return worst;
|
|
3036
|
+
}
|
|
3037
|
+
// An option that says what to do with a file, in place of printing
|
|
3038
|
+
// it: what to do when its form would change, or the lint.
|
|
3039
|
+
function fmtQuiet(flags) {
|
|
3040
|
+
return flags.write || flags.list || flags.check || flags.diff || flags.lint;
|
|
3041
|
+
}
|
|
3042
|
+
// One document: 0 printed, clean or done; 1 a --check that would
|
|
3043
|
+
// change, or a --strict finding; 2 a file that cannot be written; 4 a
|
|
3044
|
+
// document that does not format, with the finding that says why. The
|
|
3045
|
+
// style findings go to standard error, one line each, in the shape
|
|
3046
|
+
// every linter prints: `file:line:col: rule: message`.
|
|
3047
|
+
function fmtOne(name, src, flags) {
|
|
3048
|
+
const report = (0, format_1.format)(src, { path: name, lint: flags.lint });
|
|
3049
|
+
if ('error' === report.verdict) {
|
|
3050
|
+
process.stderr.write(`aontu: ${name} was not formatted\n` +
|
|
3051
|
+
report.errors.map(renderFinding).join('\n') + '\n');
|
|
3052
|
+
return 4;
|
|
3053
|
+
}
|
|
3054
|
+
for (const f of report.findings) {
|
|
3055
|
+
process.stderr.write(`${name}:${f.line}:${f.col}: ${f.rule}: ${f.message}\n`);
|
|
3056
|
+
}
|
|
3057
|
+
const strict = flags.strict && 0 < report.findings.length ? 1 : 0;
|
|
3058
|
+
if (!fmtQuiet(flags)) {
|
|
3059
|
+
process.stdout.write(report.text);
|
|
3060
|
+
return 0;
|
|
3061
|
+
}
|
|
3062
|
+
if (!report.changed) {
|
|
3063
|
+
return strict;
|
|
3064
|
+
}
|
|
3065
|
+
if (flags.list || flags.check) {
|
|
3066
|
+
process.stdout.write(name + '\n');
|
|
3067
|
+
}
|
|
3068
|
+
if (flags.diff) {
|
|
3069
|
+
process.stdout.write((0, format_1.unifiedDiff)(name, src, report.text));
|
|
3070
|
+
}
|
|
3071
|
+
if (flags.write) {
|
|
3072
|
+
try {
|
|
3073
|
+
(0, node_fs_1.writeFileSync)(name, report.text);
|
|
3074
|
+
}
|
|
3075
|
+
catch (err) {
|
|
3076
|
+
process.stderr.write(`aontu: cannot write ${name}: ${err.message}\n`);
|
|
3077
|
+
return 2;
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
return flags.check ? 1 : strict;
|
|
3081
|
+
}
|
|
3082
|
+
// The real pair takes the process's own stdin and stdout, which no
|
|
3083
|
+
// in-process test can lend it; the executable-entry tests in
|
|
3084
|
+
// cli.test.ts run each through a child process instead, so these two
|
|
3085
|
+
// lines are excluded from the in-process count, as the stdio wiring
|
|
3086
|
+
// of lsp-server.ts is.
|
|
3087
|
+
/* node:coverage ignore next 4 */
|
|
3088
|
+
const SERVERS = {
|
|
3089
|
+
lsp: () => void (0, lsp_server_1.main)(),
|
|
3090
|
+
mcp: (argv) => void (0, mcp_server_1.main)(undefined, undefined, undefined, undefined, argv),
|
|
3091
|
+
};
|
|
3092
|
+
// undefined: the server took the process; a number: an answer the CLI
|
|
3093
|
+
// gives itself, --help or a usage error.
|
|
3094
|
+
function runLsp(argv, servers) {
|
|
3095
|
+
for (const arg of argv) {
|
|
3096
|
+
if ('-h' === arg || '--help' === arg) {
|
|
3097
|
+
process.stdout.write(HELP);
|
|
3098
|
+
return 0;
|
|
3099
|
+
}
|
|
3100
|
+
process.stderr.write(`aontu: lsp takes no arguments (try --help)\n`);
|
|
3101
|
+
return 2;
|
|
3102
|
+
}
|
|
3103
|
+
servers.lsp();
|
|
3104
|
+
return undefined;
|
|
3105
|
+
}
|
|
2872
3106
|
function finish(code) {
|
|
2873
3107
|
process.exitCode = code;
|
|
2874
3108
|
}
|
|
@@ -2876,20 +3110,20 @@ function finish(code) {
|
|
|
2876
3110
|
// spelling, so the caller owns the usage error.
|
|
2877
3111
|
function parseTrustArg(value) {
|
|
2878
3112
|
if ('system' === value) {
|
|
2879
|
-
return { kind: 'system' };
|
|
3113
|
+
return { kind: 'system', textExt: [] };
|
|
2880
3114
|
}
|
|
2881
3115
|
if ('none' === value) {
|
|
2882
|
-
return { kind: 'none' };
|
|
3116
|
+
return { kind: 'none', textExt: [] };
|
|
2883
3117
|
}
|
|
2884
3118
|
if ('root' === value) {
|
|
2885
|
-
return { kind: 'root' };
|
|
3119
|
+
return { kind: 'root', textExt: [] };
|
|
2886
3120
|
}
|
|
2887
3121
|
if (value.startsWith('root:') && 'root:'.length < value.length) {
|
|
2888
|
-
return { kind: 'root', dir: value.slice('root:'.length) };
|
|
3122
|
+
return { kind: 'root', dir: value.slice('root:'.length), textExt: [] };
|
|
2889
3123
|
}
|
|
2890
3124
|
return undefined;
|
|
2891
3125
|
}
|
|
2892
|
-
function main(argv) {
|
|
3126
|
+
function main(argv, servers = SERVERS) {
|
|
2893
3127
|
// COLOUR OFF WHEN THE DESTINATION IS NOT A TERMINAL. Error frames
|
|
2894
3128
|
// hardcoded their ANSI escapes, so a piped report and a `--jsonl`
|
|
2895
3129
|
// answer carried terminal control codes into whatever read them (the
|
|
@@ -2906,7 +3140,8 @@ function main(argv) {
|
|
|
2906
3140
|
// overwritten twice. In a tool loop that reads as a passing
|
|
2907
3141
|
// validation. Counting them is what lets the refusal below happen.
|
|
2908
3142
|
const files = [];
|
|
2909
|
-
let trust = { kind: 'system-warn' };
|
|
3143
|
+
let trust = { kind: 'system-warn', textExt: [] };
|
|
3144
|
+
let textExt = [];
|
|
2910
3145
|
// The REPL's SESSION protocol (G7 phase 7): one JSON line per
|
|
2911
3146
|
// answer, so a harness can drive the session. Named --jsonl rather
|
|
2912
3147
|
// than the design's --json, which would read as the `:json` output
|
|
@@ -2933,6 +3168,16 @@ function main(argv) {
|
|
|
2933
3168
|
if ('agentsmd' === argv[2]) {
|
|
2934
3169
|
return finish(runAgentsMd(argv.slice(3)));
|
|
2935
3170
|
}
|
|
3171
|
+
if ('fmt' === argv[2]) {
|
|
3172
|
+
return void Promise.resolve(runFmt(argv.slice(3))).then(finish);
|
|
3173
|
+
}
|
|
3174
|
+
if ('lsp' === argv[2]) {
|
|
3175
|
+
const code = runLsp(argv.slice(3), servers);
|
|
3176
|
+
return undefined === code ? undefined : finish(code);
|
|
3177
|
+
}
|
|
3178
|
+
if ('mcp' === argv[2]) {
|
|
3179
|
+
return servers.mcp(argv.slice(3));
|
|
3180
|
+
}
|
|
2936
3181
|
if ('set' === argv[2]) {
|
|
2937
3182
|
return finish(runSet(argv.slice(3)));
|
|
2938
3183
|
}
|
|
@@ -3000,7 +3245,16 @@ function main(argv) {
|
|
|
3000
3245
|
process.stderr.write('aontu: --include-root needs a directory\n');
|
|
3001
3246
|
return finish(2);
|
|
3002
3247
|
}
|
|
3003
|
-
trust = { kind: 'root', dir };
|
|
3248
|
+
trust = { kind: 'root', dir, textExt };
|
|
3249
|
+
}
|
|
3250
|
+
else if ('--text-ext' === arg) {
|
|
3251
|
+
const list = null == args[i + 1] ? undefined : parseTextExt(args[++i]);
|
|
3252
|
+
if (null == list) {
|
|
3253
|
+
process.stderr.write('aontu: --text-ext needs extensions, without dots' +
|
|
3254
|
+
' (--text-ext md,sql)\n');
|
|
3255
|
+
return finish(2);
|
|
3256
|
+
}
|
|
3257
|
+
textExt = [...textExt, ...list];
|
|
3004
3258
|
}
|
|
3005
3259
|
else if (arg.startsWith('-')) {
|
|
3006
3260
|
process.stderr.write(`aontu: unknown option ${arg} (try --help)\n`);
|
|
@@ -3024,6 +3278,10 @@ function main(argv) {
|
|
|
3024
3278
|
' (try --help)\n');
|
|
3025
3279
|
return finish(2);
|
|
3026
3280
|
}
|
|
3281
|
+
// The extensions ride with the capability from here on, so the three
|
|
3282
|
+
// entry shapes below (file, REPL, stdin) each get them by threading
|
|
3283
|
+
// the one value they already thread.
|
|
3284
|
+
trust = { ...trust, textExt };
|
|
3027
3285
|
const file = files[0];
|
|
3028
3286
|
if (null != file) {
|
|
3029
3287
|
finish(runFile(file, mode, trust));
|