functionalscript 0.46.0 → 0.47.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 (178) hide show
  1. package/fjs/basen/cbase32/module.f.mjs +18 -10
  2. package/fjs/basen/cbase32/proof.f.d.mts +3 -0
  3. package/fjs/basen/cbase32/proof.f.mjs +24 -2
  4. package/fjs/basen/proof.f.mjs +8 -16
  5. package/fjs/bnf/ll1/proof.f.d.mts +2 -0
  6. package/fjs/bnf/ll1/proof.f.mjs +33 -18
  7. package/fjs/bnf/module.f.d.mts +2 -2
  8. package/fjs/bnf/module.f.mjs +2 -2
  9. package/fjs/cas/proof.f.mjs +4 -26
  10. package/fjs/ci/common/module.f.mjs +6 -0
  11. package/fjs/ci/config/module.f.d.mts +7 -7
  12. package/fjs/ci/config/module.f.mjs +7 -7
  13. package/fjs/cli/module.f.mjs +14 -10
  14. package/fjs/crypto/vdf/module.f.d.mts +0 -1
  15. package/fjs/crypto/vdf/module.f.mjs +3 -14
  16. package/fjs/dev/module.f.mjs +10 -20
  17. package/fjs/djs/parser/module.f.d.mts +101 -53
  18. package/fjs/djs/parser/module.f.mjs +732 -525
  19. package/fjs/djs/parser/proof.f.d.mts +6 -0
  20. package/fjs/djs/parser/proof.f.mjs +315 -11
  21. package/fjs/djs/parser/types.d.ts +29 -2
  22. package/fjs/djs/tokenizer/module.f.mjs +122 -105
  23. package/fjs/djs/tokenizer/proof.f.mjs +17 -0
  24. package/fjs/djs/transpiler/module.f.mjs +4 -5
  25. package/fjs/djs/transpiler/proof.f.d.mts +2 -0
  26. package/fjs/djs/transpiler/proof.f.mjs +25 -0
  27. package/fjs/edag/amnesia/module.f.d.mts +20 -0
  28. package/fjs/edag/amnesia/module.f.mjs +303 -0
  29. package/fjs/edag/amnesia/proof.f.d.mts +79 -0
  30. package/fjs/edag/amnesia/proof.f.mjs +573 -0
  31. package/fjs/edag/amnesia/types.d.ts +15 -0
  32. package/fjs/edag/module.f.d.mts +410 -0
  33. package/fjs/edag/module.f.mjs +559 -0
  34. package/fjs/edag/proof.f.d.mts +116 -0
  35. package/fjs/edag/proof.f.mjs +686 -0
  36. package/fjs/edag/types.d.ts +55 -0
  37. package/fjs/effects/node/memory/module.d.mts +37 -3
  38. package/fjs/effects/node/memory/module.mjs +38 -4
  39. package/fjs/effects/node/memory/proof.d.mts +5 -2
  40. package/fjs/effects/node/memory/proof.mjs +36 -6
  41. package/fjs/effects/node/module.d.mts +9 -1
  42. package/fjs/effects/node/module.f.d.mts +39 -0
  43. package/fjs/effects/node/module.f.mjs +46 -0
  44. package/fjs/effects/node/module.mjs +234 -32
  45. package/fjs/effects/node/types.d.ts +28 -2
  46. package/fjs/effects/node/virtual/module.f.d.mts +19 -10
  47. package/fjs/effects/node/virtual/module.f.mjs +246 -32
  48. package/fjs/effects/node/virtual/proof.f.d.mts +17 -2
  49. package/fjs/effects/node/virtual/proof.f.mjs +232 -8
  50. package/fjs/effects/node/virtual/types.d.ts +57 -1
  51. package/fjs/emergent_testing/browser/proof.d.mts +55 -0
  52. package/fjs/emergent_testing/browser/proof.mjs +352 -0
  53. package/fjs/emergent_testing/browser/species.proof.d.mts +4 -0
  54. package/fjs/emergent_testing/browser/species.proof.mjs +45 -0
  55. package/fjs/emergent_testing/browser.d.mts +79 -0
  56. package/fjs/emergent_testing/browser.mjs +432 -0
  57. package/fjs/emergent_testing/proof.f.d.mts +1 -1
  58. package/fjs/emergent_testing/proof.f.mjs +2 -2
  59. package/fjs/js/string_escape/module.f.d.mts +47 -0
  60. package/fjs/js/string_escape/module.f.mjs +95 -0
  61. package/fjs/js/string_escape/proof.f.d.mts +8 -0
  62. package/fjs/js/string_escape/proof.f.mjs +68 -0
  63. package/fjs/js/tokenizer/module.f.mjs +14 -12
  64. package/fjs/mcp/cas/module.f.d.mts +1 -7
  65. package/fjs/mcp/cas/module.f.mjs +24 -15
  66. package/fjs/mcp/evo/module.f.mjs +9 -24
  67. package/fjs/mcp/module.f.d.mts +3 -1
  68. package/fjs/mcp/module.f.mjs +4 -2
  69. package/fjs/media/json/rtti/module.f.d.mts +2 -2
  70. package/fjs/media/json/rtti/module.f.mjs +1 -1
  71. package/fjs/media/json/schema/module.f.d.mts +15 -5
  72. package/fjs/media/json/schema/module.f.mjs +42 -15
  73. package/fjs/media/json/schema/proof.f.d.mts +10 -1
  74. package/fjs/media/json/schema/proof.f.mjs +88 -16
  75. package/fjs/media/json/serializer/module.f.mjs +14 -26
  76. package/fjs/media/json/types.d.ts +1 -1
  77. package/fjs/media/lock/module.f.d.mts +8 -3
  78. package/fjs/media/lock/module.f.mjs +9 -3
  79. package/fjs/media/lock/proof.f.d.mts +1 -1
  80. package/fjs/media/lock/proof.f.mjs +2 -2
  81. package/fjs/media/lock/types.d.ts +1 -3
  82. package/fjs/media/module.f.d.mts +20 -13
  83. package/fjs/media/module.f.mjs +29 -16
  84. package/fjs/media/note/module.f.d.mts +14 -7
  85. package/fjs/media/note/module.f.mjs +14 -7
  86. package/fjs/media/note/proof.f.mjs +1 -1
  87. package/fjs/media/proof.f.mjs +5 -5
  88. package/fjs/media/revision/module.f.d.mts +8 -2
  89. package/fjs/media/revision/module.f.mjs +9 -3
  90. package/fjs/media/revision/proof.f.mjs +1 -1
  91. package/fjs/media/revision/types.d.ts +1 -1
  92. package/fjs/media/type/module.f.d.mts +20 -0
  93. package/fjs/media/type/module.f.mjs +74 -0
  94. package/fjs/media/type/proof.f.d.mts +5 -0
  95. package/fjs/media/type/proof.f.mjs +24 -1
  96. package/fjs/module.f.mjs +6 -0
  97. package/fjs/path/module.f.d.mts +60 -3
  98. package/fjs/path/module.f.mjs +138 -14
  99. package/fjs/path/proof.f.d.mts +3 -0
  100. package/fjs/path/proof.f.mjs +298 -2
  101. package/fjs/protocol/json_rpc/module.f.d.mts +65 -28
  102. package/fjs/protocol/json_rpc/module.f.mjs +49 -13
  103. package/fjs/protocol/json_rpc/proof.f.d.mts +4 -0
  104. package/fjs/protocol/json_rpc/proof.f.mjs +29 -0
  105. package/fjs/protocol/json_rpc/types.d.ts +12 -2
  106. package/fjs/protocol/mcp/module.f.d.mts +89 -54
  107. package/fjs/protocol/mcp/module.f.mjs +110 -56
  108. package/fjs/protocol/mcp/proof.f.d.mts +13 -0
  109. package/fjs/protocol/mcp/proof.f.mjs +107 -7
  110. package/fjs/protocol/mcp/stdio/module.f.mjs +3 -4
  111. package/fjs/protocol/mcp/stdio/proof.f.mjs +2 -2
  112. package/fjs/protocol/mcp/types.d.ts +14 -2
  113. package/fjs/text/utf8/module.f.mjs +27 -1
  114. package/fjs/text/utf8/proof.f.mjs +37 -0
  115. package/fjs/types/array/module.f.mjs +18 -11
  116. package/fjs/types/array/proof.f.mjs +27 -1
  117. package/fjs/types/bigfloat/module.f.d.mts +48 -9
  118. package/fjs/types/bigfloat/module.f.mjs +147 -59
  119. package/fjs/types/bigfloat/proof.f.d.mts +2 -0
  120. package/fjs/types/bigfloat/proof.f.mjs +136 -4
  121. package/fjs/types/bigfloat/types.d.ts +17 -0
  122. package/fjs/types/function/module.f.d.mts +11 -2
  123. package/fjs/types/function/module.f.mjs +20 -2
  124. package/fjs/types/function/proof.f.mjs +5 -1
  125. package/fjs/types/phantom/types.d.ts +21 -0
  126. package/fjs/types/result/module.f.d.mts +4 -4
  127. package/fjs/types/result/module.f.mjs +2 -2
  128. package/fjs/types/result/proof.f.d.mts +6 -2
  129. package/fjs/types/result/proof.f.mjs +17 -1
  130. package/fjs/types/rtti/common/module.f.d.mts +78 -5
  131. package/fjs/types/rtti/common/module.f.mjs +168 -3
  132. package/fjs/types/rtti/common/proof.f.d.mts +14 -0
  133. package/fjs/types/rtti/common/proof.f.mjs +61 -2
  134. package/fjs/types/rtti/common/types.d.ts +23 -1
  135. package/fjs/types/rtti/data/module.f.d.mts +57 -1
  136. package/fjs/types/rtti/data/module.f.mjs +241 -47
  137. package/fjs/types/rtti/data/proof.f.d.mts +10 -0
  138. package/fjs/types/rtti/data/proof.f.mjs +272 -39
  139. package/fjs/types/rtti/data/types.d.ts +14 -7
  140. package/fjs/types/rtti/host.proof.d.mts +33 -0
  141. package/fjs/types/rtti/host.proof.mjs +170 -0
  142. package/fjs/types/rtti/module.f.d.mts +51 -6
  143. package/fjs/types/rtti/module.f.mjs +50 -3
  144. package/fjs/types/rtti/parse/module.f.d.mts +31 -24
  145. package/fjs/types/rtti/parse/module.f.mjs +197 -59
  146. package/fjs/types/rtti/parse/proof.f.d.mts +37 -2
  147. package/fjs/types/rtti/parse/proof.f.mjs +171 -47
  148. package/fjs/types/rtti/proof.f.d.mts +6 -0
  149. package/fjs/types/rtti/proof.f.mjs +42 -1
  150. package/fjs/types/rtti/ts/module.f.d.mts +9 -3
  151. package/fjs/types/rtti/ts/module.f.mjs +68 -15
  152. package/fjs/types/rtti/ts/proof.f.d.mts +42 -2
  153. package/fjs/types/rtti/ts/proof.f.mjs +139 -6
  154. package/fjs/types/rtti/ts/types.d.ts +164 -16
  155. package/fjs/types/rtti/types.d.ts +31 -3
  156. package/fjs/types/rtti/validate/module.f.d.mts +120 -0
  157. package/fjs/types/rtti/validate/module.f.mjs +351 -0
  158. package/fjs/types/rtti/validate/proof.f.d.mts +154 -0
  159. package/fjs/types/rtti/validate/proof.f.mjs +781 -0
  160. package/fjs/types/ts/types.d.ts +4 -0
  161. package/fjs/web/module.f.d.mts +115 -0
  162. package/fjs/web/module.f.mjs +581 -0
  163. package/fjs/web/proof.f.d.mts +39 -0
  164. package/fjs/web/proof.f.mjs +413 -0
  165. package/fjs/web/types.d.ts +39 -0
  166. package/fjs/website/browser-prepare.d.mts +5 -0
  167. package/fjs/website/browser-prepare.mjs +115 -0
  168. package/fjs/website/browser-source.d.mts +37 -0
  169. package/fjs/website/browser-source.mjs +202 -0
  170. package/fjs/website/browser-source.proof.d.mts +31 -0
  171. package/fjs/website/browser-source.proof.mjs +162 -0
  172. package/fjs/website/browser.d.mts +5 -0
  173. package/fjs/website/browser.mjs +8 -0
  174. package/fjs/website/module.f.d.mts +3 -3
  175. package/fjs/website/module.f.mjs +62 -9
  176. package/fjs/website/proof.f.d.mts +4 -0
  177. package/fjs/website/proof.f.mjs +18 -3
  178. package/package.json +2 -3
