aontu 0.64.0 → 0.65.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.
Files changed (61) hide show
  1. package/README.md +2 -2
  2. package/dist/agentsmd.js +3 -3
  3. package/dist/agentsmd.js.map +1 -1
  4. package/dist/aontu.d.ts +1 -1
  5. package/dist/aontu.js +1 -1
  6. package/dist/cli.d.ts +15 -2
  7. package/dist/cli.js +523 -137
  8. package/dist/cli.js.map +1 -1
  9. package/dist/compat.d.ts +7 -0
  10. package/dist/compat.js +113 -0
  11. package/dist/compat.js.map +1 -0
  12. package/dist/helpdoc.js +5 -5
  13. package/dist/helpdoc.js.map +1 -1
  14. package/dist/hints.js +11 -5
  15. package/dist/hints.js.map +1 -1
  16. package/dist/lang.d.ts +1 -0
  17. package/dist/lang.js +8 -0
  18. package/dist/lang.js.map +1 -1
  19. package/dist/lsp.d.ts +1 -1
  20. package/dist/mod.d.ts +18 -3
  21. package/dist/mod.js +117 -46
  22. package/dist/mod.js.map +1 -1
  23. package/dist/pkg-net.d.ts +227 -0
  24. package/dist/pkg-net.js +1598 -0
  25. package/dist/pkg-net.js.map +1 -0
  26. package/dist/pkg-zip.d.ts +8 -0
  27. package/dist/pkg-zip.js +196 -0
  28. package/dist/pkg-zip.js.map +1 -0
  29. package/dist/pkg.d.ts +159 -0
  30. package/dist/pkg.js +767 -0
  31. package/dist/pkg.js.map +1 -0
  32. package/dist/report-sarif.js +1 -1
  33. package/dist/report-sarif.js.map +1 -1
  34. package/dist/subsume.d.ts +3 -1
  35. package/dist/subsume.js +2 -0
  36. package/dist/subsume.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/package.json +1 -1
  39. package/skill/SKILL.md +3 -3
  40. package/skill/error-codes.md +4 -4
  41. package/skill/examples.md +4 -4
  42. package/skill/grammar-card.md +1 -1
  43. package/skill/init/check.sh +2 -2
  44. package/skill/tasks.md +6 -6
  45. package/src/agentsmd.ts +3 -3
  46. package/src/aontu.ts +1 -1
  47. package/src/cli.ts +610 -150
  48. package/src/compat.ts +148 -0
  49. package/src/helpdoc.ts +5 -5
  50. package/src/hints.ts +11 -7
  51. package/src/lang.ts +9 -1
  52. package/src/mod.ts +142 -51
  53. package/src/pkg-net.ts +1945 -0
  54. package/src/pkg-zip.ts +228 -0
  55. package/src/pkg.ts +1018 -0
  56. package/src/report-sarif.ts +1 -1
  57. package/src/subsume.ts +2 -2
  58. package/dist/mod-tool.d.ts +0 -58
  59. package/dist/mod-tool.js +0 -418
  60. package/dist/mod-tool.js.map +0 -1
  61. package/src/mod-tool.ts +0 -578
package/dist/cli.js CHANGED
@@ -15,7 +15,11 @@ exports.runView = runView;
15
15
  exports.runJsonSchema = runJsonSchema;
16
16
  exports.runTemplate = runTemplate;
17
17
  exports.runTrace = runTrace;
18
- exports.runMod = runMod;
18
+ exports.runPkg = runPkg;
19
+ exports.runModel = runModel;
20
+ exports.runPackageVerb = runPackageVerb;
21
+ exports.pkgToolOptions = pkgToolOptions;
22
+ exports.serveUntilInterrupted = serveUntilInterrupted;
19
23
  exports.runHash = runHash;
20
24
  exports.runGet = runGet;
21
25
  exports.runHelp = runHelp;
@@ -46,7 +50,8 @@ const report_sarif_1 = require("./report-sarif");
46
50
  const lsp_server_1 = require("./lsp-server");
47
51
  const mcp_server_1 = require("./mcp-server");
48
52
  const jsonschema_1 = require("./jsonschema");
49
- const mod_tool_1 = require("./mod-tool");
53
+ const pkg_1 = require("./pkg");
54
+ const pkg_net_1 = require("./pkg-net");
50
55
  const mod_1 = require("./mod");
51
56
  const vet_1 = require("./vet");
52
57
  const reach_1 = require("./reach");
