aontu 0.54.0 → 0.56.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 +3 -2
- package/dist/aontu.js +5 -2
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +5 -2
- package/dist/cli.js +310 -50
- 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/format.d.ts +17 -0
- package/dist/format.js +1000 -0
- package/dist/format.js.map +1 -0
- package/dist/hints.js +8 -0
- 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 +64 -5
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +2 -1
- package/dist/lsp.js +1 -1
- package/dist/lsp.js.map +1 -1
- package/dist/mcp.js +25 -3
- package/dist/mcp.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/std.js +5 -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/vet.d.ts +2 -0
- package/dist/vet.js +6 -1
- package/dist/vet.js.map +1 -1
- package/dist/view.d.ts +7 -1
- package/dist/view.js +655 -64
- package/dist/view.js.map +1 -1
- package/grammar/aontu.abnf +155 -0
- package/package.json +2 -1
- package/skill/grammar-card.md +5 -2
- package/src/agentsmd.ts +15 -3
- package/src/aontu.ts +7 -1
- package/src/cli.ts +350 -56
- package/src/diff.ts +7 -2
- package/src/format.ts +1146 -0
- package/src/hints.ts +9 -0
- package/src/jsonschema.ts +7 -1
- package/src/lang.ts +69 -5
- package/src/lsp.ts +5 -3
- package/src/mcp.ts +26 -3
- 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/std.ts +5 -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/vet.ts +14 -4
- package/src/view.ts +817 -65
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;
|
|
@@ -46,6 +47,8 @@ const vet_1 = require("./vet");
|
|
|
46
47
|
const reach_1 = require("./reach");
|
|
47
48
|
const view_1 = require("./view");
|
|
48
49
|
const agentsmd_1 = require("./agentsmd");
|
|
50
|
+
const format_1 = require("./format");
|
|
51
|
+
const utility_1 = require("./utility");
|
|
49
52
|
const HELP = `Usage: aontu [options] [file]
|
|
50
53
|
aontu vet [options] <schema> <data> [more-data...]
|
|
51
54
|
aontu subsume [options] <general> <specific>
|
|
@@ -62,6 +65,7 @@ const HELP = `Usage: aontu [options] [file]
|
|
|
62
65
|
aontu why <path> [options] <file>
|
|
63
66
|
aontu set <path>=<value>... --entry <file> --overlay <file>
|
|
64
67
|
aontu agentsmd [--write <AGENTS.md>] <file>
|
|
68
|
+
aontu fmt [-w|-l|--check|-d] <file>...
|
|
65
69
|
|
|
66
70
|
Evaluate an Aontu source file and print the result as JSON.
|
|
67
71
|
With no file on an interactive terminal, start a REPL.
|
|
@@ -84,6 +88,10 @@ Options:
|
|
|
84
88
|
Every verb takes it too, and a bare root means the
|
|
85
89
|
document's own directory
|
|
86
90
|
--include-root <dir> Shorthand for --trust root:<dir>
|
|
91
|
+
--text-ext <e> Read these extensions as text too, comma-separated
|
|
92
|
+
and without dots (md,sql). .txt needs no flag; a
|
|
93
|
+
named format keeps its meaning, and .js stays
|
|
94
|
+
refused. Every verb takes it
|
|
87
95
|
|
|
88
96
|
Mod options:
|
|
89
97
|
--format <f> text (default) or json
|
|
@@ -175,21 +183,22 @@ Why options:
|
|
|
175
183
|
Why exit codes mirror get's: 0 explained, 1 the path names nothing,
|
|
176
184
|
2 usage, 4 the document does not stand up on its own.
|
|
177
185
|
|
|
178
|
-
View kinds: tree, matrix, graph, layer, sets, layers,
|
|
179
|
-
(the poset takes several files). The figure goes to stdout, the loss
|
|
186
|
+
View kinds: doc, lattice, tree, matrix, graph, layer, sets, layers,
|
|
187
|
+
ladder, poset (the poset takes several files). The figure goes to stdout, the loss
|
|
180
188
|
report to stderr. With --views it draws every figure a document
|
|
181
189
|
declares as data, from one evaluation: each declaration names its own
|
|
182
190
|
kind and out file, nothing is written unless every figure rendered,
|
|
183
191
|
and --check gates the committed set.
|
|
184
192
|
|
|
185
193
|
View options:
|
|
186
|
-
--as <profile> text | mermaid | dot | er | svg, per kind:
|
|
187
|
-
matrix, sets and layers draw text
|
|
188
|
-
svg; graph draws mermaid (default),
|
|
189
|
-
layer draws text (default), mermaid or
|
|
190
|
-
and poset draw mermaid (default) or dot
|
|
194
|
+
--as <profile> text | mermaid | dot | er | svg, per kind: doc,
|
|
195
|
+
lattice, tree, matrix, sets and layers draw text
|
|
196
|
+
(default) or svg; graph draws mermaid (default),
|
|
197
|
+
dot or er; layer draws text (default), mermaid or
|
|
198
|
+
svg; ladder and poset draw mermaid (default) or dot
|
|
191
199
|
--at <path> Restrict the figure to nodes under this path; the
|
|
192
|
-
|
|
200
|
+
subtree doc draws; the subtree the lattice counts;
|
|
201
|
+
the path the ladder draws; where the poset compares
|
|
193
202
|
--views <path> Draw every figure the document declares at this
|
|
194
203
|
path, one evaluation, all or nothing; each
|
|
195
204
|
declaration names its own kind and out file
|
|
@@ -198,7 +207,20 @@ View options:
|
|
|
198
207
|
nothing is written
|
|
199
208
|
--strict Exit 1 when the loss report holds anything beyond
|
|
200
209
|
edges_deduped, inverse_suppressed and crossings
|
|
210
|
+
--depth <n> doc: how many levels of key to draw (default 3)
|
|
201
211
|
--max-rows <n> Refuse a figure above this many rows (default 60)
|
|
212
|
+
--style <s> auto (default), none, ansi or css. A figure's
|
|
213
|
+
marks carry their meaning -- a direct cell, a
|
|
214
|
+
closure cell, an upward edge -- and each profile
|
|
215
|
+
has one way to show it: SGR escapes for text, CSS
|
|
216
|
+
classes for svg. auto picks that mechanism where
|
|
217
|
+
the destination can carry it: escapes only on a
|
|
218
|
+
terminal (NO_COLOR is honoured), and an svg keeps
|
|
219
|
+
the stylesheet that makes it standalone. none
|
|
220
|
+
drops both; on svg the classes stay and only the
|
|
221
|
+
stylesheet goes, for a host page that has already
|
|
222
|
+
bound --av-ink and its kin. Escapes are never
|
|
223
|
+
written to a file
|
|
202
224
|
--format <f> text (default) or json, the whole report
|
|
203
225
|
--relation <n> tree, matrix, layer: draw over this relation only;
|
|
204
226
|
graph: keep this predicate (repeatable)
|
|
@@ -255,6 +277,19 @@ Agentsmd options:
|
|
|
255
277
|
Agentsmd exit codes: 0 generated, 2 usage, 4 the document does not
|
|
256
278
|
stand up on its own.
|
|
257
279
|
|
|
280
|
+
Fmt options:
|
|
281
|
+
-w, --write Rewrite each file in place, when its form would change
|
|
282
|
+
-l, --list Print the name of each file whose form would change
|
|
283
|
+
--check Like --list, and exit 1 when any would: the CI gate
|
|
284
|
+
-d, --diff Print a unified diff for each file whose form would
|
|
285
|
+
change
|
|
286
|
+
|
|
287
|
+
The fmt verb prints one document in the agreed form; with no file it
|
|
288
|
+
reads standard input. Several files need one of the options above.
|
|
289
|
+
|
|
290
|
+
Fmt exit codes: 0 formatted or clean, 1 a --check file would change,
|
|
291
|
+
2 usage, 4 a document does not parse.
|
|
292
|
+
|
|
258
293
|
REPL commands:
|
|
259
294
|
:help Show REPL help
|
|
260
295
|
:load <file> Evaluate a document and hold it for the commands below
|
|
@@ -319,15 +354,16 @@ function makeTrustWarn() {
|
|
|
319
354
|
// entryRoot (the entry file's directory, or the working directory for
|
|
320
355
|
// stdin/REPL).
|
|
321
356
|
function trustOpts(trust, entryRoot) {
|
|
357
|
+
const text = 0 === trust.textExt.length ? {} : { textExt: trust.textExt };
|
|
322
358
|
switch (trust.kind) {
|
|
323
359
|
case 'none':
|
|
324
|
-
return { trust: { include: 'none' } };
|
|
360
|
+
return { ...text, trust: { include: 'none' } };
|
|
325
361
|
case 'root':
|
|
326
|
-
return { trust: { include: { root: trust.dir ?? entryRoot } } };
|
|
362
|
+
return { ...text, trust: { include: { root: trust.dir ?? entryRoot } } };
|
|
327
363
|
case 'system':
|
|
328
|
-
return {};
|
|
364
|
+
return { ...text };
|
|
329
365
|
default: // system-warn: today's default plus the warning window
|
|
330
|
-
return { trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
|
|
366
|
+
return { ...text, trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
|
|
331
367
|
}
|
|
332
368
|
}
|
|
333
369
|
// EVERY VERB honours the include capability, not just the bare
|
|
@@ -342,7 +378,8 @@ function trustOpts(trust, entryRoot) {
|
|
|
342
378
|
// already printed: the caller answers the usage class.
|
|
343
379
|
function takeTrust(argv) {
|
|
344
380
|
const rest = [];
|
|
345
|
-
let trust = { kind: 'system-warn' };
|
|
381
|
+
let trust = { kind: 'system-warn', textExt: [] };
|
|
382
|
+
let textExt = [];
|
|
346
383
|
for (let i = 0; i < argv.length; i++) {
|
|
347
384
|
const arg = argv[i];
|
|
348
385
|
if ('--trust' === arg) {
|
|
@@ -359,18 +396,42 @@ function takeTrust(argv) {
|
|
|
359
396
|
process.stderr.write('aontu: --include-root needs a directory\n');
|
|
360
397
|
return undefined;
|
|
361
398
|
}
|
|
362
|
-
trust = { kind: 'root', dir };
|
|
399
|
+
trust = { kind: 'root', dir, textExt };
|
|
400
|
+
}
|
|
401
|
+
else if ('--text-ext' === arg) {
|
|
402
|
+
const list = null == argv[i + 1] ? undefined : parseTextExt(argv[++i]);
|
|
403
|
+
if (null == list) {
|
|
404
|
+
process.stderr.write('aontu: --text-ext needs extensions, without dots' +
|
|
405
|
+
' (--text-ext md,sql)\n');
|
|
406
|
+
return undefined;
|
|
407
|
+
}
|
|
408
|
+
textExt = [...textExt, ...list];
|
|
363
409
|
}
|
|
364
410
|
else {
|
|
365
411
|
rest.push(arg);
|
|
366
412
|
}
|
|
367
413
|
}
|
|
368
|
-
return { argv: rest, trust };
|
|
414
|
+
return { argv: rest, trust: { ...trust, textExt } };
|
|
415
|
+
}
|
|
416
|
+
// `md,sql` or `.md,.sql` -- the dot is accepted and dropped, because a
|
|
417
|
+
// reader who has just written `@"notes.txt"` reaches for one. An empty
|
|
418
|
+
// element, or anything that is not an extension, is a usage error
|
|
419
|
+
// rather than a silently ignored word: a flag that quietly does
|
|
420
|
+
// nothing is how a document ends up refused with no reason visible.
|
|
421
|
+
function parseTextExt(arg) {
|
|
422
|
+
const out = [];
|
|
423
|
+
for (const raw of arg.split(',')) {
|
|
424
|
+
const ext = raw.trim().replace(/^\./, '').toLowerCase();
|
|
425
|
+
if ('' === ext || !/^[a-z0-9]+$/.test(ext)) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
out.push(ext);
|
|
429
|
+
}
|
|
430
|
+
return out;
|
|
369
431
|
}
|
|
370
432
|
// The evaluator options a REPL session's capability means.
|
|
371
433
|
function replTrust(state, entryRoot) {
|
|
372
|
-
|
|
373
|
-
return null == capability ? {} : { trust: capability };
|
|
434
|
+
return verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRoot);
|
|
374
435
|
}
|
|
375
436
|
// The capability a verb's engine runs under. `system` and the staged
|
|
376
437
|
// warning default both mean today's behaviour (no option); the warning
|
|
@@ -386,6 +447,18 @@ function verbTrust(trust, entryRoot) {
|
|
|
386
447
|
return undefined;
|
|
387
448
|
}
|
|
388
449
|
}
|
|
450
|
+
// THE INCLUDE OPTIONS A VERB RUNS UNDER, spread into its engine call:
|
|
451
|
+
// the capability above, and the extensions `--text-ext` widened. Both
|
|
452
|
+
// are absent when unset rather than present-and-undefined, so a verb's
|
|
453
|
+
// options bag is byte-identical to what it was before either flag
|
|
454
|
+
// existed and no engine sees a key it has to ignore.
|
|
455
|
+
function verbOpts(trust, entryRoot) {
|
|
456
|
+
const include = verbTrust(trust, entryRoot);
|
|
457
|
+
return {
|
|
458
|
+
...(undefined === include ? {} : { trust: include }),
|
|
459
|
+
...(0 === trust.textExt.length ? {} : { textExt: trust.textExt }),
|
|
460
|
+
};
|
|
461
|
+
}
|
|
389
462
|
// The directory a bare `--trust root` confines to for a verb: the
|
|
390
463
|
// primary document's own, matching the bare command's entry root.
|
|
391
464
|
function entryRootOf(file) {
|
|
@@ -491,7 +564,7 @@ function replCommand(state, line, read) {
|
|
|
491
564
|
if (':why' === cmd) {
|
|
492
565
|
const report = (0, aontu_1.why)(src, path, {
|
|
493
566
|
path: state.name,
|
|
494
|
-
|
|
567
|
+
...verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRootOf(state.name)),
|
|
495
568
|
});
|
|
496
569
|
return report.ok
|
|
497
570
|
? answer(renderWhyText(report.record))
|
|
@@ -501,7 +574,7 @@ function replCommand(state, line, read) {
|
|
|
501
574
|
? 'keys' : 'canon' === state.mode ? 'canon' : 'json';
|
|
502
575
|
const report = (0, aontu_1.get)(src, path, {
|
|
503
576
|
view, path: state.name,
|
|
504
|
-
|
|
577
|
+
...verbOpts(state.trust ?? { kind: 'system-warn', textExt: [] }, entryRootOf(state.name)),
|
|
505
578
|
});
|
|
506
579
|
return report.ok
|
|
507
580
|
? answer(report.out)
|
|
@@ -732,7 +805,7 @@ function vetOnce(args, trust) {
|
|
|
732
805
|
const findings = [];
|
|
733
806
|
for (const source of sources) {
|
|
734
807
|
const report = (0, aontu_1.vet)(schemaSrc, source.src, {
|
|
735
|
-
|
|
808
|
+
...verbOpts(trust, entryRootOf(args.schema)),
|
|
736
809
|
at: args.at,
|
|
737
810
|
closed: args.closed,
|
|
738
811
|
partial: args.partial,
|
|
@@ -971,7 +1044,7 @@ function runSubsume(argv) {
|
|
|
971
1044
|
return 2;
|
|
972
1045
|
}
|
|
973
1046
|
const report = (0, aontu_1.subsume)(generalSrc, specificSrc, {
|
|
974
|
-
|
|
1047
|
+
...verbOpts(trust, entryRootOf(args.general)),
|
|
975
1048
|
profile: args.profile,
|
|
976
1049
|
at: args.at,
|
|
977
1050
|
generalUrl: args.general,
|
|
@@ -1151,15 +1224,17 @@ function oldVersion(spec, file) {
|
|
|
1151
1224
|
// The document's own compatibility declaration: `$.aontu_policy.compat`,
|
|
1152
1225
|
// a disjunction whose default is the declared mode. Undefined when the
|
|
1153
1226
|
// key is absent or does not spell a mode.
|
|
1154
|
-
function policyCompat(newSrc, path,
|
|
1227
|
+
function policyCompat(newSrc, path, include) {
|
|
1155
1228
|
const aontu = new aontu_1.Aontu();
|
|
1156
1229
|
const ctx = aontu.ctx({ collect: true });
|
|
1157
1230
|
// The declaration is read by EVALUATING the document, so this leg
|
|
1158
|
-
// runs the include resolver too and has to run it under the
|
|
1159
|
-
//
|
|
1160
|
-
// through an unconfined resolver would confine the
|
|
1161
|
-
// not the question (use-cases/REVIEW.md finding G)
|
|
1162
|
-
|
|
1231
|
+
// runs the include resolver too and has to run it under BOTH of the
|
|
1232
|
+
// verb's include options -- a `breaking --trust none` that read its
|
|
1233
|
+
// own mode through an unconfined resolver would confine the
|
|
1234
|
+
// comparison and not the question (use-cases/REVIEW.md finding G),
|
|
1235
|
+
// and one that took the capability alone read no mode at all when
|
|
1236
|
+
// the declaration arrived through a `--text-ext` include.
|
|
1237
|
+
const v = aontu.unify(newSrc, { path, ...(0, utility_1.includeOpts)(include) }, ctx);
|
|
1163
1238
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
1164
1239
|
return undefined;
|
|
1165
1240
|
}
|
|
@@ -1252,7 +1327,7 @@ function runBreaking(argv) {
|
|
|
1252
1327
|
// neither means backward, the index's framing (v1-valid documents
|
|
1253
1328
|
// stay valid).
|
|
1254
1329
|
const mode = args.mode ??
|
|
1255
|
-
policyCompat(newSrc, args.file,
|
|
1330
|
+
policyCompat(newSrc, args.file, verbOpts(trust, entryRootOf(args.file))) ??
|
|
1256
1331
|
'backward';
|
|
1257
1332
|
if ('none' === mode) {
|
|
1258
1333
|
// The document declares no compatibility promise: nothing to check.
|
|
@@ -1295,7 +1370,7 @@ function runBreaking(argv) {
|
|
|
1295
1370
|
const oldPath = old.path;
|
|
1296
1371
|
for (const check of checks) {
|
|
1297
1372
|
const report = (0, aontu_1.subsume)(check.general[0], check.specific[0], {
|
|
1298
|
-
|
|
1373
|
+
...verbOpts(trust, entryRootOf(args.file)),
|
|
1299
1374
|
at: args.at,
|
|
1300
1375
|
generalUrl: check.general[1],
|
|
1301
1376
|
specificUrl: check.specific[1],
|
|
@@ -1425,7 +1500,7 @@ function runTrim(argv) {
|
|
|
1425
1500
|
return 2;
|
|
1426
1501
|
}
|
|
1427
1502
|
const report = (0, aontu_1.trimCheck)(src, {
|
|
1428
|
-
path: files[0],
|
|
1503
|
+
path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
1429
1504
|
});
|
|
1430
1505
|
const text = 'json' === format
|
|
1431
1506
|
? renderTrimJson(report)
|
|
@@ -1476,9 +1551,40 @@ const REACHES_EXIT = {
|
|
|
1476
1551
|
error: 4,
|
|
1477
1552
|
};
|
|
1478
1553
|
const VIEW_HELP = 'aontu view <kind> [options] <file>... (try --help)';
|
|
1479
|
-
const VIEW_KINDS = ['
|
|
1554
|
+
const VIEW_KINDS = ['doc', 'lattice', 'tree', 'matrix', 'graph', 'layer', 'sets', 'layers',
|
|
1555
|
+
'ladder', 'poset'];
|
|
1480
1556
|
const VIEW_PROFILES = ['text', 'mermaid', 'dot', 'er', 'svg'];
|
|
1481
1557
|
const VIEW_EDGES = ['upward', 'all', 'none'];
|
|
1558
|
+
// The styles the CLI accepts (VIEWS.0.md, "7. Styling"). `auto` is
|
|
1559
|
+
// here and NOT in ViewStyle: resolving it means knowing whether stdout
|
|
1560
|
+
// is a terminal, which is the CLI's to know and the library's never --
|
|
1561
|
+
// the same division err.ts already draws for the error frames.
|
|
1562
|
+
const VIEW_STYLES = ['auto', 'none', 'ansi', 'css'];
|
|
1563
|
+
// `--style auto` resolved, which only the CLI can do. The mechanism is
|
|
1564
|
+
// the PROFILE's and the library knows it -- an SVG carries its
|
|
1565
|
+
// stylesheet unless told not to, which is what makes a figure stand
|
|
1566
|
+
// alone. What the library cannot know is whether the DESTINATION is a
|
|
1567
|
+
// terminal, so that is the only thing decided here: escapes on the
|
|
1568
|
+
// text profile when stdout is a terminal and NO_COLOR is unset, the
|
|
1569
|
+
// same two conditions the error frames use. `undefined` leaves the
|
|
1570
|
+
// profile's own default in place.
|
|
1571
|
+
function viewStyleOf(asked, as) {
|
|
1572
|
+
if (undefined !== asked && 'auto' !== asked) {
|
|
1573
|
+
return asked;
|
|
1574
|
+
}
|
|
1575
|
+
// STDOUT'S OWN TERMINAL-NESS, and NO_COLOR read here rather than
|
|
1576
|
+
// through colorActive(). The figure goes to STDOUT and the error
|
|
1577
|
+
// frames go to STDERR, and they are not the same destination: main()
|
|
1578
|
+
// has already called setColor for stderr, so asking colorActive()
|
|
1579
|
+
// would answer the wrong question twice --- no escapes for
|
|
1580
|
+
// `aontu view tree m.aon 2>/dev/null` at a terminal, and escapes
|
|
1581
|
+
// into the pipe for `aontu view tree m.aon | less`. The NO_COLOR
|
|
1582
|
+
// rule is the one no-color.org states and err.ts implements:
|
|
1583
|
+
// set, to anything but empty, means no colour.
|
|
1584
|
+
const no = process.env.NO_COLOR;
|
|
1585
|
+
return 'text' === as && true === process.stdout.isTTY
|
|
1586
|
+
&& (null == no || '' === no) ? 'ansi' : undefined;
|
|
1587
|
+
}
|
|
1482
1588
|
// The figure was drawn (0, `lossy` included: the loss report says
|
|
1483
1589
|
// what it could not draw, and --strict is the gate on that), or the
|
|
1484
1590
|
// document could not be drawn (4). An EMPTY figure is a drawing, not
|
|
@@ -1493,7 +1599,7 @@ const VIEW_EXIT = {
|
|
|
1493
1599
|
const VIEW_USAGE_CODES = [
|
|
1494
1600
|
'view_kind_unknown', 'view_profile_unknown', 'view_rows_exceeded',
|
|
1495
1601
|
'view_at_required', 'view_sets_required', 'view_group_required',
|
|
1496
|
-
'view_document_shape',
|
|
1602
|
+
'view_document_shape', 'view_style_profile', 'view_style_unknown',
|
|
1497
1603
|
];
|
|
1498
1604
|
const MOD_HELP = 'aontu mod tidy|verify|vendor|manifest [dir] (try --help)';
|
|
1499
1605
|
// The module tooling (G6 phase 3, ts/src/mod-tool.ts). All LOCAL:
|
|
@@ -1552,7 +1658,8 @@ function runMod(argv) {
|
|
|
1552
1658
|
const dir = rest[1] ?? '.';
|
|
1553
1659
|
if ('get' === sub || 'publish' === sub) {
|
|
1554
1660
|
process.stderr.write('aontu: mod ' + sub + ' needs a registry client, which this build ' +
|
|
1555
|
-
'does not ship
|
|
1661
|
+
'does not ship; vendor the module by hand and run ' +
|
|
1662
|
+
"'aontu mod tidy'\n");
|
|
1556
1663
|
return 2;
|
|
1557
1664
|
}
|
|
1558
1665
|
if (!MOD_SUBS.includes(sub) || 2 < rest.length) {
|
|
@@ -1718,7 +1825,7 @@ function runRelations(argv) {
|
|
|
1718
1825
|
return 2;
|
|
1719
1826
|
}
|
|
1720
1827
|
const report = (0, aontu_1.relationCheck)(src, {
|
|
1721
|
-
path: files[0],
|
|
1828
|
+
path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
1722
1829
|
});
|
|
1723
1830
|
const text = 'json' === format
|
|
1724
1831
|
? renderRelationsJson(report)
|
|
@@ -1779,7 +1886,7 @@ function runReaches(argv) {
|
|
|
1779
1886
|
}
|
|
1780
1887
|
const report = (0, reach_1.reachCheck)(src, rest[0], rest[1], {
|
|
1781
1888
|
path: rest[2], relation,
|
|
1782
|
-
|
|
1889
|
+
...verbOpts(trust, entryRootOf(rest[2])),
|
|
1783
1890
|
});
|
|
1784
1891
|
const text = 'json' === format
|
|
1785
1892
|
? renderReachesJson(report)
|
|
@@ -1826,6 +1933,9 @@ function runView(argv) {
|
|
|
1826
1933
|
const relations = [];
|
|
1827
1934
|
const roots = [];
|
|
1828
1935
|
const opts = {};
|
|
1936
|
+
// The style ASKED FOR, which may be `auto` -- a word ViewStyle does
|
|
1937
|
+
// not have, because resolving it is the CLI's job.
|
|
1938
|
+
let style = undefined;
|
|
1829
1939
|
// A flag that takes a value, read into `opts` by name.
|
|
1830
1940
|
const valued = {
|
|
1831
1941
|
'--as': 'as', '--at': 'at', '--order': 'order', '--group-by': 'groupBy',
|
|
@@ -1836,6 +1946,7 @@ function runView(argv) {
|
|
|
1836
1946
|
const counted = {
|
|
1837
1947
|
'--max-rows': 'maxRows', '--max-cols': 'maxCols',
|
|
1838
1948
|
'--min-degree': 'minDegree', '--min-size': 'minSize',
|
|
1949
|
+
'--depth': 'depth',
|
|
1839
1950
|
};
|
|
1840
1951
|
for (let i = 0; i < argv.length; i++) {
|
|
1841
1952
|
const arg = argv[i];
|
|
@@ -1874,6 +1985,13 @@ function runView(argv) {
|
|
|
1874
1985
|
return 2;
|
|
1875
1986
|
}
|
|
1876
1987
|
}
|
|
1988
|
+
else if ('--style' === arg) {
|
|
1989
|
+
style = argv[++i];
|
|
1990
|
+
if (null == style || !VIEW_STYLES.includes(style)) {
|
|
1991
|
+
process.stderr.write(`aontu: --style needs one of ${VIEW_STYLES.join(', ')}\n`);
|
|
1992
|
+
return 2;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1877
1995
|
else if ('--check' === arg) {
|
|
1878
1996
|
check = true;
|
|
1879
1997
|
}
|
|
@@ -1915,9 +2033,24 @@ function runView(argv) {
|
|
|
1915
2033
|
rest.push(arg);
|
|
1916
2034
|
}
|
|
1917
2035
|
}
|
|
2036
|
+
// ESCAPES NEVER GO INTO A FILE. A pinned golden holding terminal
|
|
2037
|
+
// control codes is not a golden anybody can read, and a byte
|
|
2038
|
+
// comparison against one would fail on the reader's terminal
|
|
2039
|
+
// settings. `auto` resolves to `none` there on its own; asking for
|
|
2040
|
+
// `ansi` explicitly is a usage error rather than a silent downgrade,
|
|
2041
|
+
// so a script that wanted colour is told where it went.
|
|
2042
|
+
if ('ansi' === style && (undefined !== out || undefined !== opts.views)) {
|
|
2043
|
+
process.stderr.write('aontu: --style ansi writes to a terminal, not to a file\n');
|
|
2044
|
+
return 2;
|
|
2045
|
+
}
|
|
1918
2046
|
// THE VIEW DOCUMENT draws every figure a document declares, so it
|
|
1919
2047
|
// names no kind: the declarations do, one each.
|
|
1920
2048
|
if (undefined !== opts.views) {
|
|
2049
|
+
// A declaration names its own profile, so the style is left to
|
|
2050
|
+
// each figure's own default; `--style none` still reaches every
|
|
2051
|
+
// one of them, which is how a host page that binds the CSS
|
|
2052
|
+
// variables asks for eight figures without eight stylesheets.
|
|
2053
|
+
opts.style = viewStyleOf(style, undefined);
|
|
1921
2054
|
return runViewSet(rest, opts, trust, { format, check, strict, out });
|
|
1922
2055
|
}
|
|
1923
2056
|
if (2 > rest.length) {
|
|
@@ -1976,10 +2109,11 @@ function runView(argv) {
|
|
|
1976
2109
|
}
|
|
1977
2110
|
const report = (0, view_1.view)(srcs[0], {
|
|
1978
2111
|
...opts,
|
|
2112
|
+
style: viewStyleOf(style, opts.as ?? (0, view_1.viewDefaultProfile)(kind)),
|
|
1979
2113
|
kind,
|
|
1980
2114
|
path: files[0],
|
|
1981
2115
|
roots,
|
|
1982
|
-
|
|
2116
|
+
...verbOpts(trust, entryRootOf(files[0])),
|
|
1983
2117
|
docs: files.slice(1).map((path, i) => ({ src: srcs[i + 1], path })),
|
|
1984
2118
|
});
|
|
1985
2119
|
if ('json' === format) {
|
|
@@ -2049,7 +2183,7 @@ function runViewSet(rest, opts, trust, how) {
|
|
|
2049
2183
|
return 2;
|
|
2050
2184
|
}
|
|
2051
2185
|
const report = (0, view_1.viewSet)(src, {
|
|
2052
|
-
...opts, path: file,
|
|
2186
|
+
...opts, path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2053
2187
|
});
|
|
2054
2188
|
if ('json' === how.format) {
|
|
2055
2189
|
process.stdout.write(renderViewSetJson(report) + '\n');
|
|
@@ -2246,7 +2380,7 @@ function runJsonSchema(argv) {
|
|
|
2246
2380
|
return 2;
|
|
2247
2381
|
}
|
|
2248
2382
|
const report = (0, jsonschema_1.jsonSchema)(src, {
|
|
2249
|
-
at, path: files[0],
|
|
2383
|
+
at, path: files[0], ...verbOpts(trust, entryRootOf(files[0])),
|
|
2250
2384
|
});
|
|
2251
2385
|
if ('json' === format) {
|
|
2252
2386
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2329,8 +2463,7 @@ function runHash(argv) {
|
|
|
2329
2463
|
}
|
|
2330
2464
|
// The file's own directory is the include base, as every verb
|
|
2331
2465
|
// resolves a named file (vet's aontuForPath rule).
|
|
2332
|
-
const
|
|
2333
|
-
const aontu = new aontu_1.Aontu(null == capability ? undefined : { trust: capability });
|
|
2466
|
+
const aontu = new aontu_1.Aontu(verbOpts(trust, entryRootOf(files[0])));
|
|
2334
2467
|
const ctx = aontu.ctx({ collect: true });
|
|
2335
2468
|
const v = aontu.unify(src, { path: files[0] }, ctx);
|
|
2336
2469
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
@@ -2434,7 +2567,7 @@ function runGet(argv) {
|
|
|
2434
2567
|
return 2;
|
|
2435
2568
|
}
|
|
2436
2569
|
const report = (0, aontu_1.get)(src, path, {
|
|
2437
|
-
view, depth, path: file,
|
|
2570
|
+
view, depth, path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2438
2571
|
});
|
|
2439
2572
|
if ('json' === format) {
|
|
2440
2573
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2509,7 +2642,7 @@ function runWhy(argv) {
|
|
|
2509
2642
|
return 2;
|
|
2510
2643
|
}
|
|
2511
2644
|
const report = (0, aontu_1.why)(src, path, {
|
|
2512
|
-
path: file,
|
|
2645
|
+
path: file, ...verbOpts(trust, entryRootOf(file)),
|
|
2513
2646
|
});
|
|
2514
2647
|
if ('json' === format) {
|
|
2515
2648
|
process.stdout.write((0, aontu_1.exactJSON)({
|
|
@@ -2630,7 +2763,7 @@ function runSet(argv) {
|
|
|
2630
2763
|
}
|
|
2631
2764
|
}
|
|
2632
2765
|
const report = (0, aontu_1.patch)(entrySrc, overlaySrc, assignments, {
|
|
2633
|
-
|
|
2766
|
+
...verbOpts(trust, entryRootOf(entry)),
|
|
2634
2767
|
entryPath: entry,
|
|
2635
2768
|
overlayPath: overlayFile,
|
|
2636
2769
|
inPlace,
|
|
@@ -2750,7 +2883,7 @@ function runAgentsMd(argv) {
|
|
|
2750
2883
|
}
|
|
2751
2884
|
const report = (0, aontu_1.agentsMd)(src, {
|
|
2752
2885
|
name: files[0], path: files[0],
|
|
2753
|
-
|
|
2886
|
+
...verbOpts(trust, entryRootOf(files[0])),
|
|
2754
2887
|
});
|
|
2755
2888
|
if (!report.ok) {
|
|
2756
2889
|
process.stderr.write(report.findings.map(renderFinding).join('\n') + '\n');
|
|
@@ -2796,6 +2929,116 @@ function runAgentsMd(argv) {
|
|
|
2796
2929
|
// on the parity-probe discipline in AGENTS.md, which derives expected
|
|
2797
2930
|
// spec values by piping BOTH CLIs and comparing. A truncated pipe there
|
|
2798
2931
|
// reads as a port divergence.
|
|
2932
|
+
// ---------------------------------------------------------------------
|
|
2933
|
+
// The source formatter (docs/design/FMT.0.md): one agreed form, in the
|
|
2934
|
+
// tradition of gofmt. The verb prints, lists, checks, diffs or rewrites;
|
|
2935
|
+
// the form itself is the library's (ts/src/format.ts), and the two
|
|
2936
|
+
// ports agree on it row by row in test/spec/fmt.tsv.
|
|
2937
|
+
const FMT_HELP = 'aontu fmt [-w|-l|--check|-d] <file>... (try --help)';
|
|
2938
|
+
function runFmt(argv) {
|
|
2939
|
+
const files = [];
|
|
2940
|
+
const flags = { write: false, list: false, check: false, diff: false };
|
|
2941
|
+
for (const arg of argv) {
|
|
2942
|
+
if ('-h' === arg || '--help' === arg) {
|
|
2943
|
+
process.stdout.write(HELP);
|
|
2944
|
+
return 0;
|
|
2945
|
+
}
|
|
2946
|
+
if ('-w' === arg || '--write' === arg) {
|
|
2947
|
+
flags.write = true;
|
|
2948
|
+
}
|
|
2949
|
+
else if ('-l' === arg || '--list' === arg) {
|
|
2950
|
+
flags.list = true;
|
|
2951
|
+
}
|
|
2952
|
+
else if ('--check' === arg) {
|
|
2953
|
+
flags.check = true;
|
|
2954
|
+
}
|
|
2955
|
+
else if ('-d' === arg || '--diff' === arg) {
|
|
2956
|
+
flags.diff = true;
|
|
2957
|
+
}
|
|
2958
|
+
else if (arg.startsWith('-')) {
|
|
2959
|
+
process.stderr.write(`aontu: unknown fmt option ${arg} (try --help)\n`);
|
|
2960
|
+
return 2;
|
|
2961
|
+
}
|
|
2962
|
+
else {
|
|
2963
|
+
files.push(arg);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
if (0 === files.length) {
|
|
2967
|
+
// Standard input: formatted onto standard output, or listed,
|
|
2968
|
+
// checked and diffed under the name <stdin>. It cannot be written
|
|
2969
|
+
// back.
|
|
2970
|
+
if (flags.write) {
|
|
2971
|
+
process.stderr.write(`aontu: --write needs a file\n${FMT_HELP}\n`);
|
|
2972
|
+
return 2;
|
|
2973
|
+
}
|
|
2974
|
+
return new Promise((resolve) => {
|
|
2975
|
+
let src = '';
|
|
2976
|
+
process.stdin.setEncoding('utf8');
|
|
2977
|
+
process.stdin.on('data', (d) => (src += d));
|
|
2978
|
+
process.stdin.on('end', () => resolve(fmtOne('<stdin>', src, flags)));
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2981
|
+
// Several files onto standard output would be one stream nobody can
|
|
2982
|
+
// split again (the note's X-6): the verb refuses unless an option
|
|
2983
|
+
// says what to do with each.
|
|
2984
|
+
if (1 < files.length && !fmtQuiet(flags)) {
|
|
2985
|
+
process.stderr.write(`aontu: fmt prints one file; with ${files.length}, say --write, ` +
|
|
2986
|
+
`--list, --check or --diff\n${FMT_HELP}\n`);
|
|
2987
|
+
return 2;
|
|
2988
|
+
}
|
|
2989
|
+
let worst = 0;
|
|
2990
|
+
for (const file of files) {
|
|
2991
|
+
let src;
|
|
2992
|
+
try {
|
|
2993
|
+
src = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
2994
|
+
}
|
|
2995
|
+
catch (err) {
|
|
2996
|
+
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
2997
|
+
return 2;
|
|
2998
|
+
}
|
|
2999
|
+
worst = Math.max(worst, fmtOne(file, src, flags));
|
|
3000
|
+
}
|
|
3001
|
+
return worst;
|
|
3002
|
+
}
|
|
3003
|
+
// An option that says what to do with a file that would change, in
|
|
3004
|
+
// place of printing it.
|
|
3005
|
+
function fmtQuiet(flags) {
|
|
3006
|
+
return flags.write || flags.list || flags.check || flags.diff;
|
|
3007
|
+
}
|
|
3008
|
+
// One document: 0 printed, clean or done; 1 a --check that would
|
|
3009
|
+
// change; 2 a file that cannot be written; 4 a document that does not
|
|
3010
|
+
// format, with the finding that says why.
|
|
3011
|
+
function fmtOne(name, src, flags) {
|
|
3012
|
+
const report = (0, format_1.format)(src, { path: name });
|
|
3013
|
+
if ('error' === report.verdict) {
|
|
3014
|
+
process.stderr.write(`aontu: ${name} was not formatted\n` +
|
|
3015
|
+
report.errors.map(renderFinding).join('\n') + '\n');
|
|
3016
|
+
return 4;
|
|
3017
|
+
}
|
|
3018
|
+
if (!fmtQuiet(flags)) {
|
|
3019
|
+
process.stdout.write(report.text);
|
|
3020
|
+
return 0;
|
|
3021
|
+
}
|
|
3022
|
+
if (!report.changed) {
|
|
3023
|
+
return 0;
|
|
3024
|
+
}
|
|
3025
|
+
if (flags.list || flags.check) {
|
|
3026
|
+
process.stdout.write(name + '\n');
|
|
3027
|
+
}
|
|
3028
|
+
if (flags.diff) {
|
|
3029
|
+
process.stdout.write((0, format_1.unifiedDiff)(name, src, report.text));
|
|
3030
|
+
}
|
|
3031
|
+
if (flags.write) {
|
|
3032
|
+
try {
|
|
3033
|
+
(0, node_fs_1.writeFileSync)(name, report.text);
|
|
3034
|
+
}
|
|
3035
|
+
catch (err) {
|
|
3036
|
+
process.stderr.write(`aontu: cannot write ${name}: ${err.message}\n`);
|
|
3037
|
+
return 2;
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
3040
|
+
return flags.check ? 1 : 0;
|
|
3041
|
+
}
|
|
2799
3042
|
function finish(code) {
|
|
2800
3043
|
process.exitCode = code;
|
|
2801
3044
|
}
|
|
@@ -2803,16 +3046,16 @@ function finish(code) {
|
|
|
2803
3046
|
// spelling, so the caller owns the usage error.
|
|
2804
3047
|
function parseTrustArg(value) {
|
|
2805
3048
|
if ('system' === value) {
|
|
2806
|
-
return { kind: 'system' };
|
|
3049
|
+
return { kind: 'system', textExt: [] };
|
|
2807
3050
|
}
|
|
2808
3051
|
if ('none' === value) {
|
|
2809
|
-
return { kind: 'none' };
|
|
3052
|
+
return { kind: 'none', textExt: [] };
|
|
2810
3053
|
}
|
|
2811
3054
|
if ('root' === value) {
|
|
2812
|
-
return { kind: 'root' };
|
|
3055
|
+
return { kind: 'root', textExt: [] };
|
|
2813
3056
|
}
|
|
2814
3057
|
if (value.startsWith('root:') && 'root:'.length < value.length) {
|
|
2815
|
-
return { kind: 'root', dir: value.slice('root:'.length) };
|
|
3058
|
+
return { kind: 'root', dir: value.slice('root:'.length), textExt: [] };
|
|
2816
3059
|
}
|
|
2817
3060
|
return undefined;
|
|
2818
3061
|
}
|
|
@@ -2833,7 +3076,8 @@ function main(argv) {
|
|
|
2833
3076
|
// overwritten twice. In a tool loop that reads as a passing
|
|
2834
3077
|
// validation. Counting them is what lets the refusal below happen.
|
|
2835
3078
|
const files = [];
|
|
2836
|
-
let trust = { kind: 'system-warn' };
|
|
3079
|
+
let trust = { kind: 'system-warn', textExt: [] };
|
|
3080
|
+
let textExt = [];
|
|
2837
3081
|
// The REPL's SESSION protocol (G7 phase 7): one JSON line per
|
|
2838
3082
|
// answer, so a harness can drive the session. Named --jsonl rather
|
|
2839
3083
|
// than the design's --json, which would read as the `:json` output
|
|
@@ -2860,6 +3104,9 @@ function main(argv) {
|
|
|
2860
3104
|
if ('agentsmd' === argv[2]) {
|
|
2861
3105
|
return finish(runAgentsMd(argv.slice(3)));
|
|
2862
3106
|
}
|
|
3107
|
+
if ('fmt' === argv[2]) {
|
|
3108
|
+
return void Promise.resolve(runFmt(argv.slice(3))).then(finish);
|
|
3109
|
+
}
|
|
2863
3110
|
if ('set' === argv[2]) {
|
|
2864
3111
|
return finish(runSet(argv.slice(3)));
|
|
2865
3112
|
}
|
|
@@ -2927,7 +3174,16 @@ function main(argv) {
|
|
|
2927
3174
|
process.stderr.write('aontu: --include-root needs a directory\n');
|
|
2928
3175
|
return finish(2);
|
|
2929
3176
|
}
|
|
2930
|
-
trust = { kind: 'root', dir };
|
|
3177
|
+
trust = { kind: 'root', dir, textExt };
|
|
3178
|
+
}
|
|
3179
|
+
else if ('--text-ext' === arg) {
|
|
3180
|
+
const list = null == args[i + 1] ? undefined : parseTextExt(args[++i]);
|
|
3181
|
+
if (null == list) {
|
|
3182
|
+
process.stderr.write('aontu: --text-ext needs extensions, without dots' +
|
|
3183
|
+
' (--text-ext md,sql)\n');
|
|
3184
|
+
return finish(2);
|
|
3185
|
+
}
|
|
3186
|
+
textExt = [...textExt, ...list];
|
|
2931
3187
|
}
|
|
2932
3188
|
else if (arg.startsWith('-')) {
|
|
2933
3189
|
process.stderr.write(`aontu: unknown option ${arg} (try --help)\n`);
|
|
@@ -2951,6 +3207,10 @@ function main(argv) {
|
|
|
2951
3207
|
' (try --help)\n');
|
|
2952
3208
|
return finish(2);
|
|
2953
3209
|
}
|
|
3210
|
+
// The extensions ride with the capability from here on, so the three
|
|
3211
|
+
// entry shapes below (file, REPL, stdin) each get them by threading
|
|
3212
|
+
// the one value they already thread.
|
|
3213
|
+
trust = { ...trust, textExt };
|
|
2954
3214
|
const file = files[0];
|
|
2955
3215
|
if (null != file) {
|
|
2956
3216
|
finish(runFile(file, mode, trust));
|