@@ -0,0 +1,68 @@
1
+ import { assertEq, assertStructurallySame } from '../../asserts/module.f.mjs'
2
+ import {
3
+ backspace,
4
+ cr,
5
+ ff,
6
+ ht,
7
+ latinSmallLetterB,
8
+ latinSmallLetterF,
9
+ latinSmallLetterN,
10
+ latinSmallLetterR,
11
+ latinSmallLetterT,
12
+ latinSmallLetterU,
13
+ lf,
14
+ quotationMark,
15
+ reverseSolidus,
16
+ solidus,
17
+ } from '../../text/ascii/module.f.mjs'
18
+ import {
19
+ codePointToEscape,
20
+ escapeToCodePoint,
21
+ optionalEscape,
22
+ simpleEscapes,
23
+ } from './module.f.mjs'
24
+
25
+ /**
26
+ * The escapes spelled out independently of the table, so the proof compares
27
+ * two statements of the set rather than the table against itself.
28
+ *
29
+ * @type {readonly (readonly [number, number])[]}
30
+ */
31
+ const expected = [
32
+ [quotationMark, quotationMark],
33
+ [reverseSolidus, reverseSolidus],
34
+ [solidus, solidus],
35
+ [latinSmallLetterB, backspace],
36
+ [latinSmallLetterF, ff],
37
+ [latinSmallLetterN, lf],
38
+ [latinSmallLetterR, cr],
39
+ [latinSmallLetterT, ht],
40
+ ]
41
+
42
+ export const proof = {
43
+ simpleEscapes: () => assertStructurallySame(simpleEscapes, expected),
44
+ // Every letter decodes to its code point, and — apart from the optional
45
+ // one — every code point encodes back to its letter. Round-tripping both
46
+ // ways is what the two derived views are for.
47
+ roundTrip: () => expected.forEach(([letter, codePoint]) => {
48
+ assertEq(escapeToCodePoint(letter), codePoint, letter)
49
+ assertEq(codePointToEscape(codePoint), codePoint === optionalEscape ? null : letter, codePoint)
50
+ }),
51
+ // `\/` is accepted and never produced: the one asymmetry between the views.
52
+ optionalEscape: [
53
+ () => assertEq(escapeToCodePoint(optionalEscape), solidus),
54
+ () => assertEq(codePointToEscape(optionalEscape), null),
55
+ ],
56
+ // `u` is a letter the grammar accepts after a backslash, but its meaning
57
+ // comes from the digits that follow, so it is deliberately absent here.
58
+ unicodeEscapeIsNotSimple: () => assertEq(escapeToCodePoint(latinSmallLetterU), null),
59
+ // A code point with no simple escape, from either side.
60
+ noEscape: [
61
+ () => assertEq(escapeToCodePoint(0x61), null), // `a`
62
+ () => assertEq(codePointToEscape(0x61), null),
63
+ () => assertEq(codePointToEscape(0x00), null), // NUL: a control, but no short form
64
+ ],
65
+ // The letters are distinct — a repeated letter would silently shadow an
66
+ // entry in the decode view, and the table is small enough to say so.
67
+ lettersAreDistinct: () => assertEq(new Set(simpleEscapes.map(([letter]) => letter)).size, simpleEscapes.length),
68
+ }
@@ -22,15 +22,14 @@ import { strictEqual } from '../../types/function/operator/module.f.mjs'
22
22
  import { merge, fromRange, get } from '../../types/range_map/module.f.mjs'