@@ -72,10 +77,18 @@ const HELP = `Usage: aontu [options] [file]
72
77
  aontu trace [--at <path>] [--format json] [--marker <token>]
73
78
  [--profile <file>] <file>
74
79
  aontu hash [options] <file>
75
- aontu mod tidy|verify|vendor|manifest [options] [dir]
76
- aontu get <path> [options] <file>
77
- aontu why <path> [options] <file>
78
- aontu set <path>=<value>... --entry <file> --overlay <file>
80
+ aontu sync [--frozen] [options] [dir]
81
+ aontu add <pkg>[@<version>] [options] [dir]
82
+ aontu get <pkg>[@<version>] [options] [dir]
83
+ aontu remove <pkg> [options] [dir]
84
+ aontu why <pkg> [options] [dir]
85
+ aontu publish [--yes] [--to <dir>] [options] [dir]
86
+ aontu pkg tidy|verify|vendor|manifest|refreeze|tree|outdated|serve
87
+ [options] [dir]
88
+ aontu pkg keygen <file>
89
+ aontu model get <path> [options] <file>
90
+ aontu model why <path> [options] <file>
91
+ aontu model set <path>=<value>... --entry <file> --overlay <file>
79
92
  aontu allow --role <role> [--at <path>] <roles-file> <path>...
80
93
  aontu agentsmd [--write <AGENTS.md>] [--depth <n>] <file>
81
94
  aontu fmt [-w|-l|--check|-d|--lint] [--marker <token>]
@@ -144,18 +157,57 @@ Options:
144
157
  named format keeps its meaning, and .js stays
145
158
  refused. Every verb takes it
146
159
 
147
- Mod options:
160
+ Package verbs (a module is imported; a package is published):
161
+ sync Make the project correct: resolve by minimum version
162
+ selection, fetch what is missing, write aontu_meta/pkg-lock.aon,
163
+ vendor, verify. --frozen refuses to change the lockfile
164
+ add Take on a dependency the project does not have, then sync;
165
+ refuses one it has and names get
166
+ get Add a dependency or raise its minimum, then sync. Without a
167
+ version, the newest version outside the cooldown
168
+ remove Drop a dependency, then sync
169
+ why Why is this package in the closure: every path of
170
+ requirements that reaches it
171
+ publish Publish this package. A dry run without --yes; --to <dir>
172
+ writes the repository layout into a directory instead
173
+
174
+ Package options:
148
175
  --format <f> text (default) or json
149
- --against <dir> manifest: a prior version's module tree, to gate on
176
+ --frozen sync: fail if the lockfile would change (the CI mode)
177
+ --yes publish: send it (the default is a dry run)
178
+ --to <dir> publish: write the read-path layout into a directory
179
+ --key <file> publish: the Ed25519 private key (PKCS#8 PEM) that
180
+ signs the manifest, for the key provider
181
+ --token <file> publish: the forge's OIDC token, read from a file
182
+ --base <url> the repository to read from (repeatable; overrides
183
+ pkg.aon repo.base)
184
+ --write <url> publish: the write path (overrides pkg.aon repo.write)
185
+ --against <dir> manifest: a prior version's tree, to gate on
186
+ --upstream <u> serve: fetch on miss from this repository (repeatable)
187
+ --listen <a> serve: the address to listen on (default 127.0.0.1:8017)
150
188
 
151
- Mod subcommands:
152
- tidy Resolve the module closure by minimum version selection and
153
- rewrite aontu_meta/mod-lock.aon in canonical form
154
- verify Check every locked module still means what the lockfile
155
- pins, and change nothing (the CI gate; tidy rewrites)
189
+ pkg subcommands (the rest of the package operations):
190
+ tidy Resolve the closure by minimum version selection and
191
+ rewrite aontu_meta/pkg-lock.aon in canonical form
192
+ verify Check every locked package still is and still means what
193
+ the lockfile pins, bytes before meaning, and change nothing
194
+ (the CI gate; tidy rewrites)
156
195
  vendor Materialise the locked closure into aontu_meta/vendor/
157
- manifest Print the OCI artifact a publish would push, gated on the
158
- breaking check against --against
196
+ manifest Print the manifest a publish would send, gated on the
197
+ compatibility check against --against
198
+ refreeze Recompute every canon pin and nothing else, after a
199
+ canonical-form change in the engine
200
+ tree The locked closure as a graph
201
+ outdated What could move, and what would move with it
202
+ serve Serve a repository directory; with --upstream, a caching
203
+ proxy in front of another repository
204
+ keygen Write a new Ed25519 signing key (PKCS#8 PEM) to a file,
205
+ once, and print the signer id a consumer names
206
+
207
+ model subcommands (one document, interrogated or edited):
208
+ get What the document says at a path
209
+ why Every contribution to the value at a path
210
+ set Append a path-flattened conjunct to an overlay
159
211
 
160
212
  Vet options:
161
213
  --at <path> Validate against this path of the schema ($.a.b)
@@ -234,21 +286,21 @@ Hash options:
234
286
  Hash exit codes: 0 hashed, 2 usage, 4 the document does not stand up
235
287
  on its own.
236
288
 
237
- Get options:
289
+ Model get options:
238
290
  -c, --canon Canonical-form fragment (default: generated JSON)
239
291
  --keys Keys at the node, one per line
240
292
  --types Shape view: concrete leaves lifted to their kinds
241
293
  --depth <n> Structure to depth n; deeper nodes render as top
242
294
  --format <f> text (default) or json
243
295
 
244
- Get exit codes: 0 rendered, 1 the path names nothing, 2 usage, 4 the
245
- document does not stand up on its own.
296
+ Model get exit codes: 0 rendered, 1 the path names nothing, 2 usage, 4
297
+ the document does not stand up on its own.
246
298
 
247
- Why options:
299
+ Model why options:
248
300
  --format <f> text (default) or json
249
301
 
250
- Why exit codes mirror get's: 0 explained, 1 the path names nothing,
251
- 2 usage, 4 the document does not stand up on its own.
302
+ Model why exit codes mirror get's: 0 explained, 1 the path names
303
+ nothing, 2 usage, 4 the document does not stand up on its own.
252
304
 
253
305
  View kinds: doc, lattice, tree, matrix, graph, layer, sets, layers,
254
306
  ladder, poset (the poset takes several files). The figure goes to stdout, the loss
@@ -338,7 +390,7 @@ every other line is a line of output.
338
390
 
339
391
  Template exit codes: 0 written, 1 --check drift, 2 usage or I/O.
340
392
 
341
- Set options:
393
+ Model set options:
342
394
  --entry <file> The document the change is checked against
343
395
  --overlay <file> The file the change is appended to (created if
344
396
  absent; not written when the change does not hold)
@@ -354,7 +406,7 @@ Set options:
354
406
  --format <f> text (default) or json
355
407
 
356
408
  Set exit codes are vet's verdict classes: 0 valid, 1 invalid (the
357
- change contradicts a pinned value -- aontu why locates it, and
409
+ change contradicts a pinned value -- aontu model why locates it, and
358
410
  --in-place rewrites it), 2 usage, 3 incomplete, 4 the entry does not
359
411
  stand up on its own.
360
412
 
@@ -556,7 +608,7 @@ function trustOpts(trust, entryRoot) {
556
608
  return { ...text, trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
557
609
  }
558
610
  }
559
- function takeTrust(argv) {
611
+ function takeTrust(argv, io = PROCESS_IO) {
560
612
  const rest = [];
561
613
  let trust = { kind: 'system-warn', textExt: [] };
562
614
  let textExt = [];
@@ -565,7 +617,7 @@ function takeTrust(argv) {
565
617
  if ('--trust' === arg) {
566
618
  const parsed = null == argv[i + 1] ? undefined : parseTrustArg(argv[++i]);
567
619
  if (null == parsed) {
568
- process.stderr.write('aontu: --trust needs system, none, or root[:dir]\n');
620
+ io.err('aontu: --trust needs system, none, or root[:dir]\n');
569
621
  return undefined;
570
622
  }
571
623
  trust = parsed;
@@ -573,7 +625,7 @@ function takeTrust(argv) {
573
625
  else if ('--include-root' === arg) {
574
626
  const dir = argv[++i];
575
627
  if (null == dir) {
576
- process.stderr.write('aontu: --include-root needs a directory\n');
628
+ io.err('aontu: --include-root needs a directory\n');
577
629
  return undefined;
578
630
  }
579
631
  trust = { kind: 'root', dir, textExt };
@@ -581,7 +633,7 @@ function takeTrust(argv) {
581
633
  else if ('--text-ext' === arg) {
582
634
  const list = null == argv[i + 1] ? undefined : parseTextExt(argv[++i]);
583
635
  if (null == list) {
584
- process.stderr.write('aontu: --text-ext needs extensions, without dots' +
636
+ io.err('aontu: --text-ext needs extensions, without dots' +
585
637
  ' (--text-ext md,sql)\n');
586
638
  return undefined;
587
639
  }
@@ -594,7 +646,7 @@ function takeTrust(argv) {
594
646
  return { argv: rest, trust: { ...trust, textExt } };
595
647
  }
596
648
  // `md,sql` or `.md,.sql` -- the dot is accepted and dropped, because a
597
- // reader who has just written `@"notes.txt"` reaches for one. An empty
649
+ // reader who has just written `@"./notes.txt"` reaches for one. An empty
598
650
  // element, or anything that is not an extension, is a usage error
599
651
  // rather than a silently ignored word: a flag that quietly does
600
652
  // nothing is how a document ends up refused with no reason visible.
@@ -1735,81 +1787,134 @@ const VIEW_USAGE_CODES = [
1735
1787
  'view_at_required', 'view_sets_required', 'view_group_required',
1736
1788
  'view_document_shape', 'view_style_profile', 'view_style_unknown',
1737
1789
  ];
1738
- const MOD_HELP = 'aontu mod tidy|verify|vendor|manifest [dir] (try --help)';
1739
- function runMod(argv) {
1740
- const trusted = takeTrust(argv);
1741
- if (null == trusted) {
1742
- return 2;
1743
- }
1744
- argv = trusted.argv;
1745
- const trust = trusted.trust;
1746
- const rest = [];
1747
- let format = 'text';
1748
- let against;
1790
+ const PKG_HELP = 'aontu pkg tidy|verify|vendor|manifest|refreeze|tree|outdated|serve [dir] | keygen <file> (try --help)';
1791
+ const PKG_SUBS = [
1792
+ 'tidy', 'verify', 'vendor', 'manifest', 'refreeze', 'tree', 'outdated',
1793
+ 'serve', 'keygen',
1794
+ ];
1795
+ function parsePkgArgs(argv, verb, io) {
1796
+ const out = {
1797
+ rest: [], format: 'text', frozen: false, yes: false, base: [], upstream: [],
1798
+ };
1799
+ const value = (name, i) => {
1800
+ const v = argv[i];
1801
+ if (null == v) {
1802
+ io.err(`aontu: ${name} needs a value\n`);
1803
+ }
1804
+ return v;
1805
+ };
1749
1806
  for (let i = 0; i < argv.length; i++) {
1750
1807
  const arg = argv[i];
1751
1808
  if ('-h' === arg || '--help' === arg) {
1752
- process.stdout.write(HELP);
1753
- return 0;
1809
+ io.out(HELP);
1810
+ return undefined;
1754
1811
  }
1755
1812
  if ('--format' === arg) {
1756
1813
  const f = argv[++i];
1757
1814
  if ('text' !== f && 'json' !== f) {
1758
- process.stderr.write('aontu: --format needs text or json\n');
1759
- return 2;
1815
+ io.err('aontu: --format needs text or json\n');
1816
+ return undefined;
1760
1817
  }
1761
- format = f;
1818
+ out.format = f;
1762
1819
  }
1763
- else if ('--against' === arg) {
1764
- const a = argv[++i];
1765
- if (null == a) {
1766
- process.stderr.write('aontu: --against needs a module directory\n');
1767
- return 2;
1820
+ else if ('--frozen' === arg) {
1821
+ out.frozen = true;
1822
+ }
1823
+ else if ('--yes' === arg) {
1824
+ out.yes = true;
1825
+ }
1826
+ else if ('--against' === arg || '--to' === arg || '--key' === arg ||
1827
+ '--token' === arg || '--write' === arg || '--listen' === arg) {
1828
+ const v = value(arg, ++i);
1829
+ if (null == v) {
1830
+ return undefined;
1768
1831
  }
1769
- against = a;
1832
+ out['--against' === arg ? 'against' : '--to' === arg ? 'to' :
1833
+ '--key' === arg ? 'key' : '--token' === arg ? 'token' :
1834
+ '--write' === arg ? 'write' : 'listen'] = v;
1835
+ }
1836
+ else if ('--base' === arg || '--upstream' === arg) {
1837
+ const v = value(arg, ++i);
1838
+ if (null == v) {
1839
+ return undefined;
1840
+ }
1841
+ out['--base' === arg ? 'base' : 'upstream'].push(v);
1770
1842
  }
1771
1843
  else if (arg.startsWith('-')) {
1772
- process.stderr.write(`aontu: unknown mod option ${arg} (try --help)\n`);
1773
- return 2;
1844
+ io.err(`aontu: unknown ${verb} option ${arg} (try --help)\n`);
1845
+ return undefined;
1774
1846
  }
1775
1847
  else {
1776
- rest.push(arg);
1848
+ out.rest.push(arg);
1777
1849
  }
1778
1850
  }
1779
- const sub = rest[0];
1780
- const dir = rest[1] ?? '.';
1781
- if ('get' === sub || 'publish' === sub) {
1782
- process.stderr.write('aontu: mod ' + sub + ' needs a registry client, which this build ' +
1783
- 'does not ship; vendor the module by hand and run ' +
1784
- "'aontu mod tidy'\n");
1851
+ return out;
1852
+ }
1853
+ // A verb that finds the older layout names the current one, once, and
1854
+ // reads nothing from it.
1855
+ function nameOldLayout(dir, io) {
1856
+ const old = ['aon_vendor', 'mod-lock.aon', 'mod.aon',
1857
+ (0, node_path_1.join)(mod_1.META_DIR, 'mod-lock.aon')].filter((f) => (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, f)));
1858
+ if (0 < old.length) {
1859
+ io.err('aontu: ' + old.join(', ') + ' belong to an older layout: the package ' +
1860
+ 'file is ' + mod_1.PKG_FILE + ', the lockfile ' + (0, node_path_1.join)(mod_1.META_DIR, mod_1.LOCK_FILE) +
1861
+ ' and the vendor tree ' + (0, node_path_1.join)(mod_1.META_DIR, 'vendor') + '; rename ' +
1862
+ mod_1.PKG_FILE + '\'s `mod` block to `pkg`, then run aontu sync\n');
1863
+ }
1864
+ }
1865
+ function runPkg(argv, servers) {
1866
+ const io = servers.io ?? PROCESS_IO;
1867
+ const trusted = takeTrust(argv, io);
1868
+ if (null == trusted) {
1785
1869
  return 2;
1786
1870
  }
1787
- if (!MOD_SUBS.includes(sub) || 2 < rest.length) {
1788
- process.stderr.write(`aontu: mod needs tidy, verify, vendor or manifest\n${MOD_HELP}\n`);
1871
+ const args = parsePkgArgs(trusted.argv, 'pkg', io);
1872
+ if (null == args) {
1873
+ return '-h' === trusted.argv[0] || trusted.argv.includes('--help') ? 0 : 2;
1874
+ }
1875
+ const trust = trusted.trust;
1876
+ const sub = args.rest[0];
1877
+ const dir = args.rest[1] ?? '.';
1878
+ if (!PKG_SUBS.includes(sub) || 2 < args.rest.length) {
1879
+ io.err(`aontu: pkg needs one of ${PKG_SUBS.join(', ')}\n${PKG_HELP}\n`);
1789
1880
  return 2;
1790
1881
  }
1791
- 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'))) {
1792
- process.stderr.write('aontu: aon_vendor/ and mod-lock.aon now live under aontu_meta/: ' +
1793
- 'move them, or run aontu mod tidy and aontu mod vendor\n');
1882
+ if ('keygen' === sub) {
1883
+ if (2 !== args.rest.length) {
1884
+ io.err('aontu: pkg keygen needs the file to write\naontu pkg keygen <file>\n');
1885
+ return 2;
1886
+ }
1887
+ const made = (0, pkg_net_1.keygen)(args.rest[1]);
1888
+ if (null != made.refused) {
1889
+ io.err('aontu: ' + made.refused + '\n');
1890
+ return 2;
1891
+ }
1892
+ io.out('signer: ' + made.signer + '\n');
1893
+ return 0;
1794
1894
  }
1795
- // `--against` gates a manifest and means nothing to the other two;
1895
+ nameOldLayout(dir, io);
1896
+ // `--against` gates a manifest and means nothing to the others;
1796
1897
  // accepting it there would say it had been honoured.
1797
- if (null != against && 'manifest' !== sub) {
1798
- process.stderr.write('aontu: --against is a manifest option\n');
1799
- return 2;
1800
- }
1801
- const modopts = modToolOptions(trust, (0, node_path_1.resolve)(dir));
1802
- const report = 'tidy' === sub ? (0, mod_tool_1.modTidy)(dir, modopts) :
1803
- 'verify' === sub ? (0, mod_tool_1.modVerify)(dir, modopts) :
1804
- 'vendor' === sub ? (0, mod_tool_1.modVendor)(dir, modopts) :
1805
- (0, mod_tool_1.modManifest)(dir, modopts, against);
1806
- process.stdout.write(('json' === format ?
1807
- (0, aontu_1.exactJSON)({ aontu: { version: version(), verb: 'mod ' + sub }, ...report }, 2) :
1808
- modText(sub, report)) + '\n');
1809
- return MOD_EXIT[report.verdict];
1810
- }
1811
- const MOD_SUBS = ['tidy', 'verify', 'vendor', 'manifest'];
1812
- const MOD_EXIT = {
1898
+ if (null != args.against && 'manifest' !== sub) {
1899
+ io.err('aontu: --against is a manifest option\n');
1900
+ return 2;
1901
+ }
1902
+ const opts = pkgToolOptions(trust, (0, node_path_1.resolve)(dir));
1903
+ if ('outdated' === sub || 'serve' === sub) {
1904
+ return runPkgNet(sub, dir, args, opts, servers, io);
1905
+ }
1906
+ const report = 'tidy' === sub ? (0, pkg_1.pkgTidy)(dir, opts) :
1907
+ 'verify' === sub ? (0, pkg_1.pkgVerify)(dir, opts) :
1908
+ 'vendor' === sub ? (0, pkg_1.pkgVendor)(dir, opts) :
1909
+ 'refreeze' === sub ? (0, pkg_1.pkgRefreeze)(dir, opts) :
1910
+ 'tree' === sub ? (0, pkg_1.pkgTree)(dir, opts) :
1911
+ (0, pkg_1.pkgManifest)(dir, opts, args.against);
1912
+ io.out(('json' === args.format ?
1913
+ (0, aontu_1.exactJSON)({ aontu: { version: version(), verb: 'pkg ' + sub }, ...report }, 2) :
1914
+ pkgText(sub, report)) + '\n');
1915
+ return PKG_EXIT[report.verdict];
1916
+ }
1917
+ const PKG_EXIT = {
1813
1918
  ok: 0,
1814
1919
  missing: 1,
1815
1920
  mismatch: 1,
@@ -1817,13 +1922,19 @@ const MOD_EXIT = {
1817
1922
  // nothing to check, which is a refusal and not a pass.
1818
1923
  unlocked: 1,
1819
1924
  breaking: 1,
1925
+ frozen: 1,
1926
+ refused: 1,
1927
+ outdated: 1,
1928
+ sent: 0,
1929
+ 'dry-run': 0,
1930
+ current: 0,
1820
1931
  undecided: 3,
1821
1932
  error: 4,
1822
1933
  };
1823
1934
  // The tooling's evaluator: the same standalone evaluation the module
1824
1935
  // resolver verifies with (ts/src/mod.ts), and for the same reason —
1825
1936
  // only the engine can say what a module MEANS.
1826
- function modToolOptions(trust, entryRoot) {
1937
+ function pkgToolOptions(trust, entryRoot) {
1827
1938
  const opts = verbOpts(trust, entryRoot);
1828
1939
  // The user cache lives outside any confinement root, so a confined
1829
1940
  // run reads the vendor tree only -- as the evaluator's own module
@@ -1840,24 +1951,54 @@ function modToolOptions(trust, entryRoot) {
1840
1951
  hash: (0, aontu_1.canonHash)(val),
1841
1952
  canon: val.canon,
1842
1953
  // The same question `aontu hash` asks before it will answer:
1843
- // did this document stand up ON ITS OWN? See ModToolEval.
1954
+ // did this document stand up ON ITS OWN? See PkgToolEval.
1844
1955
  ok: 0 === ctx.err.length && true !== val.isNil,
1845
1956
  };
1846
1957
  },
1847
1958
  };
1848
1959
  }
1849
- function modText(sub, report) {
1960
+ function pkgLockLines(entries) {
1961
+ return entries.map((e) => e.key + ' ' + e.v + ' ' + e.canon);
1962
+ }
1963
+ // The renderers verify, tidy and sync share, as the Go port's do.
1964
+ function pkgMismatchLines(mismatched) {
1965
+ return mismatched.map((m) => 'canon' === m.pin ?
1966
+ m.key + ': pinned ' + m.want + ' but the store means ' +
1967
+ ('' === m.got ? 'nothing (it does not evaluate)' : m.got) :
1968
+ m.key + ': pinned ' + m.pin + ' ' + m.want + ' but the store holds ' + m.got);
1969
+ }
1970
+ // NOT a fetch: the package may well be sitting in the store. What is
1971
+ // absent is the PIN, and only a sync writes one.
1972
+ function pkgUnlockedLines(unlocked) {
1973
+ return unlocked.map((key) => key + ': not in the lockfile (run: aontu sync)');
1974
+ }
1975
+ function pkgForbiddenLines(forbidden) {
1976
+ return forbidden.map((f) => f + ': not admitted in a package');
1977
+ }
1978
+ function pkgText(sub, report) {
1850
1979
  const lines = ['verdict: ' + report.verdict];
1851
1980
  if ('manifest' === sub) {
1852
- if ('' !== report.mod) {
1853
- lines.push(report.mod + ' ' + report.version);
1854
- lines.push('config: ' + report.config);
1855
- }
1856
- for (const key of Object.keys(report.annotations).sort()) {
1857
- lines.push(key + ': ' + report.annotations[key]);
1858
- }
1859
- for (const file of report.files) {
1860
- lines.push('layer: ' + file);
1981
+ const m = report.manifest;
1982
+ if (null != m) {
1983
+ lines.push(m.package + ' ' + m.version + ' ' + m.publish);
1984
+ lines.push('archive: ' + m.archive.digest + ' (' + m.archive.files.length +
1985
+ ' files, ' + m.archive.size + ' bytes)');
1986
+ for (const mod of m.modules) {
1987
+ lines.push('module: ' + mod.path + ' ' + mod.main + ' ' + mod.canon);
1988
+ }
1989
+ for (const key of Object.keys(m.deps).sort(keyorder_1.cmpCodePoint)) {
1990
+ lines.push('dep: ' + key + ' ' + m.deps[key].v +
1991
+ (null == m.deps[key].pkg ? '' : ' (' + m.deps[key].pkg + ')'));
1992
+ }
1993
+ for (const v of m.retract ?? []) {
1994
+ lines.push('retract: ' + v);
1995
+ }
1996
+ if (null != m.moved) {
1997
+ lines.push('moved: ' + m.moved);
1998
+ }
1999
+ for (const f of m.archive.files) {
2000
+ lines.push('file: ' + f.path + ' ' + f.digest + ' ' + f.size);
2001
+ }
1861
2002
  }
1862
2003
  for (const f of report.findings) {
1863
2004
  lines.push(f.path + ': ' + f.message);
@@ -1865,44 +2006,281 @@ function modText(sub, report) {
1865
2006
  for (const miss of report.missing) {
1866
2007
  lines.push(miss + ': missing');
1867
2008
  }
2009
+ lines.push(...pkgForbiddenLines(report.forbidden));
1868
2010
  return lines.join('\n');
1869
2011
  }
1870
2012
  if ('verify' === sub) {
1871
- for (const mod of report.verified) {
1872
- lines.push(mod + ': verified');
2013
+ for (const key of report.verified) {
2014
+ lines.push(key + ': verified');
2015
+ }
2016
+ lines.push(...pkgMismatchLines(report.mismatched), ...pkgUnlockedLines(report.unlocked));
2017
+ for (const miss of report.missing) {
2018
+ lines.push(miss + ': not fetched (run: aontu sync)');
1873
2019
  }
1874
- for (const m of report.mismatched) {
1875
- lines.push(m.mod + ': pinned ' + m.want + ' but the store means ' +
1876
- ('' === m.got ? 'nothing (it does not evaluate)' : m.got));
2020
+ return lines.join('\n');
2021
+ }
2022
+ if ('refreeze' === sub) {
2023
+ for (const r of report.repinned) {
2024
+ lines.push(r.key + ': ' + r.from + ' -> ' + r.to);
1877
2025
  }
1878
- // NOT a fetch: the module may well be sitting in the store. What
1879
- // is absent is the PIN, and only a tidy writes one.
1880
- for (const mod of report.unlocked) {
1881
- lines.push(mod + ': not in the lockfile (run: aontu mod tidy)');
2026
+ for (const key of report.unchanged) {
2027
+ lines.push(key + ': unchanged');
2028
+ }
2029
+ for (const bad of report.unevaluable) {
2030
+ lines.push(bad + ': does not evaluate on its own; nothing to pin');
1882
2031
  }
1883
2032
  for (const miss of report.missing) {
1884
- lines.push(miss + ': not fetched (run: aontu mod get)');
2033
+ lines.push(miss + ': not fetched (run: aontu sync)');
1885
2034
  }
1886
2035
  return lines.join('\n');
1887
2036
  }
1888
- const done = 'tidy' === sub ? report.lock : report.vendored;
1889
- for (const item of done) {
1890
- lines.push('tidy' === sub ?
1891
- item.mod + ' ' + item.v + ' ' + item.canon : '' + item);
2037
+ if ('tree' === sub) {
2038
+ const byKey = new Map(report.nodes.map((n) => [n.key, n]));
2039
+ const seen = new Set();
2040
+ const walk = (key, depth) => {
2041
+ const node = byKey.get(key);
2042
+ const again = seen.has(key);
2043
+ seen.add(key);
2044
+ lines.push(' '.repeat(depth) + key +
2045
+ (null == node || '' === node.v ? '' : ' ' + node.v) +
2046
+ (again ? ' (above)' : null == node ? ' (not locked)' : ''));
2047
+ if (again || null == node) {
2048
+ return;
2049
+ }
2050
+ for (const dep of node.deps) {
2051
+ walk(dep, depth + 1);
2052
+ }
2053
+ };
2054
+ walk(report.root, 0);
2055
+ for (const miss of report.missing) {
2056
+ lines.push(miss + ': not fetched (run: aontu sync)');
2057
+ }
2058
+ return lines.join('\n');
1892
2059
  }
1893
- // A module that is PRESENT but does not stand up. Named separately
2060
+ const done = 'tidy' === sub ? pkgLockLines(report.lock) : report.vendored;
2061
+ lines.push(...done);
2062
+ // A package that is PRESENT but does not stand up. Named separately
1894
2063
  // from a missing one because the repair is different: a fetch cannot
1895
- // help, the module itself has to be fixed (or its own dependencies
2064
+ // help, the package itself has to be fixed (or its own dependencies
1896
2065
  // vendored beside it). Before the missing tail, as the Go port's
1897
2066
  // shared renderer orders them.
1898
2067
  for (const bad of report.unevaluable ?? []) {
1899
2068
  lines.push(bad + ': does not evaluate on its own; nothing to pin');
1900
2069
  }
2070
+ lines.push(...pkgForbiddenLines(report.forbidden ?? []));
1901
2071
  for (const miss of report.missing) {
1902
- lines.push(miss + ': not fetched (run: aontu mod get)');
2072
+ lines.push(miss + ': not fetched (run: aontu sync)');
1903
2073
  }
1904
2074
  return lines.join('\n');
1905
2075
  }
2076
+ // The two `pkg` subcommands that reach a repository.
2077
+ async function runPkgNet(sub, dir, args, opts, servers, io) {
2078
+ if ('serve' === sub) {
2079
+ const served = await (0, pkg_net_1.startServe)({
2080
+ dir: (0, node_path_1.resolve)(dir), upstream: args.upstream,
2081
+ listen: args.listen ?? '127.0.0.1:8017', http: servers.http(),
2082
+ });
2083
+ io.out('serving ' + (0, node_path_1.resolve)(dir) + ' at ' + served.url + '\n' +
2084
+ args.upstream.map((u) => 'upstream: ' + u + '\n').join(''));
2085
+ await servers.serve(served);
2086
+ await served.close();
2087
+ return 0;
2088
+ }
2089
+ if (null == opts.cache) {
2090
+ io.err(NO_CACHE);
2091
+ return 2;
2092
+ }
2093
+ const report = await (0, pkg_net_1.pkgOutdated)(dir, opts, servers.http(), { base: netBase(args) });
2094
+ io.out(pkgReportText('pkg outdated', args.format, report) + '\n');
2095
+ return PKG_EXIT[report.verdict];
2096
+ }
2097
+ const NO_CACHE = 'aontu: this verb reads and writes the user cache, which a ' +
2098
+ 'confined run (--trust root) does not reach and this host does not name ' +
2099
+ '(set XDG_CACHE_HOME or HOME)\n';
2100
+ function netBase(args) {
2101
+ return 0 === args.base.length ? undefined : args.base;
2102
+ }
2103
+ const PACKAGE_VERBS = ['sync', 'add', 'get', 'remove', 'why', 'publish'];
2104
+ const PACKAGE_HELP = {
2105
+ sync: 'aontu sync [--frozen] [dir] (try --help)',
2106
+ add: 'aontu add <pkg> [dir] (try --help)',
2107
+ get: 'aontu get <pkg>[@<version>] [dir] (try --help)',
2108
+ remove: 'aontu remove <pkg> [dir] (try --help)',
2109
+ why: 'aontu why <pkg> [dir] (try --help)',
2110
+ publish: 'aontu publish [--yes] [--to <dir>] [--key <file>] [dir] (try --help)',
2111
+ };
2112
+ // The top-level package verbs (ADR-039 part 5). Every one but `why`
2113
+ // reaches a repository, so every one runs behind the seam.
2114
+ async function runPackageVerb(verb, argv, servers) {
2115
+ const io = servers.io ?? PROCESS_IO;
2116
+ const trusted = takeTrust(argv, io);
2117
+ if (null == trusted) {
2118
+ return 2;
2119
+ }
2120
+ const args = parsePkgArgs(trusted.argv, verb, io);
2121
+ if (null == args) {
2122
+ return '-h' === trusted.argv[0] || trusted.argv.includes('--help') ? 0 : 2;
2123
+ }
2124
+ const wantsPkg = 'sync' !== verb && 'publish' !== verb;
2125
+ const dir = args.rest[wantsPkg ? 1 : 0] ?? '.';
2126
+ if (args.rest.length > (wantsPkg ? 2 : 1) || (wantsPkg && 0 === args.rest.length)) {
2127
+ io.err('aontu: ' + verb + (wantsPkg ? ' needs a package' : ' takes a directory') +
2128
+ '\n' + PACKAGE_HELP[verb] + '\n');
2129
+ return 2;
2130
+ }
2131
+ nameOldLayout(dir, io);
2132
+ const opts = pkgToolOptions(trusted.trust, (0, node_path_1.resolve)(dir));
2133
+ const http = servers.http();
2134
+ if ('why' === verb) {
2135
+ const report = (0, pkg_net_1.pkgWhy)(dir, opts, args.rest[0]);
2136
+ io.out(pkgReportText('why', args.format, report) + '\n');
2137
+ return PKG_EXIT[report.verdict];
2138
+ }
2139
+ if ('publish' === verb) {
2140
+ for (const f of [args.key, args.token]) {
2141
+ if (null != f && !(0, node_fs_1.existsSync)(f)) {
2142
+ io.err('aontu: cannot read ' + f + '\n');
2143
+ return 2;
2144
+ }
2145
+ }
2146
+ if (true === args.yes && null == args.key) {
2147
+ io.err('aontu: publish --yes needs --key <file>, the Ed25519 key that signs\n');
2148
+ return 2;
2149
+ }
2150
+ const report = await (0, pkg_net_1.pkgPublish)(dir, opts, http, {
2151
+ yes: args.yes, to: null == args.to ? undefined : (0, node_path_1.resolve)(args.to), key: args.key,
2152
+ token: args.token, against: args.against, base: netBase(args), write: args.write,
2153
+ });
2154
+ io.out(pkgReportText('publish', args.format, report) + '\n');
2155
+ return PKG_EXIT[report.verdict];
2156
+ }
2157
+ if (null == opts.cache) {
2158
+ io.err(NO_CACHE);
2159
+ return 2;
2160
+ }
2161
+ const net = { base: netBase(args) };
2162
+ const report = 'sync' === verb ? await (0, pkg_net_1.pkgSync)(dir, opts, http, { ...net, frozen: args.frozen }) :
2163
+ 'remove' === verb ? await (0, pkg_net_1.pkgRemove)(dir, opts, http, args.rest[0], net) :
2164
+ await (0, pkg_net_1.pkgGet)(dir, opts, http, args.rest[0], { ...net, mode: verb });
2165
+ if ('string' === typeof report) {
2166
+ io.err('aontu: ' + report + '\n');
2167
+ return 2;
2168
+ }
2169
+ io.out(pkgReportText(verb, args.format, report) + '\n');
2170
+ return PKG_EXIT[report.verdict];
2171
+ }
2172
+ function pkgReportText(verb, fmt, report) {
2173
+ return 'json' === fmt ?
2174
+ (0, aontu_1.exactJSON)({ aontu: { version: version(), verb }, ...report }, 2) :
2175
+ pkgNetText(verb, report);
2176
+ }
2177
+ function pkgNetText(verb, report) {
2178
+ const lines = ['verdict: ' + report.verdict];
2179
+ const tail = () => {
2180
+ for (const e of report.events ?? []) {
2181
+ lines.push(e.code + ': ' + e.message);
2182
+ }
2183
+ if (null != report.refusal) {
2184
+ lines.push('refused: ' + report.refusal.code + ': ' + report.refusal.message);
2185
+ }
2186
+ };
2187
+ if ('why' === verb) {
2188
+ const why = report;
2189
+ for (const p of why.paths) {
2190
+ lines.push(p.join(' -> '));
2191
+ }
2192
+ if ('missing' === why.verdict) {
2193
+ lines.push(why.pkg + ': not in the closure');
2194
+ }
2195
+ return lines.join('\n');
2196
+ }
2197
+ if ('publish' === verb) {
2198
+ const pub = report;
2199
+ lines.push(...pkgText('manifest', pub).split('\n').slice(1));
2200
+ if (null != pub.digest) {
2201
+ lines.push('digest: ' + pub.digest);
2202
+ }
2203
+ if (null != pub.signer) {
2204
+ lines.push('signer: ' + pub.signer);
2205
+ }
2206
+ if (null != pub.against) {
2207
+ lines.push('against: ' + pub.against);
2208
+ }
2209
+ if (null != pub.to) {
2210
+ lines.push('to: ' + pub.to);
2211
+ }
2212
+ if (null != pub.write) {
2213
+ lines.push('write: ' + pub.write + pkg_net_1.PUBLISH_PATH);
2214
+ }
2215
+ if ('dry-run' === pub.verdict) {
2216
+ lines.push('dry run: nothing sent (add --yes)');
2217
+ }
2218
+ if ('sent' === pub.verdict) {
2219
+ lines.push('sent');
2220
+ }
2221
+ tail();
2222
+ return lines.join('\n');
2223
+ }
2224
+ if ('pkg outdated' === verb) {
2225
+ const out = report;
2226
+ for (const e of out.locked) {
2227
+ if (0 < (0, pkg_1.versionCompare)(e.newest, e.v)) {
2228
+ lines.push(e.key + ' ' + e.v + ' -> ' + e.newest);
2229
+ for (const m of e.moves) {
2230
+ lines.push(' ' + m);
2231
+ }
2232
+ }
2233
+ else {
2234
+ lines.push(e.key + ' ' + e.v + ': current');
2235
+ }
2236
+ if (null != e.retracted) {
2237
+ lines.push(e.key + ' ' + e.v + ': retracted by ' + e.retracted);
2238
+ }
2239
+ }
2240
+ tail();
2241
+ return lines.join('\n');
2242
+ }
2243
+ const sync = report;
2244
+ if (null != sync.change) {
2245
+ lines.push('change: ' + sync.change);
2246
+ }
2247
+ for (const f of sync.fetched) {
2248
+ lines.push('fetched: ' + f);
2249
+ }
2250
+ lines.push(...pkgLockLines(sync.lock));
2251
+ for (const bad of sync.unevaluable) {
2252
+ lines.push(bad + ': does not evaluate on its own; nothing to pin');
2253
+ }
2254
+ lines.push(...pkgForbiddenLines(sync.forbidden), ...pkgMismatchLines(sync.mismatched), ...pkgUnlockedLines(sync.unlocked));
2255
+ for (const miss of sync.missing) {
2256
+ lines.push(miss + ': not fetched (run: aontu sync)');
2257
+ }
2258
+ for (const c of sync.changes) {
2259
+ lines.push('lockfile would change: ' + c);
2260
+ }
2261
+ tail();
2262
+ return lines.join('\n');
2263
+ }
2264
+ const MODEL_HELP = 'aontu model get|why|set ... (try --help)';
2265
+ // One document, interrogated or edited (ADR-039 part 5).
2266
+ function runModel(argv) {
2267
+ const sub = argv[0];
2268
+ if ('-h' === sub || '--help' === sub) {
2269
+ process.stdout.write(HELP);
2270
+ return 0;
2271
+ }
2272
+ if ('get' === sub) {
2273
+ return runGet(argv.slice(1));
2274
+ }
2275
+ if ('why' === sub) {
2276
+ return runWhy(argv.slice(1));
2277
+ }
2278
+ if ('set' === sub) {
2279
+ return runSet(argv.slice(1));
2280
+ }
2281
+ process.stderr.write(`aontu: model needs get, why or set\n${MODEL_HELP}\n`);
2282
+ return 2;
2283
+ }
1906
2284
  function vacuous(what, why) {
1907
2285
  process.stderr.write(`aontu: ${what}: ${why}\n`);
1908
2286
  }
@@ -2807,7 +3185,7 @@ function runHash(argv) {
2807
3185
  process.stdout.write(text + '\n');
2808
3186
  return 0;
2809
3187
  }
2810
- const GET_HELP = 'aontu get <path> <file> (try --help)';
3188
+ const GET_HELP = 'aontu model get <path> <file> (try --help)';
2811
3189
  function runGet(argv) {
2812
3190
  const trusted = takeTrust(argv);
2813
3191
  if (null == trusted) {
@@ -2851,7 +3229,7 @@ function runGet(argv) {
2851
3229
  format = f;
2852
3230
  }
2853
3231
  else if (arg.startsWith('-')) {
2854
- process.stderr.write(`aontu: unknown get option ${arg} (try --help)\n`);
3232
+ process.stderr.write(`aontu: unknown model get option ${arg} (try --help)\n`);
2855
3233
  return 2;
2856
3234
  }
2857
3235
  else {
@@ -2859,7 +3237,7 @@ function runGet(argv) {
2859
3237
  }
2860
3238
  }
2861
3239
  if (2 !== rest.length) {
2862
- process.stderr.write(`aontu: get needs a path and one file\n${GET_HELP}\n`);
3240
+ process.stderr.write(`aontu: model get needs a path and one file\n${GET_HELP}\n`);
2863
3241
  return 2;
2864
3242
  }
2865
3243
  const [path, file] = rest;
@@ -2883,7 +3261,7 @@ function runGet(argv) {
2883
3261
  });
2884
3262
  if ('json' === format) {
2885
3263
  process.stdout.write((0, aontu_1.exactJSON)({
2886
- aontu: { version: version(), verb: 'get' },
3264
+ aontu: { version: version(), verb: 'model get' },
2887
3265
  findings: report.findings,
2888
3266
  ok: report.ok,
2889
3267
  out: report.out,
@@ -2908,7 +3286,7 @@ function runGet(argv) {
2908
3286
  // contributions that met there, each with the site it was written at.
2909
3287
  // The positive twin of the vet report: errors explain what failed to
2910
3288
  // unify, this explains what did.
2911
- const WHY_HELP = 'aontu why <path> <file> (try --help)';
3289
+ const WHY_HELP = 'aontu model why <path> <file> (try --help)';
2912
3290
  function runWhy(argv) {
2913
3291
  const trusted = takeTrust(argv);
2914
3292
  if (null == trusted) {
@@ -2933,7 +3311,7 @@ function runWhy(argv) {
2933
3311
  format = f;
2934
3312
  }
2935
3313
  else if (arg.startsWith('-')) {
2936
- process.stderr.write(`aontu: unknown why option ${arg} (try --help)\n`);
3314
+ process.stderr.write(`aontu: unknown model why option ${arg} (try --help)\n`);
2937
3315
  return 2;
2938
3316
  }
2939
3317
  else {
@@ -2941,7 +3319,7 @@ function runWhy(argv) {
2941
3319
  }
2942
3320
  }
2943
3321
  if (2 !== rest.length) {
2944
- process.stderr.write(`aontu: why needs a path and one file\n${WHY_HELP}\n`);
3322
+ process.stderr.write(`aontu: model why needs a path and one file\n${WHY_HELP}\n`);
2945
3323
  return 2;
2946
3324
  }
2947
3325
  const [path, file] = rest;
@@ -2958,7 +3336,7 @@ function runWhy(argv) {
2958
3336
  });
2959
3337
  if ('json' === format) {
2960
3338
  process.stdout.write((0, aontu_1.exactJSON)({
2961
- aontu: { version: version(), verb: 'why' },
3339
+ aontu: { version: version(), verb: 'model why' },
2962
3340
  findings: report.findings,
2963
3341
  ok: report.ok,
2964
3342
  ...(null == report.record ? {} : { record: report.record }),
@@ -2990,7 +3368,7 @@ function renderWhyText(record) {
2990
3368
  ('literal' === c.role ? '' : ` (${c.role})`);
2991
3369
  })).join('\n');
2992
3370
  }
2993
- const SET_HELP = 'aontu set <path>=<value> --entry <file> --overlay <file> (try --help)';
3371
+ const SET_HELP = 'aontu model set <path>=<value> --entry <file> --overlay <file> (try --help)';
2994
3372
  function runSet(argv) {
2995
3373
  const trusted = takeTrust(argv);
2996
3374
  if (null == trusted) {
@@ -3031,7 +3409,7 @@ function runSet(argv) {
3031
3409
  format = f;
3032
3410
  }
3033
3411
  else if (arg.startsWith('-')) {
3034
- process.stderr.write(`aontu: unknown set option ${arg} (try --help)\n`);
3412
+ process.stderr.write(`aontu: unknown model set option ${arg} (try --help)\n`);
3035
3413
  return 2;
3036
3414
  }
3037
3415
  else {
@@ -3039,7 +3417,7 @@ function runSet(argv) {
3039
3417
  }
3040
3418
  }
3041
3419
  if (0 === assignments.length || null == entry || null == overlayFile) {
3042
- process.stderr.write(`aontu: set needs assignments, --entry and --overlay\n${SET_HELP}\n`);
3420
+ process.stderr.write(`aontu: model set needs assignments, --entry and --overlay\n${SET_HELP}\n`);
3043
3421
  return 2;
3044
3422
  }
3045
3423
  let entrySrc;
@@ -3086,7 +3464,7 @@ function runSet(argv) {
3086
3464
  }
3087
3465
  if ('json' === format) {
3088
3466
  process.stdout.write((0, aontu_1.exactJSON)({
3089
- aontu: { version: version(), verb: 'set' },
3467
+ aontu: { version: version(), verb: 'model set' },
3090
3468
  appended: report.appended,
3091
3469
  findings: report.findings,
3092
3470
  overlay: report.overlay,
@@ -3523,12 +3901,22 @@ function fmtOne(name, src, flags, marker) {
3523
3901
  }
3524
3902
  return flags.check ? 1 : strict;
3525
3903
  }
3904
+ const PROCESS_IO = {
3905
+ out: (s) => void process.stdout.write(s),
3906
+ err: (s) => void process.stderr.write(s),
3907
+ };
3908
+ // `pkg serve` runs until the process is interrupted.
3909
+ function serveUntilInterrupted() {
3910
+ return new Promise((done) => process.once('SIGINT', () => done()));
3911
+ }
3526
3912
  // Excluded: the real pair takes the process stdio, so ts/test/cli.test.ts
3527
3913
  // drives each server through a child process instead.
3528
- /* node:coverage ignore next 4 */
3914
+ /* node:coverage ignore next 6 */
3529
3915
  const SERVERS = {
3530
3916
  lsp: () => void (0, lsp_server_1.main)(),
3531
3917
  mcp: (argv) => void (0, mcp_server_1.main)(undefined, undefined, undefined, undefined, argv),
3918
+ serve: serveUntilInterrupted,
3919
+ http: pkg_net_1.defaultHttp,
3532
3920
  };
3533
3921
  // undefined: the server took the process; a number: an answer the CLI
3534
3922
  // gives itself, --help or a usage error.
@@ -3801,10 +4189,10 @@ function runInit(argv) {
3801
4189
  return 0;
3802
4190
  }
3803
4191
  const KNOWN_VERBS = [
3804
- 'agentsmd', 'allow', 'breaking', 'explain', 'fmt', 'get', 'hash',
3805
- 'help', 'init', 'jsonschema', 'lsp', 'mcp', 'mod', 'reaches',
3806
- 'relations', 'set', 'subsume', 'template', 'trace', 'trim',
3807
- 'vet', 'view', 'why',
4192
+ 'add', 'agentsmd', 'allow', 'breaking', 'explain', 'fmt', 'get', 'hash',
4193
+ 'help', 'init', 'jsonschema', 'lsp', 'mcp', 'model', 'pkg', 'publish',
4194
+ 'reaches', 'relations', 'remove', 'subsume', 'sync', 'template', 'trace',
4195
+ 'trim', 'vet', 'view', 'why',
3808
4196
  ];
3809
4197
  exports.KNOWN_VERBS = KNOWN_VERBS;
3810
4198
  // looksLikeVerb reports whether an unreadable argument was meant as a
@@ -3889,17 +4277,18 @@ function main(argv, servers = SERVERS) {
3889
4277
  if ('mcp' === argv[2]) {
3890
4278
  return servers.mcp(argv.slice(3));
3891
4279
  }
3892
- if ('set' === argv[2]) {
3893
- return finish(runSet(argv.slice(3)));
3894
- }
3895
4280
  if ('allow' === argv[2]) {
3896
4281
  return finish(runAllow(argv.slice(3)));
3897
4282
  }
3898
- if ('why' === argv[2]) {
3899
- return finish(runWhy(argv.slice(3)));
4283
+ if ('model' === argv[2]) {
4284
+ return finish(runModel(argv.slice(3)));
3900
4285
  }
3901
- if ('get' === argv[2]) {
3902
- return finish(runGet(argv.slice(3)));
4286
+ if ('pkg' === argv[2]) {
4287
+ const r = runPkg(argv.slice(3), servers);
4288
+ return 'number' === typeof r ? finish(r) : void r.then(finish);
4289
+ }
4290
+ if (PACKAGE_VERBS.includes(argv[2])) {
4291
+ return void runPackageVerb(argv[2], argv.slice(3), servers).then(finish);
3903
4292
  }
3904
4293
  if ('hash' === argv[2]) {
3905
4294
  return finish(runHash(argv.slice(3)));
@@ -3915,9 +4304,6 @@ function main(argv, servers = SERVERS) {
3915
4304
  if ('init' === argv[2]) {
3916
4305
  return finish(runInit(argv.slice(3)));
3917
4306
  }
3918
- if ('mod' === argv[2]) {
3919
- return finish(runMod(argv.slice(3)));
3920
- }
3921
4307
  if ('relations' === argv[2]) {
3922
4308
  return finish(runRelations(argv.slice(3)));
3923
4309
  }