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.
Files changed (128) hide show
  1. package/README.md +3 -3
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +10 -3
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/aontu.d.ts +4 -2
  6. package/dist/aontu.js +5 -2
  7. package/dist/aontu.js.map +1 -1
  8. package/dist/cli.d.ts +10 -3
  9. package/dist/cli.js +311 -53
  10. package/dist/cli.js.map +1 -1
  11. package/dist/diff.d.ts +1 -0
  12. package/dist/diff.js +3 -2
  13. package/dist/diff.js.map +1 -1
  14. package/dist/escape.d.ts +5 -0
  15. package/dist/escape.js +455 -0
  16. package/dist/escape.js.map +1 -0
  17. package/dist/format.d.ts +26 -0
  18. package/dist/format.js +1489 -0
  19. package/dist/format.js.map +1 -0
  20. package/dist/hints.js +39 -1
  21. package/dist/hints.js.map +1 -1
  22. package/dist/jsonschema.d.ts +1 -0
  23. package/dist/jsonschema.js +3 -2
  24. package/dist/jsonschema.js.map +1 -1
  25. package/dist/lang.js +84 -6
  26. package/dist/lang.js.map +1 -1
  27. package/dist/lsp.d.ts +2 -1
  28. package/dist/lsp.js +4 -4
  29. package/dist/lsp.js.map +1 -1
  30. package/dist/mcp-server.js +2 -2
  31. package/dist/mcp-server.js.map +1 -1
  32. package/dist/mcp.js +6 -4
  33. package/dist/mcp.js.map +1 -1
  34. package/dist/mod-tool.js +8 -7
  35. package/dist/mod-tool.js.map +1 -1
  36. package/dist/mod.js +6 -6
  37. package/dist/mod.js.map +1 -1
  38. package/dist/patch.d.ts +1 -0
  39. package/dist/patch.js +1 -0
  40. package/dist/patch.js.map +1 -1
  41. package/dist/query.d.ts +1 -0
  42. package/dist/query.js +4 -3
  43. package/dist/query.js.map +1 -1
  44. package/dist/reach.d.ts +1 -0
  45. package/dist/reach.js +3 -2
  46. package/dist/reach.js.map +1 -1
  47. package/dist/relation.d.ts +1 -0
  48. package/dist/relation.js +3 -2
  49. package/dist/relation.js.map +1 -1
  50. package/dist/sigdecl.js +1 -1
  51. package/dist/sigdecl.js.map +1 -1
  52. package/dist/std.js +2 -1
  53. package/dist/std.js.map +1 -1
  54. package/dist/subsume.d.ts +1 -0
  55. package/dist/subsume.js +3 -2
  56. package/dist/subsume.js.map +1 -1
  57. package/dist/trim.d.ts +1 -0
  58. package/dist/trim.js +3 -2
  59. package/dist/trim.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/type.d.ts +1 -0
  62. package/dist/type.js.map +1 -1
  63. package/dist/utility.d.ts +8 -2
  64. package/dist/utility.js +9 -1
  65. package/dist/utility.js.map +1 -1
  66. package/dist/val/EachFuncVal.js +1 -2
  67. package/dist/val/EachFuncVal.js.map +1 -1
  68. package/dist/val/EmitFuncVal.d.ts +23 -0
  69. package/dist/val/EmitFuncVal.js +261 -0
  70. package/dist/val/EmitFuncVal.js.map +1 -0
  71. package/dist/val/FilterFuncVal.js +1 -2
  72. package/dist/val/FilterFuncVal.js.map +1 -1
  73. package/dist/val/FuncBaseVal.d.ts +1 -0
  74. package/dist/val/FuncBaseVal.js +16 -0
  75. package/dist/val/FuncBaseVal.js.map +1 -1
  76. package/dist/val/PackFuncVal.js +1 -2
  77. package/dist/val/PackFuncVal.js.map +1 -1
  78. package/dist/val/PlaceVal.d.ts +3 -1
  79. package/dist/val/PlaceVal.js +8 -6
  80. package/dist/val/PlaceVal.js.map +1 -1
  81. package/dist/val/StrFuncVal.d.ts +32 -0
  82. package/dist/val/StrFuncVal.js +292 -0
  83. package/dist/val/StrFuncVal.js.map +1 -0
  84. package/dist/vet.d.ts +1 -0
  85. package/dist/vet.js +1 -1
  86. package/dist/vet.js.map +1 -1
  87. package/dist/view.d.ts +2 -1
  88. package/dist/view.js +379 -8
  89. package/dist/view.js.map +1 -1
  90. package/grammar/aontu.abnf +156 -0
  91. package/grammar/aontu.gbnf +4 -3
  92. package/grammar/aontu.lark +4 -3
  93. package/grammar/aontu.tmLanguage.json +1 -1
  94. package/package.json +2 -1
  95. package/skill/grammar-card.md +5 -2
  96. package/src/agentsmd.ts +15 -3
  97. package/src/aontu.ts +8 -1
  98. package/src/cli.ts +365 -58
  99. package/src/diff.ts +7 -2
  100. package/src/escape.ts +371 -0
  101. package/src/format.ts +1728 -0
  102. package/src/hints.ts +53 -1
  103. package/src/jsonschema.ts +7 -1
  104. package/src/lang.ts +93 -6
  105. package/src/lsp.ts +8 -6
  106. package/src/mcp-server.ts +3 -2
  107. package/src/mcp.ts +6 -4
  108. package/src/mod-tool.ts +9 -8
  109. package/src/mod.ts +6 -6
  110. package/src/patch.ts +7 -0
  111. package/src/query.ts +8 -4
  112. package/src/reach.ts +7 -2
  113. package/src/relation.ts +7 -2
  114. package/src/sigdecl.ts +1 -1
  115. package/src/std.ts +2 -1
  116. package/src/subsume.ts +7 -2
  117. package/src/trim.ts +7 -2
  118. package/src/type.ts +8 -0
  119. package/src/utility.ts +27 -2
  120. package/src/val/EachFuncVal.ts +1 -3
  121. package/src/val/EmitFuncVal.ts +401 -0
  122. package/src/val/FilterFuncVal.ts +1 -3
  123. package/src/val/FuncBaseVal.ts +18 -0
  124. package/src/val/PackFuncVal.ts +1 -3
  125. package/src/val/PlaceVal.ts +8 -6
  126. package/src/val/StrFuncVal.ts +334 -0
  127. package/src/vet.ts +9 -3
  128. package/src/view.ts +442 -9