23
23
  import { empty, stateScan, flat, toArray, reduce as listReduce, scan, map as listMap } from '../../types/list/module.f.mjs'
24
24
  import { keywords } from '../keywords/module.f.mjs'
25
+ import { simpleEscapes } from '../string_escape/module.f.mjs'
25
26
  import { at, fromEntries } from '../../types/ordered_map/module.f.mjs'
26
27
  import { one } from '../../types/range/module.f.mjs'
27
28
  import {
28
29
  range,
29
30
  //
30
- backspace,
31
31
  ht,
32
32
  lf,
33
- ff,
34
33
  cr,
35
34
  //
36
35
  exclamationMark,
@@ -70,12 +69,8 @@ import {
70
69
  lowLine,
71
70
  //
72
71
  latinSmallLetterRange,
73
- latinSmallLetterB,
74
72
  latinSmallLetterE,
75
- latinSmallLetterF,
76
73
  latinSmallLetterN,
77
- latinSmallLetterR,
78
- latinSmallLetterT,
79
74
  latinSmallLetterU,
80
75
  //
81
76
  leftCurlyBracket,
@@ -501,14 +496,21 @@ const parseEscapeDefault = state => input => {
501
496
  return [{ first: { kind: 'error', message: 'unescaped character' }, tail: next[0] }, next[1]]
502
497
  }
503
498
 
499
+ /**
500
+ * One dispatch entry per simple escape, appending the code point the letter
501
+ * denotes. The three self-denoting escapes are not special-cased: `\"` appends
502
+ * `"` because that is what the table pairs it with.
503
+ *
504
+ * @type {readonly _RangeFunc<_ParseEscapeCharState>[]}
505
+ */
506
+ const simpleEscapeFuncs = simpleEscapes.map(([letter, codePoint]) =>
507
+ rangeFunc(one(letter))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(codePoint) }]))
508
+
504
509
  /** @type {(state: _ParseEscapeCharState) => (input: number) => readonly [List<JsToken>, _TokenizerState]} */
505
510
  const parseEscapeCharStateOp = create(parseEscapeDefault)([
506
- rangeSetFunc([one(quotationMark), one(reverseSolidus), one(solidus)])(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }]),
507
- rangeFunc(one(latinSmallLetterB))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(backspace) }]),
508
- rangeFunc(one(latinSmallLetterF))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(ff) }]),
509
- rangeFunc(one(latinSmallLetterN))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(lf) }]),
510
- rangeFunc(one(latinSmallLetterR))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(cr) }]),
511
- rangeFunc(one(latinSmallLetterT))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(ht) }]),
511
+ ...simpleEscapeFuncs,
512
+ // `\u` is the one escape whose meaning is not a lookup: the four hex
513
+ // digits that follow decide it, so it starts a state instead.
512
514
  rangeFunc(one(latinSmallLetterU))(state => () => [empty, { kind: 'unicodeChar', value: state.value, unicode: 0, hexIndex: 0 }]),
513
515
  ])
514
516
 
@@ -116,7 +116,7 @@ import type { Key } from '../../effects/memory/types.ts';
116
116
  /** Arguments for `cas_add`: content to store, with optional encoding type. */
117
117
  export declare const casAddArgs: {
118
118
  readonly content: import("../../types/rtti/types.ts")._Type0<"string">;
119
- readonly type: import("../../types/rtti/types.ts").Or<["text", "base64", undefined]>;
119
+ readonly type: import("../../types/rtti/types.ts").Or<readonly ["text", "base64", undefined]>;
120
120
  };
121
121
  /** Arguments for `cas_get`: the cBase32 hash to look up; optionally request inline content. */
122
122
  export declare const casGetArgs: {
@@ -131,12 +131,6 @@ export type _Meta = {
131
131
  readonly type: 'text' | 'base64';
132
132
  readonly uri: string;
133
133
  };
134
- /** @typedef {{
135
- * readonly length: number
136
- * readonly mimeType: string
137
- * readonly type: 'text' | 'base64'
138
- * readonly uri: string
139
- * }} _Meta */
140
134
  /**
141
135
  * Registry of all CAS tools, bound to `home` and the Evo cache at
142
136
  * `cacheKey`. `cas_add` is the only tool that writes, so it is the only one
@@ -123,7 +123,7 @@ import { noteDialect } from '../../media/note/module.f.mjs'
123
123
  import { maxLengthBytes } from '../../types/bit_vec/module.f.mjs'
124
124
  import { ok } from '../../types/result/module.f.mjs'
125
125
  import {
126
- toolEntry, errorResult, okResult,
126
+ toolEntry, errorResult, okResult, toolResultStep,
127
127
  } from '../../protocol/mcp/module.f.mjs'
128
128
  import { collectRead, fileCas } from '../../cas/module.f.mjs'
129
129
  import { errorSummary } from '../../effects/node/module.f.mjs'
@@ -135,11 +135,15 @@ import { syncRevision } from '../../cas/evo/module.f.mjs'
135
135
  import { assertNotNullish } from '../../asserts/module.f.mjs'
136
136
 
137
137
  // ── Argument schemas (declared once, used for both inputSchema and validate) ─────
138
+ //
139
+ // Closed, as the bare form says: a tool's argument list is a vocabulary this
140
+ // server defines rather than a format a client extends, and the JSON Schema
141
+ // derived from these now advertises exactly what the validator enforces.
138
142
 
139
143
  /** Arguments for `cas_add`: content to store, with optional encoding type. */
140
144
  export const casAddArgs = /** @type {const} */ ({
141
145
  content: string,
142
- type: or(/** @type {const} */ ('text'), /** @type {const} */ ('base64'), undefined)
146
+ type: or('text', 'base64', undefined)
143
147
  })
144
148
 
145
149
  /** Arguments for `cas_get`: the cBase32 hash to look up; optionally request inline content. */
@@ -170,6 +174,14 @@ const detectDialect = detect([revisionDialect, lockDialect, noteDialect])
170
174
  * readonly uri: string
171
175
  * }} _Meta */
172
176
 