package/src/hints.ts CHANGED
@@ -192,6 +192,8 @@ const hints: Record<string, string> = {
192
192
  view_kind_unknown: 'The figure kind is not one the verb draws. The kinds are tree, matrix,\ngraph, layer, sets, layers, ladder and poset; the note lists them.',
193
193
 
194
194
  view_profile_unknown: 'The figure kind does not render into the profile asked for: there is no\ntext form of a node-link drawing and no Mermaid form of a matrix. The\nnote lists the profiles the kind declares; the first is its default.',
195
+
196
+ format_check: 'The formatted text is not the same document, so nothing was written.\nThis is a formatter defect: please report it, with the source.',
195
197
  view_style_profile: 'Each profile has ONE way to carry the meaning of a figure\'s marks:\nSGR escapes for text, CSS classes for svg. Asking for the other one is\na usage error rather than a silent no-op. `none` works everywhere.',
196
198
  view_style_unknown: 'The styles are none, ansi and css, plus `auto` at the command line,\nwhich the command resolves before the library runs: whether the\ndestination is a terminal is not something a library can see.',
197
199
 
@@ -220,11 +222,33 @@ const hints: Record<string, string> = {
220
222
 
221
223
  match_none: 'No pattern matched, and there is no default. `match` tries each\npattern in the order written and takes the first the value unifies\nwith; the value {value} unified with none of {tried}. Add a trailing\ndefault — the argument after the last pair — if the rest was meant\nto be allowed.\n \nExamples:\n match(1, integer, ok) -> "ok" # The first pattern matches;\n match(x, integer, ok, other) -> "other" # ... or the default does;\n match(x, integer, ok) -> nil # ... but nothing here does.',
222
224
 
225
+ emit_data: 'The first argument to emit() is not a bag. `emit` visits the\nchildren of its SELECTION, so the selection has to have children: a\nlist of nodes, or a map whose values are the nodes.\n \nExamples:\n emit([{k:1}], {match:{k:1},body:[a]}) -> [..] # A list of nodes;\n emit({x:{k:1}}, {match:{k:1},body:[a]}) -> [..] # ... or a map of them;\n emit(1, {match:{k:1},body:[a]}) -> nil # ... but not a scalar.',
226
+
227
+ emit_table: 'The second argument to emit() is not a rule table. A table is a\nLIST of templates, tried in order; a single template may be written\nas the map itself, which is that list of one.\n \nExamples:\n emit($.n, [{match:integer,body:[a]}]) -> [..] # A table of rules;\n emit($.n, {match:integer,body:[a]}) -> [..] # ... or one rule alone;\n emit($.n, integer) -> nil # ... but not a value.',
228
+
229
+ emit_template: 'A template in an emit() table is not a rule. Every rule is a map\nnaming both a `match` — the pattern the node is tried against — and a\n`body`, the pieces to emit. A rule with no pattern would claim every\nnode by accident; one with no body would claim a node and emit\nnothing.\n \nExamples:\n {match: {kind: sqs}, body: [a]} # A rule;\n {match: {kind: sqs}} # ... but a pattern is not one;\n {body: [a]} # ... nor is a body alone.',
230
+
231
+ emit_body: 'A template body in an emit() table is not a list. A body is the\nSEQUENCE of pieces the matched node emits, so it is written as a\nlist even when it holds one piece — which is what lets bodies\ncompose, since a body element that is itself a list splices.\n \nExamples:\n {match: integer, body: [a]} -> [..] # One piece;\n {match: integer, body: [a,b]} -> [..] # ... or several;\n {match: integer, body: a} -> nil # ... but not a bare value.',
232
+
233
+ emit_ref: 'A template body names {ref}, and the node it matched cannot\nanswer it. Inside a body a relative reference is a field of the\nMATCHED NODE — `.pin` is that node\'s `pin` — so the node has to have\nthe field; the node was {value}. An absolute reference (`$.x`) reads\nthe document root instead, and is untouched.\n \nExamples:\n {match:{pin:string}, body:[.pin]} -> [..] # A field of the node;\n {match:{pin:string}, body:[$.z]} -> [..] # ... or the root;\n {match:{pin:string}, body:[.port]} -> nil # ... but not a field it\n # has not got.',
234
+
235
+ emit_none: 'No template matched a node, and there is no catch-all. `emit`\ntries each template in the order written and takes the first the\nnode unifies with; the node {value} unified with none of {tried}.\nAdd a template whose `match` is `any` — last, since the first match\nwins — if the rest of the selection was meant to be allowed.\n \nExamples:\n emit([1], [{match:integer,body:[a]}]) -> [..] # A pattern matches;\n emit([x], [{match:any,body:[a]}]) -> [..] # ... or a catch-all;\n emit([x], [{match:integer,body:[a]}]) -> nil # ... but nothing here.',
236
+
237
+ esc_variant: 'esc() and usc() were given a variant that names no convention.\nA variant names a CONVENTION rather than a language, because several\nlanguages share one and one language has several. The names are `sq`,\n`sql`, `shell`, `xml`, `uri` and `regex`; written with no variant at\nall it is the C escape, JSON canonical, which covers the double-quoted\nliteral of every C-family language.\n \nExamples:\n esc(text) -> ... # C / JSON, the default;\n esc(text, sq) -> ... # ... single-quoted C-family;\n esc(text, pascal) -> nil # ... but that is not a convention.',
238
+
239
+ usc_malformed: 'usc() was given text the convention could not have produced,\nso there is nothing to read back out: a truncated code-point escape, an\nescape the convention does not define, or an escape character standing\nalone where the convention doubles it. `usc` is the LEFT inverse of\n`esc` and it is partial — every escaped value has an original, but not\nevery string is an escaped value.\n \nExamples:\n usc(esc(text)) -> ... # Whatever esc() wrote;\n usc(text, sql) -> ... # ... in the same convention;\n usc(text, shell) -> nil # ... but not in another one.',
240
+
241
+ rep_pattern: 'The pattern given to rep() is outside the portable subset. It is\nthe same subset re() takes — RE2-compatible, no backreferences, no\nlookaround — so one document has one regexp language rather than two,\nand so a generator running a pattern over model data cannot take\nexponential time doing it.\n \nExamples:\n rep(s, "[:,]", " ") -> ... # A class;\n rep(s, "(a)(b)", "$2$1") -> ... # ... a group;\n rep(s, "(?=a)", "x") -> nil # ... but not a lookahead.',
242
+
243
+ rep_sub: 'The substitution given to rep() names something the pattern has\nnot got. `$1` to `$9` are the numbered groups, `$&` is the whole match\nand `$$` is a literal `$`; a `$` naming anything else, or a group\nnumber the pattern does not have, is refused rather than expanded to\nnothing — a generator that writes a file with a hole in it and says\nnothing is the failure this refusal exists to close.\n \nExamples:\n rep(s, "(a)", "[$1]") -> ... # A group the pattern has;\n rep(s, "a", "$$") -> ... # ... a literal dollar;\n rep(s, "a", "$1") -> nil # ... but not a group it has not.',
244
+
245
+ split_sep: 'The separator given to split() is neither a string nor a pattern.\nA plain string is a LITERAL and an `re(…)` argument is a pattern — the\nasymmetry with rep() is deliberate, since splitting is usually on a\nliteral, and it removes the trap where `split(v, ".")` silently cuts\nbetween every character.\n \nExamples:\n split("a,b", ",") -> [..] # A literal separator;\n split("a1b", re("[0-9]")) -> [..] # ... or a pattern;\n split("a,b", 1) -> nil # ... but not a number.',
246
+
223
247
  place_pair: 'Two placeholders met, and neither has a value to fill the other.\n`_` is a HOLE: it is filled by whatever the call is unified with, so\na call holding one needs a peer that does not. Give one side a\nvalue.\n \nExamples:\n upper(_) & hello -> "HELLO" # The peer fills the hole;\n _ + 2 & 1 -> 3 # ... whatever the call is;\n upper(_) & lower(_) -> nil # ... but two holes fill nothing.',
224
248
 
225
249
 
226
250
  module_path: 'A module import is domain-shaped and carries a major, but its\npath cannot be a directory on every platform the toolchain runs on --\nso it is refused before anything is built from it. An element may not\nbe empty, may not begin or end with `.` (which is what forbids `..`),\nand may not be a reserved device name. These are Go\'s module-path\nrules, for Go\'s reason: a module path becomes a real directory.\n \nExamples:\n @"corp.example/s@1" -> {..} # An ordinary path is fine;\n @"corp.example/../s@1" -> nil # ... `..` would escape the store;\n @"corp.example/nul@1" -> nil # ... and Windows has no such file.',
227
- module_missing: 'A module import names a module that is not in this project. A\nmodule is resolved from LOCAL stores only -- `aon_vendor/` beside the\nproject\'s mod.aon, then the user cache -- because evaluation never\ntouches the network. Fetching is a separate step, and the message\nnames it.\n \nExamples:\n @"corp.example/s@1" -> nil # Not fetched: run aontu mod get;\n @"./local.aon" -> {..} # ... a local path is not a module;\n @"corp.example/s@1#aon1-…" -> {..} # ... and a pin does not fetch it either.',
251
+ module_missing: 'A module import names a module that is not in this project. A\nmodule is resolved from LOCAL stores only -- `aontu_meta/vendor/` beside the\nproject\'s mod.aon, then the user cache -- because evaluation never\ntouches the network. Fetching is a separate step, and the message\nnames it.\n \nExamples:\n @"corp.example/s@1" -> nil # Not fetched: run aontu mod get;\n @"./local.aon" -> {..} # ... a local path is not a module;\n @"corp.example/s@1#aon1-…" -> {..} # ... and a pin does not fetch it either.',
228
252
 
229
253
  module_integrity: 'A module resolved locally does not have the MEANING it was pinned\nto. The pin is a canon-hash -- the hash of the module unified\nstandalone -- so it survives comments, formatting and refactoring and\nbreaks on any semantic change in the module\'s transitive closure.\nVerification is always local: the registry\'s annotation is advisory.\n \nExamples:\n @"corp.example/s@1" -> {..} # No pin, no check;\n @"corp.example/s@1#aon1-x" -> nil # ... a pin that disagrees refuses;\n aontu hash <file> # ... and this is what it should be.',
230
254
 
@@ -513,6 +537,9 @@ const codeClasses: Record<string, string> = {
513
537
  view_profile_unknown: 'reference',
514
538
  view_style_profile: 'reference',
515
539
  view_style_unknown: 'reference',
540
+ // The formatter's self-check (docs/design/FMT.0.md): a report-layer
541
+ // code, class internal -- the formatter, not the document, is wrong.
542
+ format_check: 'internal',
516
543
  view_rows_exceeded: 'budget',
517
544
  view_line_break: 'parse',
518
545
  view_relation_ambiguous: 'reference',
@@ -544,6 +571,31 @@ const codeClasses: Record<string, string> = {
544
571
  filter_data: 'parse',
545
572
  match_none: 'conflict',
546
573
 
574
+ // G9 phase 6 -- the string builtins. All five are class `parse`:
575
+ // what is wrong is the CALL as written -- a variant that names no
576
+ // convention, a pattern outside the subset, a substitution naming a
577
+ // group that does not exist, a separator that is neither string nor
578
+ // pattern. `usc_malformed` is the odd one and still `parse`: the
579
+ // TEXT the call was given has no inverse, which is a fact about the
580
+ // argument rather than about any meet.
581
+ esc_variant: 'parse',
582
+ usc_malformed: 'parse',
583
+ rep_pattern: 'parse',
584
+ rep_sub: 'parse',
585
+ split_sep: 'parse',
586
+
587
+ // G9 phase 6 -- apply-templates. The four shape codes are class
588
+ // `parse`: what is wrong is the CALL as written -- a selection with
589
+ // no children, a table that is not one, a rule missing a half.
590
+ // `emit_none` is class `conflict` for `match_none`'s reason: the
591
+ // node and every pattern written for it disagreed.
592
+ emit_data: 'parse',
593
+ emit_table: 'parse',
594
+ emit_template: 'parse',
595
+ emit_body: 'parse',
596
+ emit_none: 'conflict',
597
+ emit_ref: 'conflict',
598
+
547
599
  // G8 phase 3 -- the placeholder. Class `conflict`: two values met
548
600
  // and neither could answer for the other, which is what every
549
601
  // conflict is.
package/src/jsonschema.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+ import { includeOpts } from './utility'
2
3
 
3
4
  // JSON SCHEMA EXPORT (the review's finding I / SUPPORT.md act 2).
4
5
  //
@@ -75,6 +76,11 @@ export type SchemaOptions = {
75
76
  // its own directory.
76
77
  path?: string
77
78
  trust?: TrustOptions
79
+
80
+ // Extensions additionally read as text (the CLI's `--text-ext`).
81
+ // Rides beside `trust` because it is the other half of what an
82
+ // include may read.
83
+ textExt?: string[]
78
84
  }
79
85
 
80
86
 
@@ -501,7 +507,7 @@ function fromList(ctx: Ctx, path: string[], v: any): any {
501
507
  // The verb. Evaluate, anchor, walk, report.
502
508
  export function jsonSchema(src: string, options?: SchemaOptions): SchemaReport {
503
509
  const opts = options ?? {}
504
- const aontu = new Aontu(null == opts.trust ? {} : { trust: opts.trust })
510
+ const aontu = new Aontu(includeOpts(opts))
505
511
 
506
512
  // COLLECT MODE, so a syntax error arrives on the context rather than
507
513
  // as a throw -- the same failure Go's `parseEntry` hands back as an
package/src/lang.ts CHANGED
@@ -145,6 +145,10 @@ import { PackFuncVal } from './val/PackFuncVal'
145
145
  import { EachFuncVal } from './val/EachFuncVal'
146
146
  import { FilterFuncVal } from './val/FilterFuncVal'
147
147
  import { MatchFuncVal } from './val/MatchFuncVal'
148
+ import { EmitFuncVal } from './val/EmitFuncVal'
149
+ import {
150
+ EscFuncVal, UscFuncVal, RepFuncVal, SplitFuncVal,
151
+ } from './val/StrFuncVal'
148
152
  import {
149
153
  AddFuncVal, SubFuncVal, MulFuncVal, DivFuncVal, ModFuncVal, RemFuncVal,
150
154
  } from './val/ArithFuncVal'
@@ -667,6 +671,25 @@ help isolate the syntax error.`,
667
671
  // the language does not grow a second. It is the primitive that
668
672
  // turns a bag of computed lines into a file.
669
673
  join: JoinFuncVal,
674
+
675
+ // G9 phase 6: apply-templates. One flat list of pieces from a
676
+ // selection and a RULE TABLE -- for each node, the first template
677
+ // whose `match` it unifies with, its `body` instantiated at that
678
+ // node. The dispatch is the engine's because a body referenced by
679
+ // path resolves its references at the definition site, and the
680
+ // relative resolution that does exist is a dot count that does not
681
+ // survive a second dispatch (docs/design/EMIT.0.md).
682
+ emit: EmitFuncVal,
683
+
684
+ // G9 phase 6: the string builtins the rule layer needs. `esc`
685
+ // makes a value safe inside a literal and `usc` reads it back;
686
+ // `rep` and `split` derive names from model data. All four are
687
+ // ordinary string functions -- they know nothing about generation,
688
+ // which is why they can land before the renderer does.
689
+ esc: EscFuncVal,
690
+ usc: UscFuncVal,
691
+ rep: RepFuncVal,
692
+ split: SplitFuncVal,
670
693
  }
671
694
 
672
695
 
@@ -1597,6 +1620,14 @@ help isolate the syntax error.`,
1597
1620
  // references, constraints, its own includes. Two extensions, and they
1598
1621
  // are the ones this project owns.
1599
1622
  //
1623
+ // `text` — the file's BYTES, as one string scalar. No parser is
1624
+ // chosen, so there is nothing for two ports to disagree about and
1625
+ // nothing in the file that can mean anything: `notes: @"notes.txt"`
1626
+ // is a document loading prose into a string. `.txt` is the only
1627
+ // extension here by default; `AontuOptions.textExt` (the CLI's
1628
+ // `--text-ext`) adds others, because which name a project keeps its
1629
+ // templates under is the project's business, not this table's.
1630
+ //
1600
1631
  // A FORMAT NAME — configuration DATA, parsed by that format's own
1601
1632
  // parser into the JSON value it denotes, which then becomes Aontu
1602
1633
  // values like any other data. Every one of these formats maps onto
@@ -1628,8 +1659,43 @@ const INCLUDE_KINDS: { [kind: string]: string } = {
1628
1659
  yaml: 'yaml',
1629
1660
  yml: 'yaml',
1630
1661
  ini: 'ini',
1662
+
1663
+ txt: 'text',
1664
+ }
1665
+
1666
+
1667
+ // WHAT AN EXTENSION MEANS, for this parse. The table is the fixed
1668
+ // part; `textExt` is the per-parse widening, and it wins over nothing
1669
+ // -- a host cannot re-read `.toml` as text, because an extension the
1670
+ // table already names has a meaning documents rely on. Undefined is
1671
+ // the refusal, and it is the ONE place that decides it: the resolver's
1672
+ // gate and the processor map both ask here, so a widening cannot reach
1673
+ // one and not the other.
1674
+ function includeFormat(
1675
+ ext: string, textExt?: string[]): string | undefined {
1676
+ const known = INCLUDE_KINDS[ext]
1677
+ if (undefined !== known) {
1678
+ return known
1679
+ }
1680
+ // NOT EVEN AS TEXT. `.js` is the extension ADR-012 singles out
1681
+ // because multisource's own default EXECUTES it, and an extension
1682
+ // this project refuses on purpose stays refused however a flag is
1683
+ // spelled -- reading it is harmless, but a widening that can reach
1684
+ // the one name the rule names is a widening whose limit nobody can
1685
+ // state. Go's includeFormat holds the same list, and the two CLIs
1686
+ // are diffed on `--text-ext js` because they once disagreed here.
1687
+ if (REFUSED_EXT.has(ext)) {
1688
+ return undefined
1689
+ }
1690
+ return textExt?.includes(ext) ? 'text' : undefined
1631
1691
  }
1632
1692
 
1693
+
1694
+ // Extensions no widening may reach. `js` executes under multisource's
1695
+ // default processor; `''` is the no-extension fallback, which names no
1696
+ // file type at all.
1697
+ const REFUSED_EXT = new Set(['js', ''])
1698
+
1633
1699
  // `.csv` IS DELIBERATELY ABSENT, and the reason is ADR-001 rather than
1634
1700
  // taste. The two ports' CSV parsers disagree about what a CSV file IS:
1635
1701
  // one answers header-keyed records with string fields, the other raw
@@ -1754,13 +1820,20 @@ const dataProcessor = (format: string) => (res: any) => {
1754
1820
  res.val = rawToVal(DATA_READERS[format](res.src, res.path))
1755
1821
  }
1756
1822
 
1823
+ // TEXT IS NOT PARSED. The bytes multisource read are the value, so
1824
+ // this is the one processor with no reader behind it -- which is why
1825
+ // a `.txt` include cannot fail on content, only on being unreadable.
1826
+ const textProcessor = (res: any) => {
1827
+ res.val = new StringVal({ peg: res.src })
1828
+ }
1829
+
1757
1830
  /**
1758
1831
  * The multisource processor map, built FROM the include table so the
1759
1832
  * two cannot drift: every extension the table names gets the reader
1760
1833
  * the table names for it, and the two kinds that are not in the table
1761
1834
  * refuse.
1762
1835
  */
1763
- function includeProcessors(): { [kind: string]: any } {
1836
+ function includeProcessors(textExt?: string[]): { [kind: string]: any } {
1764
1837
  const map: { [kind: string]: any } = {
1765
1838
  // multisource's fallback for an extension no entry names, so it is
1766
1839
  // the one that catches whatever the resolver's gate did not.
@@ -1769,9 +1842,23 @@ function includeProcessors(): { [kind: string]: any } {
1769
1842
  js: refuseProcessor,
1770
1843
  }
1771
1844
  const source = makeJsonicProcessor()
1845
+ const forKind = (kind: string) => {
1846
+ const format = includeFormat(kind, textExt)
1847
+ if ('source' === format) return source
1848
+ if ('text' === format) return textProcessor
1849
+ return dataProcessor(format as string)
1850
+ }
1772
1851
  for (const kind of Object.keys(INCLUDE_KINDS)) {
1773
- const format = INCLUDE_KINDS[kind]
1774
- map[kind] = 'source' === format ? source : dataProcessor(format)
1852
+ map[kind] = forKind(kind)
1853
+ }
1854
+ // A WIDENING NEVER OVERWRITES. `js` and the empty fallback refuse
1855
+ // above and stay refusing: `--text-ext js` would otherwise turn the
1856
+ // one extension ADR-012 singles out into a readable one, by a flag
1857
+ // whose whole promise is that it chooses no parser.
1858
+ for (const ext of textExt ?? []) {
1859
+ if (undefined === map[ext]) {
1860
+ map[ext] = textProcessor
1861
+ }
1775
1862
  }
1776
1863
  return map
1777
1864
  }
@@ -1893,7 +1980,7 @@ function makeModelResolver(options: any) {
1893
1980
  // module legs do not: both state `kind: 'aon'` because what they
1894
1981
  // serve is Aontu source by construction, not by its spelling.
1895
1982
  const gateExtension = (path: string, full: string): void => {
1896
- if (undefined === INCLUDE_KINDS[extKindOf(full)]) {
1983
+ if (undefined === includeFormat(extKindOf(full), options.textExt)) {
1897
1984
  refuseExtension(path, full)
1898
1985
  }
1899
1986
  }
@@ -2001,7 +2088,7 @@ function makeModelResolver(options: any) {
2001
2088
  const found = resolveModule(modref, from, modFs(ctx), {
2002
2089
  // The user cache lives outside any confinement root, so it is
2003
2090
  // consulted only when nothing confines this evaluation. A
2004
- // rooted profile sees the project's own `aon_vendor/` and
2091
+ // rooted profile sees the project's own `aontu_meta/vendor/` and
2005
2092
  // nothing else, which is what `root` means.
2006
2093
  ...(null == rootDir ? { cache: modCache(options) } : {}),
2007
2094
  eval: options.mod?.eval,
@@ -2308,7 +2395,7 @@ class Lang {
2308
2395
  // (BUGS §49b). Its `js` entry EXECUTES the file, which is not
2309
2396
  // something an extension should be able to ask for. And its
2310
2397
  // fallback hands any other file back as TEXT.
2311
- processor: includeProcessors()
2398
+ processor: includeProcessors(this.opts.textExt)
2312
2399
  })
2313
2400
  .use(AontuJsonic)
2314
2401
  }
package/src/lsp.ts CHANGED
@@ -21,7 +21,9 @@ import type { Val } from './type'
21
21
  import { Aontu, VERSION } from './aontu'
22
22
  import { getHint } from './err'
23
23
  import { collectNils } from './walk'
24
- import { collectDeprecations, deprecationMessage } from './utility'
24
+ import { collectDeprecations, deprecationMessage,
25
+ includeOpts,
26
+ } from './utility'
25
27
  import { why } from './query'
26
28
  import type { WhyConjunct } from './provenance'
27
29
 
@@ -84,13 +86,13 @@ type OutMessage = {
84
86
  // functions, syntax errors) produce diagnostics.
85
87
  function computeDiagnostics(
86
88
  src: string,
87
- opts?: { vars?: Record<string, Val>, trust?: any }
89
+ opts?: { vars?: Record<string, Val>, trust?: any, textExt?: string[] }
88
90
  ): Diagnostic[] {
89
91
  // The trust profile (G5, docs/trust.md): the LSP is the
90
92
  // highest-exposure surface — merely OPENING a hostile .aon file in an
91
93
  // editor performs its reads — so the handler confines evaluation to
92
94
  // the workspace root and threads the profile through here.
93
- const aontu = new Aontu(null == opts?.trust ? {} : { trust: opts.trust })
95
+ const aontu = new Aontu(includeOpts(opts ?? {}))
94
96
 
95
97
  let root: any
96
98
  let ac: any
@@ -525,13 +527,13 @@ const COMPLETION_KEYWORD = 14
525
527
  // between G4 phases 1/2 and G8 phase 1.
526
528
  const BUILTIN_FUNCS = [
527
529
  'above', 'acyclic', 'add', 'below', 'close', 'copy', 'deprecate', 'div',
528
- 'each',
530
+ 'each', 'emit', 'esc',
529
531
  'filter', 'greatest',
530
532
  'hide', 'inverse', 'join', 'key', 'least', 'length', 'list', 'lower',
531
533
  'map', 'match', 'max', 'min', 'mod', 'move', 'mul', 'must', 'neq', 'open',
532
534
  'pack', 'path', 'pick',
533
- 'pref', 're', 'refer', 'rel', 'rem', 'sub', 'sum', 'super', 'type', 'unique',
534
- 'upper',
535
+ 'pref', 're', 'refer', 'rel', 'rem', 'rep', 'split', 'sub', 'sum',
536
+ 'super', 'type', 'unique', 'upper', 'usc',
535
537
  ]
536
538
 
537
539
  // Scalar-kind and literal keywords.
package/src/mcp-server.ts CHANGED
@@ -30,9 +30,9 @@ import type { McpRequest, McpResponse } from './mcp'
30
30
  import { VERSION } from './aontu'
31
31
 
32
32
 
33
- const USAGE = 'aontu-mcp - Aontu MCP server (stdio, NDJSON JSON-RPC)\n' +
33
+ const USAGE = 'aontu mcp - Aontu MCP server (stdio, NDJSON JSON-RPC)\n' +
34
34
  '\n' +
35
- ' aontu-mcp [--root <dir>]\n' +
35
+ ' aontu mcp [--root <dir>]\n' +
36
36
  '\n' +
37
37
  ' --root <dir> Serve <name>Path file arguments and resolve\n' +
38
38
  ' @"..." includes, confined below <dir>\n' +
@@ -41,6 +41,7 @@ const USAGE = 'aontu-mcp - Aontu MCP server (stdio, NDJSON JSON-RPC)\n' +
41
41
 
42
42
 
43
43
  // The startup arguments. Parsed here rather than in bin/aontu-mcp.js
44
+ // or the CLI's mcp verb
44
45
  // so the parsing is import-testable; unknown options REFUSE rather
45
46
  // than warn, because a server whose operator typo'd --root must not
46
47
  // come up quietly unconfined.
package/src/mcp.ts CHANGED
@@ -459,6 +459,8 @@ const TOOLS: ToolDef[] = [
459
459
  name: 'view',
460
460
  description:
461
461
  'Draw a figure of the document as deterministic text. Kinds: ' +
462
+ 'doc (the shape of the document itself), lattice (the value ' +
463
+ 'lattice, with the document\'s own values placed on it), ' +
462
464
  'tree (the dependency tree of a relation), matrix (the ' +
463
465
  'dependency matrix, canon or partition order, --closure), graph ' +
464
466
  '(node-link, as mermaid, dot or er), layer (the architecture ' +
@@ -474,8 +476,8 @@ const TOOLS: ToolDef[] = [
474
476
  kind: {
475
477
  type: 'string',
476
478
  description:
477
- 'The figure to draw: tree (the default), matrix, graph, layer, ' +
478
- 'sets, layers or ladder',
479
+ 'The figure to draw: tree (the default), doc, lattice, matrix, ' +
480
+ 'graph, layer, sets, layers or ladder',
479
481
  },
480
482
  as: {
481
483
  type: 'string',
@@ -565,8 +567,8 @@ const TOOLS: ToolDef[] = [
565
567
  required: ['source'],
566
568
  docs: ['source'],
567
569
  check: (a) => {
568
- const kinds = ['doc', 'tree', 'matrix', 'graph', 'layer', 'sets',
569
- 'layers', 'ladder']
570
+ const kinds = ['doc', 'lattice', 'tree', 'matrix', 'graph', 'layer',
571
+ 'sets', 'layers', 'ladder']
570
572
  if (null != a.kind && !kinds.includes(a.kind)) {
571
573
  return `kind must be one of ${kinds.join(', ')}, not ${JSON.stringify(a.kind)}`
572
574
  }
package/src/mod-tool.ts CHANGED
@@ -78,7 +78,7 @@ export type ModVerifyReport = {
78
78
 
79
79
  export type ModVendorReport = {
80
80
  verdict: 'ok' | 'missing'
81
- // The modules materialised into `aon_vendor/`, sorted.
81
+ // The modules materialised into `aontu_meta/vendor/`, sorted.
82
82
  vendored: string[]
83
83
  // Locked modules present in no store, sorted.
84
84
  missing: string[]
@@ -193,7 +193,7 @@ function usableRef(mod: string): ModuleRef | undefined {
193
193
  function storeDir(
194
194
  root: string, ref: ModuleRef, hash: string, options: ModToolOptions,
195
195
  ): string | undefined {
196
- const stores = [moduleDir(pathJoin(root, 'aon_vendor'), ref)]
196
+ const stores = [moduleDir(pathJoin(root, 'aontu_meta', 'vendor'), ref)]
197
197
  if (null != options.cache && '' !== hash) {
198
198
  stores.push(pathJoin(options.cache, hash))
199
199
  }
@@ -203,7 +203,7 @@ function storeDir(
203
203
 
204
204
  // The lockfile's entries, as written.
205
205
  function readLock(root: string): Record<string, ModLock> {
206
- const file = pathJoin(root, 'mod-lock.aon')
206
+ const file = pathJoin(root, 'aontu_meta', 'mod-lock.aon')
207
207
  if (!existsSync(file)) {
208
208
  return {}
209
209
  }
@@ -335,7 +335,8 @@ export function modTidy(root: string, options: ModToolOptions): ModTidyReport {
335
335
  const uniqueUnevaluable = [...new Set(unevaluable)].sort()
336
336
  const held = 0 === uniqueMissing.length && 0 === uniqueUnevaluable.length
337
337
  if (held) {
338
- writeFileSync(pathJoin(root, 'mod-lock.aon'),
338
+ mkdirSync(pathJoin(root, 'aontu_meta'), { recursive: true })
339
+ writeFileSync(pathJoin(root, 'aontu_meta', 'mod-lock.aon'),
339
340
  LOCK_HEADER + lockText(lock, options) + '\n')
340
341
  }
341
342
 
@@ -441,14 +442,14 @@ export function modVerify(root: string, options: ModToolOptions):
441
442
  }
442
443
 
443
444
 
444
- // `aontu mod vendor`: materialise the locked closure into `aon_vendor/`.
445
+ // `aontu mod vendor`: materialise the locked closure into `aontu_meta/vendor/`.
445
446
  export function modVendor(root: string, options: ModToolOptions):
446
447
  ModVendorReport {
447
448
  const locked = readLock(root)
448
449
  const vendored: string[] = []
449
450
  const missing: string[] = []
450
451
 
451
- const vendorRoot = pathJoin(root, 'aon_vendor')
452
+ const vendorRoot = pathJoin(root, 'aontu_meta', 'vendor')
452
453
 
453
454
  for (const mod of Object.keys(locked).sort()) {
454
455
  const ref = usableRef(mod)
@@ -593,13 +594,13 @@ function majorOf(version: string): string {
593
594
 
594
595
 
595
596
  // Every file of a module's source tree, relative and forward-slashed.
596
- // `aon_vendor/` is excluded: a published module carries its own
597
+ // `aontu_meta/vendor/` is excluded: a published module carries its own
597
598
  // sources, not a copy of everyone else's -- a consumer resolves the
598
599
  // closure itself, and a nested vendor tree would publish the world.
599
600
  function layerFiles(dir: string, prefix = ''): string[] {
600
601
  const out: string[] = []
601
602
  for (const name of readdirSync(dir).sort()) {
602
- if ('aon_vendor' === name) {
603
+ if ('aontu_meta' === name) {
603
604
  continue
604
605
  }
605
606
  const full = pathJoin(dir, name)
package/src/mod.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  // local: @"./fragment.aon" <- unchanged, not a module
13
13
  //
14
14
  // EVALUATION NEVER TOUCHES THE NETWORK. Resolution reads local stores
15
- // only: `aon_vendor/` beside the project's `mod.aon`, then a
15
+ // only: `aontu_meta/vendor/` beside the project's `mod.aon`, then a
16
16
  // content-addressed user cache keyed by canon-hash. Fetching is a
17
17
  // separate, explicit tool step, and a module that is in neither store
18
18
  // is an evaluation error that says so.
@@ -81,7 +81,7 @@ export function parseModuleRef(spec: string): ModuleRef | undefined {
81
81
  // `[A-Za-z0-9._-]` admits `..`, and `moduleDir` joins elements with
82
82
  // pathJoin, which CLEANS `..` rather than refusing it:
83
83
  //
84
- // moduleDir('/store/aon_vendor', 'corp.example/../../etc/passwd@1')
84
+ // moduleDir('/store/aontu_meta/vendor', 'corp.example/../../etc/passwd@1')
85
85
  // -> /store/etc/passwd@1
86
86
  //
87
87
  // `mod vendor` then copied a tree THERE, outside the project entirely,
@@ -168,9 +168,9 @@ export function moduleDir(store: string, ref: ModuleRef): string {
168
168
  // root being a directory holding a `mod.aon`. This used to answer with
169
169
  // the NEAREST one alone, and the plural is the fix, because a
170
170
  // VENDORED MODULE IS A PROJECT INSIDE A PROJECT. A module in
171
- // `aon_vendor/` carries its own `mod.aon`, which stopped the upward
171
+ // `aontu_meta/vendor/` carries its own `mod.aon`, which stopped the upward
172
172
  // walk there, so a nested import resolved against the vendored
173
- // module's own directory: a tree with no `aon_vendor/` of its own, and
173
+ // module's own directory: a tree with no `aontu_meta/vendor/` of its own, and
174
174
  // therefore a `module not fetched` for a dependency sitting flat
175
175
  // beside it in the CONSUMER's vendor tree — the only layout `mod
176
176
  // vendor` produces (use-cases/BUGS.md §31).
@@ -272,7 +272,7 @@ export function modCacheDirFor(
272
272
 
273
273
  export function lockHash(root: string, ref: ModuleRef, fs: ModuleFs):
274
274
  string | undefined {
275
- const file = pathJoin(root, 'mod-lock.aon')
275
+ const file = pathJoin(root, 'aontu_meta', 'mod-lock.aon')
276
276
  if (!fs.existsSync(file)) {
277
277
  return undefined
278
278
  }
@@ -392,7 +392,7 @@ export function resolveModule(
392
392
  roots.map((r) => lockHash(r, ref, fs)).find((h) => null != h)
393
393
 
394
394
  const stores: string[] =
395
- roots.map((r) => moduleDir(pathJoin(r, 'aon_vendor'), ref))
395
+ roots.map((r) => moduleDir(pathJoin(r, 'aontu_meta', 'vendor'), ref))
396
396
  if (null != options.cache && null != expect) {
397
397
  // Content-addressed: the cache is keyed by the hash, so a cache hit
398
398
  // is already the right MEANING before anything is read from it.
package/src/patch.ts CHANGED
@@ -75,6 +75,12 @@ export type PatchOptions = {
75
75
  // The include capability this document evaluates under
76
76
  // (G5, docs/trust.md); vet's precedent.
77
77
  trust?: TrustOptions
78
+ // The extensions an include additionally reads as text (the CLI's
79
+ // --text-ext). It rides WITH the capability, never beside it: this
80
+ // verb threaded the capability and not the extension, so `set`
81
+ // refused an include -- and wrote nothing -- under a flag the bare
82
+ // command honoured.
83
+ textExt?: string[]
78
84
  }
79
85
 
80
86
 
@@ -578,6 +584,7 @@ export function patch(
578
584
  // the caller, "which file" is the whole question.
579
585
  const report: VetReport = vet(entrySrc, overlay, {
580
586
  trust: options.trust,
587
+ textExt: options.textExt,
581
588
  schemaPath: options.entryPath,
582
589
  dataPath: options.overlayPath,
583
590
  schemaUrl: options.entryPath,
package/src/query.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+ import { includeOpts } from './utility'
2
3
 
3
4
  // THE QUERY SURFACE (G7 phase 1,
4
5
  // docs/capability-review/g7-machine-access.md): select one node of an
@@ -56,6 +57,11 @@ export type QueryOptions = {
56
57
  // extension -- but reading is enough.) A server passes
57
58
  // `{include:'none'}`.
58
59
  trust?: TrustOptions
60
+
61
+ // Extensions additionally read as text (the CLI's `--text-ext`).
62
+ // Rides beside `trust` because it is the other half of what an
63
+ // include may read.
64
+ textExt?: string[]
59
65
  }
60
66
 
61
67
  export type QueryReport = {
@@ -271,8 +277,7 @@ export function get(
271
277
  const options = opts ?? {}
272
278
  const view: QueryView = options.view ?? 'json'
273
279
 
274
- const aontu = new Aontu(
275
- null == options.trust ? undefined : { trust: options.trust })
280
+ const aontu = new Aontu(includeOpts(options))
276
281
  const ctx = aontu.ctx({ collect: true })
277
282
  const parseOpts = null == options.path ? undefined : { path: options.path }
278
283
  const root: any = aontu.unify(src, parseOpts, ctx)
@@ -336,8 +341,7 @@ export type WhyReport = {
336
341
  export function why(
337
342
  src: string, path: string, opts?: QueryOptions): WhyReport {
338
343
  const options = opts ?? {}
339
- const aontu = new Aontu(
340
- null == options.trust ? undefined : { trust: options.trust })
344
+ const aontu = new Aontu(includeOpts(options))
341
345
  const prov = new Provenance()
342
346
  const ctx = aontu.ctx({ collect: true, prov })
343
347
  const parseOpts = null == options.path ? undefined : { path: options.path }
package/src/reach.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+ import { includeOpts } from './utility'
2
3
 
3
4
  // REACHABILITY OVER THE LINK GRAPH (the review's finding J,
4
5
  // use-cases/REVIEW.md): "ship a transitive `reaches(a, b)` check verb".
@@ -60,6 +61,11 @@ export type ReachOptions = {
60
61
  // The include capability this document evaluates under (G5,
61
62
  // docs/trust.md).
62
63
  trust?: TrustOptions
64
+
65
+ // Extensions additionally read as text (the CLI's `--text-ext`).
66
+ // Rides beside `trust` because it is the other half of what an
67
+ // include may read.
68
+ textExt?: string[]
63
69
  // Follow only edges under this relation. Absent means follow every
64
70
  // edge, which is the whole graph and the commoner question.
65
71
  relation?: string
@@ -124,8 +130,7 @@ export function reachCheck(
124
130
  src: string, from: string, to: string, opts?: ReachOptions
125
131
  ): ReachReport {
126
132
  const options = opts ?? {}
127
- const aontu = new Aontu(
128
- null == options.trust ? undefined : { trust: options.trust })
133
+ const aontu = new Aontu(includeOpts(options))
129
134
  const ctx = aontu.ctx({ collect: true })
130
135
  const parseOpts = null == options.path ? undefined : { path: options.path }
131
136
  const root: any = aontu.unify(src, parseOpts, ctx)
package/src/relation.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+ import { includeOpts } from './utility'
2
3
 
3
4
  // RELATION GRAPH VERDICTS (RELATIONS.0.md §3.3, replacing the G4
4
5
  // phase 5 magic-key pass): acyclicity and inverse consistency over
@@ -70,6 +71,11 @@ export type RelationOptions = {
70
71
  // docs/trust.md). vet's precedent: the verb passes the profile the
71
72
  // caller asked for, and an absent option means today's default.
72
73
  trust?: TrustOptions
74
+
75
+ // Extensions additionally read as text (the CLI's `--text-ext`).
76
+ // Rides beside `trust` because it is the other half of what an
77
+ // include may read.
78
+ textExt?: string[]
73
79
  }
74
80
 
75
81
 
@@ -248,8 +254,7 @@ export function relationErrors(ctx: any, root: any): void {
248
254
  export function relationCheck(
249
255
  src: string, opts?: RelationOptions): RelationReport {
250
256
  const options = opts ?? {}
251
- const aontu = new Aontu(
252
- null == options.trust ? undefined : { trust: options.trust })
257
+ const aontu = new Aontu(includeOpts(options))
253
258
  const ctx = aontu.ctx({ collect: true })
254
259
  const parseOpts = null == options.path ? undefined : { path: options.path }
255
260
  const root: any = aontu.unify(src, parseOpts, ctx)
package/src/sigdecl.ts CHANGED
@@ -6,6 +6,6 @@
6
6
  // this copy is identical with the shared file.
7
7
 
8
8
  const SIGDECL: string =
9
- "# The call surface: one declaration line per built-in function\n# (docs/design/SIGNATURES.0.md). THIS FILE IS THE SOURCE — both ports\n# carry a build-time-inlined copy (ts/src/sigdecl.ts, go/sigdecl.txt;\n# `make sig` regenerates both, and each port's suite asserts its copy\n# is byte-identical with this file) and parse it at initialisation\n# with the signature grammar, a tabnas grammar (ts/src/sig.ts,\n# go/sig.go). The suites also round-trip every line:\n# render(parse(line)) must be the line exactly, in both ports.\n#\n# The syntax (rendered TypeScript-ish, honest about argument MODES):\n# line = name '(' [ arg {',' arg} ] ')' ':' type\n# arg = [mode] name ['?'] ':' type\n# | '...' name ':' '(' [mode] type {',' [mode] type} ')'\n# type = word {'|' word}\n# mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'\n# `value` mode is unmarked. `constraint` is the result word for\n# residuals whose meet depends on the peer; `any` is the honest type\n# where a function is a wrapper.\nupper(s: string|number) : string\nlower(s: string|number) : string\ncopy(v: any) : any\npref(v: any) : any\nsuper(t: any) : any\ntype(t: any) : any\nhide(v: any) : any\nclose(m: any) : any\nopen(m: any) : any\nmove(v: any) : any\npath(capture p?: path) : path\nmap() : map\nlist() : list\nmin(n: number|string) : constraint\nmax(n: number|string) : constraint\nabove(n: number|string) : constraint\nbelow(n: number|string) : constraint\nre(text p: string) : constraint\nlength(n: number|constraint) : constraint\nkey(up?: integer|biginteger) : string\nunique(projector k?: string) : constraint\nneq(...vals: number|string) : constraint\nmust(trial c: any, text msg: string) : constraint\ndeprecate(v: any, r?: map) : any\nacyclic() : constraint\ninverse(projector k: string) : constraint\nrefer(template t?: any) : constraint\nrel(template t?: any) : constraint\npack(d: map|list, template t: any) : map\neach(d: map|list, template t?: any) : list\nfilter(d: map|list, trial c: any) : map|list\nmatch(s: any, ...pr: (trial any, any), dflt?: any) : any\nadd(a: number, b: number) : number\nsub(a: number, b: number) : number\nmul(a: number, b: number) : number\ndiv(a: number, b: number) : number\nmod(a: number, b: number) : number\nrem(a: number, b: number) : number\nsum(d: map|list) : number\nleast(d: map|list) : number\ngreatest(d: map|list) : number\npick(d: map|list, projector k: string|integer) : any\njoin(d: map|list, sep?: string) : string\n"
9
+ "# The call surface: one declaration line per built-in function\n# (docs/design/SIGNATURES.0.md). THIS FILE IS THE SOURCE — both ports\n# carry a build-time-inlined copy (ts/src/sigdecl.ts, go/sigdecl.txt;\n# `make sig` regenerates both, and each port's suite asserts its copy\n# is byte-identical with this file) and parse it at initialisation\n# with the signature grammar, a tabnas grammar (ts/src/sig.ts,\n# go/sig.go). The suites also round-trip every line:\n# render(parse(line)) must be the line exactly, in both ports.\n#\n# The syntax (rendered TypeScript-ish, honest about argument MODES):\n# line = name '(' [ arg {',' arg} ] ')' ':' type\n# arg = [mode] name ['?'] ':' type\n# | '...' name ':' '(' [mode] type {',' [mode] type} ')'\n# type = word {'|' word}\n# mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'\n# `value` mode is unmarked. `constraint` is the result word for\n# residuals whose meet depends on the peer; `any` is the honest type\n# where a function is a wrapper.\nupper(s: string|number) : string\nlower(s: string|number) : string\ncopy(v: any) : any\npref(v: any) : any\nsuper(t: any) : any\ntype(t: any) : any\nhide(v: any) : any\nclose(m: any) : any\nopen(m: any) : any\nmove(v: any) : any\npath(capture p?: path) : path\nmap() : map\nlist() : list\nmin(n: number|string) : constraint\nmax(n: number|string) : constraint\nabove(n: number|string) : constraint\nbelow(n: number|string) : constraint\nre(text p: string) : constraint\nlength(n: number|constraint) : constraint\nkey(up?: integer|biginteger) : string\nunique(projector k?: string) : constraint\nneq(...vals: number|string) : constraint\nmust(trial c: any, text msg: string) : constraint\ndeprecate(v: any, r?: map) : any\nacyclic() : constraint\ninverse(projector k: string) : constraint\nrefer(template t?: any) : constraint\nrel(template t?: any) : constraint\npack(d: map|list, template t: any) : map\neach(d: map|list, template t?: any) : list\nfilter(d: map|list, trial c: any) : map|list\nmatch(s: any, ...pr: (trial any, any), dflt?: any) : any\nadd(a: number, b: number) : number\nsub(a: number, b: number) : number\nmul(a: number, b: number) : number\ndiv(a: number, b: number) : number\nmod(a: number, b: number) : number\nrem(a: number, b: number) : number\nsum(d: map|list) : number\nleast(d: map|list) : number\ngreatest(d: map|list) : number\npick(d: map|list, projector k: string|integer) : any\njoin(d: map|list, sep?: string) : string\nesc(s: string, variant?: string) : string\nusc(s: string, variant?: string) : string\nrep(s: string, text p: string, text sub: string) : string\nsplit(s: string, sep: string|constraint) : list\nemit(s: map|list, template t: map|list) : list\n"
10
10
 
11
11
  export { SIGDECL }