177
+ /**
178
+ * Maps a media-type detector verdict to the `cas_get` wire metadata.
179
+ *
180
+ * @type {(uri: string) => (detected: { readonly length: bigint, readonly mime_type: string, readonly type: 'text' | 'base64' }) => _Meta}
181
+ */
182
+ const toMeta = uri => ({ length, mime_type: mimeType, type }) =>
183
+ ({ length: Number(length), mimeType, type, uri })
184
+
173
185
  /**
174
186
  * Registry of all CAS tools, bound to `home` and the Evo cache at
175
187
  * `cacheKey`. `cas_add` is the only tool that writes, so it is the only one
@@ -220,21 +232,21 @@ export const casToolRegistry = home => cacheKey => {
220
232
  return pureOk(errorResult(`invalid cBase32 hash: ${r.hash}`))
221
233
  }
222
234
  const uri = c.url(key)
235
+ const meta = toMeta(uri)
223
236
  return resultStep(
224
237
  detectStream(c.read(key)),
225
238
  ([tag, detected]) => {
226
239
  if (tag === 'error') {
227
240
  return pureOk(errorResult(`no such hash: ${r.hash}`))
228
241
  }
229
- const { length, mime_type: mimeType, type } = detected
230
- /** @type {_Meta} */
231
- const meta = { length: Number(length), mimeType, type, uri }
242
+ const { length, type } = detected
243
+ const detectedMeta = meta(detected)
232
244
  if (r.content !== true) {
233
245
  // A dialect match can only be decided from the whole parsed blob;
234
246
  // only attempt the extra bounded read when it stands a chance
235
247
  // (whole-blob text within the same cap `content: true` allows).
236
248
  if (type !== 'text' || length > maxLengthBytes) {
237
- return pureOk(okResult(toJson(meta)))
249
+ return pureOk(okResult(toJson(detectedMeta)))
238
250
  }
239
251
  return resultStep(
240
252
  collectRead(c.read(key)),
@@ -242,9 +254,9 @@ export const casToolRegistry = home => cacheKey => {
242
254
  // Already known to fit from the streaming pass above, so an
243
255
  // error here means the hash vanished between reads; fall back
244
256
  // to the streaming verdict rather than fail the whole request.
245
- if (collectTag === 'error') { return pureOk(okResult(toJson(meta))) }
257
+ if (collectTag === 'error') { return pureOk(okResult(toJson(detectedMeta))) }
246
258
  const refined = detectDialect(value)
247
- return pureOk(okResult(toJson({ ...meta, mimeType: refined.mime_type })))
259
+ return pureOk(okResult(toJson(meta(refined))))
248
260
  }
249
261
  )
250
262
  }
@@ -267,8 +279,7 @@ export const casToolRegistry = home => cacheKey => {
267
279
  // hand — is reflected in the inline result too, not just the
268
280
  // streaming guess.
269
281
  const refined = detectDialect(value)
270
- /** @type {_Meta} */
271
- const refinedMeta = { length: Number(refined.length), mimeType: refined.mime_type, type: refined.type, uri }
282
+ const refinedMeta = meta(refined)
272
283
  if (refined.type === 'text') {
273
284
  // `type: 'text'` means the detector validated `value` as
274
285
  // whole-blob UTF-8 with a byte-aligned length (see
@@ -295,12 +306,10 @@ export const casToolRegistry = home => cacheKey => {
295
306
  'cas_list',
296
307
  'List all stored content hashes (cBase32), one per line.',
297
308
  casListArgs,
298
- () => resultStep(
309
+ () => toolResultStep(
299
310
  c.list(),
300
- r => pureOk(r[0] === 'error'
301
- ? errorResult(errorSummary(r[1]))
302
- : okResult(r[1].map(vecToCBase32).join('\n')))
303
- ),
311
+ hs => hs.map(vecToCBase32).join('\n'),
312
+ errorSummary),
304
313
  ),
305
314
  ]
306
315
  }
@@ -51,15 +51,16 @@
51
51
 
52
52
  import { string, option, array } from '../../types/rtti/module.f.mjs'
53
53
  import { lockField } from '../../media/revision/module.f.mjs'
54
- import { pureOk, resultStep } from '../../effects/module.f.mjs'
55
54
  import { evoSummary } from '../../cas/evo/module.f.mjs'
56
- import {
57
- toolEntry, errorResult, okResult,
58
- } from '../../protocol/mcp/module.f.mjs'
55
+ import { toolEntry, toolResultStep } from '../../protocol/mcp/module.f.mjs'
59
56
  import { stringify } from '../../media/json/module.f.mjs'
60
57
  import { identity } from '../../types/function/module.f.mjs'
61
58
 
62
59
  // ── Argument schemas (declared once, used for both inputSchema and validate) ─────
60
+ //
61
+ // Closed, as the bare form says, for the reason `../cas/module.f.mjs` gives:
62
+ // a tool's argument list is a vocabulary this server defines rather than a
63
+ // format a client extends.
63
64
 
64
65
  /**
65
66
  * Arguments for `evo_list`: an optional status filter, forwarded unchanged to
@@ -125,23 +126,13 @@ export const evoToolRegistry = e => [
125
126
  // A cache slot the runner cannot reach is a tool-level error, not a
126
127
  // panic: the client asked a question the server could not answer, and
127
128
  // saying so is an ordinary `isError` result.
128
- (({ archived }) => resultStep(
129
- e.list(archived),
130
- r => pureOk(r[0] === 'error'
131
- ? errorResult(evoSummary(r[1]))
132
- : okResult(toJson(r[1])))
133
- )),
129
+ ({ archived }) => toolResultStep(e.list(archived), toJson, evoSummary),
134
130
  ),
135
131
  toolEntry(
136
132
  'evo_head',
137
133
  'List the current head hashes (cBase32) of a subject, one per line. Empty when the subject is unknown.',
138
134
  evoHeadArgs,
139
- ({ subject }) => resultStep(
140
- e.head(subject),
141
- r => pureOk(r[0] === 'error'
142
- ? errorResult(evoSummary(r[1]))
143
- : okResult(r[1].join('\n'))),
144
- ),
135
+ ({ subject }) => toolResultStep(e.head(subject), hs => hs.join('\n'), evoSummary),
145
136
  ),
146
137
  toolEntry(
147
138
  'evo_revision',
@@ -152,10 +143,7 @@ export const evoToolRegistry = e => [
152
143
  // the transport's `-32603`, not a tool-level error — see "Result size"
153
144
  // in the module doc.
154
145
 
155
- (({ hash }) => resultStep(
156
- e.revision(hash),
157
- r => pureOk(r[0] === 'error' ? errorResult(evoSummary(r[1])) : okResult(toJson(r[1])))
158
- )),
146
+ ({ hash }) => toolResultStep(e.revision(hash), toJson, evoSummary),
159
147
  ),
160
148
  toolEntry(
161
149
  'evo_add',
@@ -166,9 +154,6 @@ export const evoToolRegistry = e => [
166
154
  // it can read. They stay distinguishable by tag — `evoSummary` is the
167
155
  // renderer that switches on it — so telling them apart never needed
168
156
  // them to arrive in separate layers.
169
- input => resultStep(
170
- e.add(input),
171
- r => pureOk(r[0] === 'error' ? errorResult(evoSummary(r[1])) : okResult(r[1]))
172
- ),
157
+ input => toolResultStep(e.add(input), identity, evoSummary),
173
158
  ),
174
159
  ]
@@ -50,7 +50,9 @@ import type { Key } from '../effects/memory/types.ts';
50
50
  export declare const casMcpHandlers: (home: string) => (cacheKey: Key<Cache>) => McpHandlers<FileCasOperation | MemOp>;
51
51
  /**
52
52
  * Static MCP configuration for the CAS server: advertises the `tools`
53
- * capability, identifies the server, and pins the protocol version.
53
+ * capability, identifies the server, and lists the protocol revisions it
54
+ * speaks — one, so every client is answered with `2024-11-05`, whether that is
55
+ * an echo or a counter-proposal.
54
56
  * @type {McpConfig}
55
57
  */
56
58
  export declare const casConfig: McpConfig;
@@ -62,13 +62,15 @@ export const casMcpHandlers = home => cacheKey =>
62
62
 
63
63
  /**
64
64
  * Static MCP configuration for the CAS server: advertises the `tools`
65
- * capability, identifies the server, and pins the protocol version.
65
+ * capability, identifies the server, and lists the protocol revisions it
66
+ * speaks — one, so every client is answered with `2024-11-05`, whether that is
67
+ * an echo or a counter-proposal.
66
68
  * @type {McpConfig}
67
69
  */
68
70
  export const casConfig = {
69
71
  serverInfo: { name: 'functionalscript-cas', version: '0.30.0' },
70
72
  capabilities: { tools: {} },
71
- protocolVersion: '2024-11-05',
73
+ protocolVersions: ['2024-11-05'],
72
74
  }
73
75
 
74
76
  // ── Server ──────────────────────────────────────────────────────────────────────
@@ -12,12 +12,12 @@
12
12
  *
13
13
  * The TypeScript counterparts live in the sibling
14
14
  * [`../types.ts`](../types.ts), which pins them against these schemas with
15
- * `Assert<Equal<Unknown, Ts<typeof unknown>>>`.
15
+ * `Assert<Check<Unknown, typeof unknown>>`.
16
16
  *
17
17
  * @module
18
18
  */
19
19
  /** rtti schema matching any JSON primitive: `null`, `boolean`, `number`, or `string`. */
20
- export declare const primitive: import("../../../types/rtti/types.ts").Or<[null, import("../../../types/rtti/types.ts")._Type0<"boolean">, import("../../../types/rtti/types.ts")._Type0<"number">, import("../../../types/rtti/types.ts")._Type0<"string">]>;
20
+ export declare const primitive: import("../../../types/rtti/types.ts").Or<readonly [null, import("../../../types/rtti/types.ts")._Type0<"boolean">, import("../../../types/rtti/types.ts")._Type0<"number">, import("../../../types/rtti/types.ts")._Type0<"string">]>;
21
21
  /**
22
22
  * rtti schema matching any JSON value: a primitive, an array of JSON values,
23
23
  * or an object whose values are JSON values. Self-referential via a thunk;
@@ -12,7 +12,7 @@
12
12
  *
13
13
  * The TypeScript counterparts live in the sibling
14
14
  * [`../types.ts`](../types.ts), which pins them against these schemas with
15
- * `Assert<Equal<Unknown, Ts<typeof unknown>>>`.
15
+ * `Assert<Check<Unknown, typeof unknown>>`.
16
16
  *
17
17
  * @module
18
18
  */
@@ -19,13 +19,15 @@
19
19
  *
20
20
  * @import { Type as RttiType } from '../../../types/rtti/types.ts'
21
21
  * @import { ArraySet, Data, KindSet, Node, ObjectSet, RuleSet, UnionSet } from '../../../types/rtti/data/types.ts'
22
- * @import { Ts } from '../../../types/rtti/ts/types.ts'
22
+ * @import { Ts, Check } from '../../../types/rtti/ts/types.ts'
23
23
  * @import { Phantom } from '../../../types/phantom/types.ts'
24
+ * @import { Assert } from '../../../asserts/types.ts'
24
25
  */
25
26
  import type { Type as RttiType } from '../../../types/rtti/types.ts';
26
27
  import type { Data } from '../../../types/rtti/data/types.ts';
27
- import type { Ts } from '../../../types/rtti/ts/types.ts';
28
+ import type { Ts, Check } from '../../../types/rtti/ts/types.ts';
28
29
  import type { Phantom } from '../../../types/phantom/types.ts';
30
+ import type { Assert } from '../../../asserts/types.ts';
29
31
  /** @type {() => readonly ['const', typeof unknownConst]} */
30
32
  declare const unknownThunk: () => readonly ['const', typeof unknownConst];
31
33
  /**
@@ -33,18 +35,26 @@ declare const unknownThunk: () => readonly ['const', typeof unknownConst];
33
35
  * @type {Phantom<typeof unknownThunk, _UnknownConst>}
34
36
  */
35
37
  export declare const unknown: Phantom<typeof unknownThunk, _UnknownConst>;
38
+ export type _UnknownCheck0 = Assert<Check<_UnknownConst, typeof unknownThunk>>;
39
+ export type _UnknownCheck1 = Assert<Check<_UnknownConst, typeof unknown>>;
36
40
  export type Unknown = Ts<typeof unknown>;
41
+ /**
42
+ * Checked against the un-annotated thunk, so a wrong `_UnknownConst` above
43
+ * would be caught here instead of silently trusted via the `Phantom` lie.
44
+ * @typedef {Assert<Check<_UnknownConst, typeof unknownThunk>>} _UnknownCheck0
45
+ */
46
+ /** @typedef {Assert<Check<_UnknownConst, typeof unknown>>} _UnknownCheck1 */
37
47
  /** A JSON Schema (draft 2020-12) document — the subset of keywords that `toJsonSchema` emits. */
38
48
  /** @typedef {Ts<typeof unknown>} Unknown */
39
49
  declare const unknownConst: {
40
50
  readonly $schema: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts")._Type0<"string">, undefined]>;
41
51
  readonly $ref: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts")._Type0<"string">, undefined]>;
42
52
  readonly $defs: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts").Type1<"record", Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>>, undefined]>;
43
- readonly type: import("../../../types/rtti/types.ts").Or<["boolean", "number", "string", "integer", "array", "object", undefined]>;
53
+ readonly type: import("../../../types/rtti/types.ts").Or<readonly ["boolean", "number", "string", "integer", "array", "object", undefined]>;
44
54
  readonly const: import("../../../types/rtti/types.ts").Or<readonly [() => readonly ['or', typeof import("../rtti/module.f.mjs").primitive, typeof import("../rtti/module.f.mjs").object, typeof import("../rtti/module.f.mjs").array], undefined]>;
45
55
  readonly not: import("../../../types/rtti/types.ts").Or<readonly [Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>, undefined]>;
46
56
  readonly anyOf: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts").Type1<"array", Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>>, undefined]>;
47
- readonly items: import("../../../types/rtti/types.ts").Or<[Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>, false, undefined]>;
57
+ readonly items: import("../../../types/rtti/types.ts").Or<readonly [Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>, false, undefined]>;
48
58
  readonly prefixItems: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts").Type1<"array", Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>>, undefined]>;
49
59
  readonly minItems: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts")._Type0<"number">, undefined]>;
50
60
  readonly properties: import("../../../types/rtti/types.ts").Or<readonly [import("../../../types/rtti/types.ts").Type1<"record", Phantom<() => readonly ['const', typeof unknownConst], _UnknownConst>>, undefined]>;
@@ -95,7 +105,7 @@ export declare const dataToJsonSchema: (data: Data) => Unknown;
95
105
  * | `bigint` const | `{ "const": Number(value) }` (lossy for \|value\| > MAX_SAFE_INTEGER) |
96
106
  * | `undefined` const | `{ "not": {} }` |
97
107
  * | struct `{ a: T, … }` | `{ "type": "object", "properties": { "a": …T… }, "required": [non-optional keys] }` |
98
- * | tuple `[A, B]` | `{ "type": "array", "prefixItems": […A…, …B…], "minItems": 2, "items": false }` |
108
+ * | tuple `[A, B]` | `{ "type": "array", "prefixItems": […A…, …B…], "minItems": 2, "items": {} }` |
99
109
  * | `array(T)` | `{ "type": "array", "items": …T… }` |
100
110
  * | `record(T)` | `{ "type": "object", "additionalProperties": …T… }` |
101
111
  * | `or(...types)` | `{ "anyOf": […each…] }`, normalized and in canonical kind order |
@@ -19,8 +19,9 @@
19
19
  *
20
20
  * @import { Type as RttiType } from '../../../types/rtti/types.ts'
21
21
  * @import { ArraySet, Data, KindSet, Node, ObjectSet, RuleSet, UnionSet } from '../../../types/rtti/data/types.ts'
22
- * @import { Ts } from '../../../types/rtti/ts/types.ts'
22
+ * @import { Ts, Check } from '../../../types/rtti/ts/types.ts'
23
23
  * @import { Phantom } from '../../../types/phantom/types.ts'
24
+ * @import { Assert } from '../../../asserts/types.ts'
24
25
  */
25
26
 
26
27
  import { assert, assertNotNullish } from '../../../asserts/module.f.mjs'
@@ -38,6 +39,13 @@ const unknownThunk = () => ['const', unknownConst]
38
39
  */
39
40
  export const unknown = unknownThunk
40
41
 
42
+ /**
43
+ * Checked against the un-annotated thunk, so a wrong `_UnknownConst` above
44
+ * would be caught here instead of silently trusted via the `Phantom` lie.
45
+ * @typedef {Assert<Check<_UnknownConst, typeof unknownThunk>>} _UnknownCheck0
46
+ */
47
+ /** @typedef {Assert<Check<_UnknownConst, typeof unknown>>} _UnknownCheck1 */
48
+
41
49
  /** A JSON Schema (draft 2020-12) document — the subset of keywords that `toJsonSchema` emits. */
42
50
  /** @typedef {Ts<typeof unknown>} Unknown */
43
51
 
@@ -165,22 +173,41 @@ const unitSchemas = bits => [
165
173
  ]
166
174
 
167
175
  /**
168
- * A set of arrays: `prefixItems` for the tuple prefix, `items` for the
169
- * elements past it `false` when the length is exact, so a tuple admits
170
- * nothing beyond its prefix and the empty tuple is `{ "items": false }`.
171
- * `prefixItems` alone constrains only elements that exist (draft 2020-12
172
- * implies no minimum length), so a non-empty prefix also emits `minItems`.
176
+ * The length below which the array would leave a declared position that
177
+ * excludes `undefined` unfilled: one past the last such position, and zero
178
+ * when every position admits absence. The array counterpart of the `required`
179
+ * key list an absent element reads as `undefined` just as an absent key
180
+ * does and, arrays being contiguous, one number says it for every position.
181
+ *
182
+ * @type {(rules: RuleSet) => (prefix: readonly Node[]) => number}
183
+ */
184
+ const minLength = rules => prefix =>
185
+ prefix.findLastIndex(n => !admitsUndefined(rules)(n)) + 1
186
+
187
+ /**
188
+ * A set of arrays: `prefixItems` for the declared positions, `items` for what
189
+ * may follow — `false` when nothing may, which is what makes the exact-length
190
+ * pattern exact. `prefixItems` alone constrains only elements that exist
191
+ * (draft 2020-12 implies no minimum length), so the required length is
192
+ * `minItems`, and a position past it — one the array may simply end before —
193
+ * has `undefined` stripped from its schema, absence being expressed by
194
+ * `minItems` already. Both are the object side's `required` /
195
+ * {@link stripUndefined} pair, one kind over.
173
196
  *
174
197
  * @type {(rules: RuleSet) => (p: ArraySet) => Unknown}
175
198
  */
176
- const arraySetSchema = rules => p => ({
177
- type: 'array',
178
- ...(p.prefix.length === 0 ? {} : {
179
- prefixItems: p.prefix.map(nodeSchema(rules)),
180
- minItems: p.prefix.length,
181
- }),
182
- items: p.rest === undefined ? false : nodeSchema(rules)(p.rest),
183
- })
199
+ const arraySetSchema = rules => p => {
200
+ const minItems = minLength(rules)(p.prefix)
201
+ return {
202
+ type: 'array',
203
+ ...(p.prefix.length === 0 ? {} : {
204
+ prefixItems: p.prefix.map(
205
+ (n, i) => nodeSchema(rules)(i < minItems ? n : stripUndefined(n))),
206
+ }),
207
+ ...(minItems === 0 ? {} : { minItems }),
208
+ items: p.rest === undefined ? false : nodeSchema(rules)(p.rest),
209
+ }
210
+ }
184
211
 
185
212
  /** Whether the node's value set admits `undefined` — its unit bit, read
186
213
  * through a reference if needed.
@@ -282,7 +309,7 @@ export const dataToJsonSchema = ([rules, entry]) => {
282
309
  * | `bigint` const | `{ "const": Number(value) }` (lossy for \|value\| > MAX_SAFE_INTEGER) |
283
310
  * | `undefined` const | `{ "not": {} }` |
284
311
  * | struct `{ a: T, … }` | `{ "type": "object", "properties": { "a": …T… }, "required": [non-optional keys] }` |
285
- * | tuple `[A, B]` | `{ "type": "array", "prefixItems": […A…, …B…], "minItems": 2, "items": false }` |
312
+ * | tuple `[A, B]` | `{ "type": "array", "prefixItems": […A…, …B…], "minItems": 2, "items": {} }` |
286
313
  * | `array(T)` | `{ "type": "array", "items": …T… }` |
287
314
  * | `record(T)` | `{ "type": "object", "additionalProperties": …T… }` |
288
315
  * | `or(...types)` | `{ "anyOf": […each…] }`, normalized and in canonical kind order |
@@ -28,12 +28,19 @@ export declare const proof: {
28
28
  array: () => void;
29
29
  record: () => void;
30
30
  or: () => void;
31
- tuple: () => void;
31
+ tuple: {
32
+ allRequired: () => void;
33
+ withOptional: () => void;
34
+ allOptional: () => void;
35
+ open: () => void;
36
+ };
32
37
  struct: {
33
38
  allRequired: () => void;
34
39
  withOptional: () => void;
35
40
  allOptional: () => void;
36
41
  empty: () => void;
42
+ openEmpty: () => void;
43
+ open: () => void;
37
44
  orOptional: () => void;
38
45
  withConst: () => void;
39
46
  optionalOfEveryKind: () => void;
@@ -52,7 +59,9 @@ export declare const proof: {
52
59
  duplicateLiteral: () => void;
53
60
  never: () => void;
54
61
  emptyTuple: () => void;
62
+ openEmptyTuple: () => void;
55
63
  coverageCollapse: () => void;
64
+ noCollapseWhenClosed: () => void;
56
65
  commutative: () => void;
57
66
  };
58
67
  recursion: {