functionalscript 0.36.0 → 0.38.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 (523) hide show
  1. package/README.md +1 -1
  2. package/{fs → fjs}/asn.1/module.f.js +1 -1
  3. package/{fs → fjs}/asn.1/proof.f.js +32 -94
  4. package/fjs/asserts/module.f.d.ts +36 -0
  5. package/fjs/asserts/module.f.js +39 -0
  6. package/fjs/asserts/proof.f.d.ts +11 -0
  7. package/fjs/asserts/proof.f.js +18 -0
  8. package/{fs → fjs}/base_n/module.f.js +3 -3
  9. package/{fs → fjs}/base_n/proof.f.js +15 -39
  10. package/{fs → fjs/basen}/base128/module.f.d.ts +1 -1
  11. package/{fs → fjs/basen}/base128/module.f.js +1 -1
  12. package/{fs → fjs/basen}/base128/proof.f.js +3 -3
  13. package/{fs → fjs/basen}/base64/module.f.d.ts +2 -2
  14. package/{fs → fjs/basen}/base64/module.f.js +25 -15
  15. package/{fs → fjs/basen}/base64/proof.f.d.ts +2 -0
  16. package/{fs → fjs/basen}/base64/proof.f.js +26 -6
  17. package/{fs → fjs/basen}/cbase32/module.f.d.ts +2 -2
  18. package/{fs → fjs/basen}/cbase32/module.f.js +2 -2
  19. package/{fs → fjs/basen}/cbase32/proof.f.js +16 -43
  20. package/fjs/bnf/data/module.f.d.ts +52 -0
  21. package/{fs → fjs}/bnf/data/module.f.js +56 -6
  22. package/{fs → fjs}/bnf/data/proof.f.d.ts +1 -0
  23. package/{fs → fjs}/bnf/data/proof.f.js +59 -24
  24. package/{fs → fjs}/bnf/descent/module.f.d.ts +4 -14
  25. package/fjs/bnf/descent/module.f.js +124 -0
  26. package/{fs → fjs}/bnf/descent/proof.f.d.ts +1 -0
  27. package/{fs → fjs}/bnf/descent/proof.f.js +59 -28
  28. package/{fs → fjs}/bnf/ll1/module.f.d.ts +4 -4
  29. package/{fs → fjs}/bnf/ll1/module.f.js +15 -13
  30. package/{fs → fjs}/bnf/ll1/proof.f.d.ts +1 -0
  31. package/{fs → fjs}/bnf/ll1/proof.f.js +33 -16
  32. package/{fs → fjs}/bnf/module.f.d.ts +19 -5
  33. package/{fs → fjs}/bnf/module.f.js +14 -15
  34. package/fjs/bnf/proof.f.js +69 -0
  35. package/{fs → fjs}/bnf/testlib.f.js +2 -2
  36. package/{fs → fjs}/cas/cli/module.f.js +7 -7
  37. package/{fs → fjs}/cas/cli/proof.f.d.ts +4 -1
  38. package/{fs → fjs}/cas/cli/proof.f.js +37 -74
  39. package/fjs/cas/evo/mcp/module.f.d.ts +19 -0
  40. package/fjs/cas/evo/mcp/module.f.js +56 -0
  41. package/fjs/cas/evo/mcp/proof.f.d.ts +9 -0
  42. package/fjs/cas/evo/mcp/proof.f.js +95 -0
  43. package/fjs/cas/evo/module.f.d.ts +138 -0
  44. package/fjs/cas/evo/module.f.js +309 -0
  45. package/fjs/cas/evo/proof.f.d.ts +32 -0
  46. package/fjs/cas/evo/proof.f.js +453 -0
  47. package/fjs/cas/mcp/module.f.d.ts +49 -0
  48. package/fjs/cas/mcp/module.f.js +267 -0
  49. package/{fs → fjs}/cas/mcp/proof.f.d.ts +7 -2
  50. package/{fs → fjs}/cas/mcp/proof.f.js +116 -60
  51. package/{fs → fjs}/cas/module.f.d.ts +10 -0
  52. package/{fs → fjs}/cas/module.f.js +36 -10
  53. package/{fs → fjs}/cas/proof.f.d.ts +8 -2
  54. package/{fs → fjs}/cas/proof.f.js +85 -94
  55. package/{fs → fjs}/ci/bun/module.f.js +2 -2
  56. package/{fs → fjs}/ci/common/module.f.d.ts +2 -2
  57. package/{fs → fjs}/ci/common/module.f.js +4 -4
  58. package/fjs/ci/config/module.f.d.ts +42 -0
  59. package/{fs → fjs}/ci/config/module.f.js +6 -8
  60. package/fjs/ci/deno/module.f.js +20 -0
  61. package/{fs → fjs}/ci/module.f.js +9 -9
  62. package/{fs → fjs}/ci/node/module.f.d.ts +1 -1
  63. package/{fs → fjs}/ci/node/module.f.js +3 -5
  64. package/{fs → fjs}/ci/playwright/module.f.js +3 -3
  65. package/{fs → fjs}/ci/proof.f.js +27 -22
  66. package/{fs → fjs}/ci/rust/module.f.js +11 -3
  67. package/{fs → fjs}/cli/module.f.js +3 -3
  68. package/{fs → fjs}/cli/proof.f.js +25 -66
  69. package/{fs/types → fjs/common}/monoid/module.f.d.ts +1 -1
  70. package/{fs/types → fjs/common}/monoid/proof.f.js +4 -9
  71. package/{fs → fjs}/crypto/hmac/module.f.js +2 -2
  72. package/{fs → fjs}/crypto/hmac/proof.f.js +9 -17
  73. package/{fs → fjs}/crypto/pow/module.f.js +3 -3
  74. package/fjs/crypto/pow/proof.f.js +111 -0
  75. package/{fs → fjs}/crypto/secp/module.f.js +2 -2
  76. package/{fs → fjs}/crypto/secp/proof.f.js +14 -35
  77. package/{fs → fjs}/crypto/sha2/module.f.js +2 -2
  78. package/{fs → fjs}/crypto/sha2/proof.f.js +23 -54
  79. package/{fs → fjs}/crypto/sign/module.f.d.ts +0 -5
  80. package/{fs → fjs}/crypto/sign/module.f.js +11 -8
  81. package/{fs → fjs}/crypto/sign/proof.f.js +36 -105
  82. package/{fs → fjs}/crypto/vdf/module.f.js +1 -1
  83. package/{fs → fjs}/crypto/vdf/proof.f.js +23 -64
  84. package/{fs → fjs}/dev/module.f.js +6 -6
  85. package/{fs → fjs}/dev/package_json/module.f.js +6 -6
  86. package/{fs → fjs}/dev/package_json/proof.f.js +9 -9
  87. package/{fs → fjs}/dev/proof.f.js +3 -5
  88. package/{fs → fjs}/djs/ast/module.f.js +2 -2
  89. package/{fs → fjs}/djs/ast/proof.f.js +8 -16
  90. package/fjs/djs/examples/m.f.d.ts +2 -0
  91. package/{fs → fjs}/djs/module.f.d.ts +1 -1
  92. package/{fs → fjs}/djs/module.f.js +5 -5
  93. package/{fs → fjs}/djs/parser/module.f.d.ts +5 -0
  94. package/{fs → fjs}/djs/parser/module.f.js +24 -4
  95. package/{fs → fjs}/djs/parser/proof.f.js +145 -407
  96. package/{fs → fjs}/djs/proof.f.js +16 -39
  97. package/{fs → fjs}/djs/serializer/module.f.js +6 -6
  98. package/{fs → fjs}/djs/serializer/proof.f.js +18 -43
  99. package/fjs/djs/tokenizer/module.f.d.ts +24 -0
  100. package/fjs/djs/tokenizer/module.f.js +472 -0
  101. package/{fs/djs/tokenizer-new → fjs/djs/tokenizer}/proof.f.d.ts +4 -3
  102. package/{fs/djs/tokenizer-new → fjs/djs/tokenizer}/proof.f.js +447 -446
  103. package/{fs → fjs}/djs/transpiler/module.f.d.ts +5 -0
  104. package/{fs → fjs}/djs/transpiler/module.f.js +21 -11
  105. package/{fs → fjs}/djs/transpiler/proof.f.d.ts +3 -0
  106. package/fjs/djs/transpiler/proof.f.js +67 -0
  107. package/{fs → fjs}/effects/memory/module.f.js +4 -4
  108. package/{fs → fjs}/effects/memory/proof.f.js +11 -24
  109. package/{fs → fjs}/effects/module.f.js +1 -1
  110. package/{fs → fjs}/effects/node/memory/module.js +2 -2
  111. package/{fs → fjs}/effects/node/memory/proof.js +8 -15
  112. package/{fs → fjs}/effects/node/module.d.ts +1 -1
  113. package/{fs → fjs}/effects/node/module.f.d.ts +1 -1
  114. package/{fs → fjs}/effects/node/module.f.js +7 -7
  115. package/{fs → fjs}/effects/node/module.js +13 -13
  116. package/{fs → fjs}/effects/node/proof.f.d.ts +1 -0
  117. package/{fs → fjs}/effects/node/proof.f.js +106 -292
  118. package/{fs → fjs}/effects/node/virtual/module.f.js +7 -7
  119. package/{fs → fjs}/effects/node/virtual/proof.f.d.ts +2 -0
  120. package/{fs → fjs}/effects/node/virtual/proof.f.js +44 -30
  121. package/{fs → fjs}/effects/proof.f.js +18 -47
  122. package/fjs/emergent_testing/all.test.js +4 -0
  123. package/{fs → fjs}/emergent_testing/example.f.d.ts +1 -1
  124. package/{fs → fjs}/emergent_testing/module.f.js +6 -6
  125. package/{fs → fjs}/emergent_testing/proof.f.d.ts +19 -17
  126. package/{fs → fjs}/emergent_testing/proof.f.js +14 -14
  127. package/fjs/emergent_testing/scenarios/all.js +1 -0
  128. package/{fs → fjs}/fsc/bnf.f.js +2 -2
  129. package/{fs → fjs}/fsc/json.f.js +1 -1
  130. package/{fs → fjs}/fsc/module.f.js +7 -7
  131. package/{fs → fjs}/fsc/proof.f.js +16 -38
  132. package/{fs → fjs}/fsm/module.f.js +9 -9
  133. package/{fs → fjs}/fsm/proof.f.js +12 -19
  134. package/{fs → fjs}/js/tokenizer/module.f.js +7 -7
  135. package/{fs → fjs}/js/tokenizer/proof.f.js +5 -5
  136. package/{fs → fjs}/mcp/module.f.d.ts +20 -13
  137. package/{fs → fjs}/mcp/module.f.js +16 -9
  138. package/{fs → fjs}/mcp/proof.f.js +17 -17
  139. package/{fs → fjs}/mcp/stdio/module.f.d.ts +4 -4
  140. package/{fs → fjs}/mcp/stdio/module.f.js +12 -12
  141. package/{fs → fjs}/mcp/stdio/proof.f.js +10 -10
  142. package/{fs → fjs/media}/html/module.f.d.ts +3 -3
  143. package/{fs → fjs/media}/html/module.f.js +9 -9
  144. package/{fs → fjs/media}/html/proof.f.js +12 -33
  145. package/fjs/media/json/module.f.d.ts +50 -0
  146. package/{fs → fjs/media}/json/module.f.js +7 -7
  147. package/{fs → fjs/media}/json/parser/module.f.d.ts +7 -2
  148. package/{fs → fjs/media}/json/parser/module.f.js +21 -7
  149. package/{fs → fjs/media}/json/parser/proof.f.js +45 -120
  150. package/{fs → fjs/media}/json/proof.f.js +4 -4
  151. package/fjs/media/json/rpc/module.f.d.ts +114 -0
  152. package/{fs → fjs/media}/json/rpc/module.f.js +4 -4
  153. package/{fs → fjs/media}/json/rpc/proof.f.js +4 -4
  154. package/fjs/media/json/schema/module.f.d.ts +78 -0
  155. package/{fs → fjs/media}/json/schema/module.f.js +25 -41
  156. package/{fs → fjs/media}/json/schema/proof.f.js +6 -9
  157. package/{fs → fjs/media}/json/serializer/module.f.d.ts +1 -1
  158. package/{fs → fjs/media}/json/serializer/module.f.js +2 -2
  159. package/{fs → fjs/media}/json/serializer/proof.f.js +12 -29
  160. package/{fs → fjs/media}/json/tokenizer/module.f.d.ts +2 -2
  161. package/{fs → fjs/media}/json/tokenizer/module.f.js +4 -4
  162. package/{fs → fjs/media}/json/tokenizer/proof.f.js +5 -5
  163. package/fjs/media/module.f.d.ts +37 -0
  164. package/fjs/media/module.f.js +23 -0
  165. package/fjs/media/proof.f.d.ts +9 -0
  166. package/fjs/media/proof.f.js +58 -0
  167. package/fjs/media/revision/module.f.d.ts +78 -0
  168. package/fjs/media/revision/module.f.js +122 -0
  169. package/fjs/media/revision/proof.f.d.ts +31 -0
  170. package/fjs/media/revision/proof.f.js +140 -0
  171. package/{fs/mime → fjs/media/type}/module.f.d.ts +6 -6
  172. package/{fs/mime → fjs/media/type}/module.f.js +6 -6
  173. package/{fs/mime → fjs/media/type}/proof.f.js +8 -12
  174. package/fjs/module.f.d.ts +2 -0
  175. package/{fs/fjs → fjs}/module.f.js +9 -9
  176. package/fjs/module.js +4 -0
  177. package/{fs → fjs}/path/module.f.js +2 -2
  178. package/{fs → fjs}/path/proof.f.js +27 -78
  179. package/{fs/fjs → fjs}/proof.f.js +6 -4
  180. package/{fs → fjs}/sul/id/module.f.js +9 -9
  181. package/{fs → fjs}/sul/id/proof.f.js +12 -26
  182. package/{fs → fjs}/sul/level/hash/module.f.js +3 -3
  183. package/{fs → fjs}/sul/level/hash/proof.f.js +8 -8
  184. package/{fs → fjs}/sul/level/literal/module.f.js +5 -5
  185. package/{fs → fjs}/sul/level/literal/proof.f.js +15 -29
  186. package/{fs → fjs}/sul/module.f.js +3 -3
  187. package/{fs → fjs}/sul/proof.f.js +3 -3
  188. package/fjs/text/ascii/proof.f.d.ts +6 -0
  189. package/fjs/text/ascii/proof.f.js +14 -0
  190. package/{fs → fjs}/text/code_point/module.f.js +12 -12
  191. package/{fs → fjs}/text/code_point/proof.f.js +1 -1
  192. package/{fs → fjs}/text/module.f.js +5 -5
  193. package/{fs → fjs}/text/proof.f.js +7 -12
  194. package/{fs → fjs}/text/sgr/module.f.js +2 -2
  195. package/{fs → fjs}/text/sgr/proof.f.js +8 -17
  196. package/{fs → fjs}/text/utf16/module.f.js +6 -6
  197. package/{fs → fjs}/text/utf16/proof.f.js +27 -70
  198. package/{fs → fjs}/text/utf8/module.f.js +22 -17
  199. package/{fs → fjs}/text/utf8/proof.f.js +59 -128
  200. package/{fs → fjs}/types/array/module.f.js +1 -1
  201. package/{fs → fjs}/types/array/proof.f.js +21 -55
  202. package/{fs → fjs}/types/bigfloat/module.f.js +1 -1
  203. package/fjs/types/bigfloat/proof.f.js +217 -0
  204. package/{fs → fjs}/types/bigint/module.f.js +2 -2
  205. package/{fs → fjs}/types/bigint/proof.f.js +51 -147
  206. package/{fs → fjs}/types/bit_vec/module.f.js +8 -8
  207. package/{fs → fjs}/types/bit_vec/proof.f.js +76 -218
  208. package/{fs → fjs}/types/btree/find/module.f.js +1 -1
  209. package/fjs/types/btree/find/proof.f.d.ts +3 -0
  210. package/fjs/types/btree/find/proof.f.js +108 -0
  211. package/{fs → fjs}/types/btree/module.f.js +2 -2
  212. package/fjs/types/btree/proof.f.d.ts +13 -0
  213. package/{fs → fjs}/types/btree/proof.f.js +12 -19
  214. package/{fs → fjs}/types/btree/remove/module.f.js +4 -4
  215. package/fjs/types/btree/remove/proof.f.d.ts +9 -0
  216. package/{fs → fjs}/types/btree/remove/proof.f.js +88 -235
  217. package/{fs → fjs}/types/btree/set/module.f.js +8 -5
  218. package/{fs → fjs}/types/btree/set/proof.f.js +39 -28
  219. package/{fs → fjs}/types/byte_set/module.f.js +2 -2
  220. package/fjs/types/byte_set/proof.f.js +79 -0
  221. package/{fs → fjs}/types/function/compare/proof.f.js +14 -37
  222. package/fjs/types/function/operator/proof.f.d.ts +23 -0
  223. package/{fs → fjs}/types/function/operator/proof.f.js +18 -49
  224. package/{fs → fjs}/types/function/proof.f.js +3 -4
  225. package/{fs → fjs}/types/list/module.f.js +2 -2
  226. package/fjs/types/list/proof.f.d.ts +30 -0
  227. package/{fs → fjs}/types/list/proof.f.js +59 -167
  228. package/{fs → fjs}/types/map/proof.f.js +6 -14
  229. package/fjs/types/nibble_set/proof.f.js +60 -0
  230. package/{fs → fjs}/types/nominal/proof.f.js +5 -10
  231. package/{fs → fjs}/types/nullable/module.f.js +2 -2
  232. package/fjs/types/nullable/proof.f.js +29 -0
  233. package/{fs → fjs}/types/number/module.f.js +5 -5
  234. package/{fs → fjs}/types/number/proof.f.js +10 -25
  235. package/{fs → fjs}/types/object/module.f.js +4 -4
  236. package/{fs → fjs}/types/object/proof.f.js +4 -7
  237. package/{fs → fjs}/types/ordered_map/module.f.js +6 -6
  238. package/{fs → fjs}/types/ordered_map/proof.f.js +3 -3
  239. package/fjs/types/patricia_trie/proof.f.d.ts +13 -0
  240. package/{fs → fjs}/types/patricia_trie/proof.f.js +22 -22
  241. package/{fs → fjs}/types/prime_field/module.f.js +3 -8
  242. package/{fs → fjs}/types/prime_field/proof.f.js +2 -2
  243. package/{fs → fjs}/types/range/module.f.d.ts +1 -1
  244. package/fjs/types/range/module.f.js +2 -0
  245. package/fjs/types/range/proof.f.js +9 -0
  246. package/{fs → fjs}/types/range_map/module.f.js +4 -4
  247. package/{fs → fjs}/types/range_map/proof.f.js +35 -88
  248. package/{fs → fjs}/types/result/module.js +1 -1
  249. package/fjs/types/result/proof.f.d.ts +12 -0
  250. package/fjs/types/result/proof.f.js +31 -0
  251. package/{fs → fjs}/types/rtti/common/module.f.d.ts +36 -1
  252. package/{fs → fjs}/types/rtti/common/module.f.js +48 -4
  253. package/fjs/types/rtti/common/proof.f.d.ts +8 -0
  254. package/fjs/types/rtti/common/proof.f.js +51 -0
  255. package/{fs → fjs}/types/rtti/module.f.d.ts +2 -2
  256. package/{fs → fjs}/types/rtti/module.f.js +1 -1
  257. package/{fs → fjs}/types/rtti/parse/module.f.js +16 -25
  258. package/{fs → fjs}/types/rtti/parse/proof.f.js +9 -20
  259. package/{fs → fjs}/types/rtti/ts/module.f.d.ts +10 -4
  260. package/{fs → fjs}/types/rtti/ts/module.f.js +1 -1
  261. package/{fs → fjs}/types/rtti/ts/proof.f.js +2 -2
  262. package/{fs → fjs}/types/rtti/validate/module.f.js +11 -32
  263. package/{fs → fjs}/types/rtti/validate/proof.f.js +6 -11
  264. package/{fs → fjs}/types/sorted_list/module.f.js +3 -3
  265. package/{fs → fjs}/types/sorted_list/proof.f.js +14 -27
  266. package/{fs → fjs}/types/sorted_set/module.f.js +1 -1
  267. package/{fs → fjs}/types/sorted_set/proof.f.js +20 -45
  268. package/{fs → fjs}/types/string/module.f.js +4 -4
  269. package/fjs/types/string/proof.f.js +77 -0
  270. package/{fs → fjs}/types/string_set/module.f.js +6 -6
  271. package/fjs/types/string_set/proof.f.js +43 -0
  272. package/{fs → fjs}/types/ts/proof.f.d.ts +18 -18
  273. package/{fs → fjs}/types/ts/proof.f.js +16 -43
  274. package/{fs → fjs}/types/uint8array/module.f.js +10 -10
  275. package/{fs → fjs}/types/uint8array/proof.f.d.ts +4 -1
  276. package/{fs → fjs}/types/uint8array/proof.f.js +11 -11
  277. package/{fs → fjs}/website/module.f.js +3 -3
  278. package/fjs/website/proof.f.js +13 -0
  279. package/package.json +8 -8
  280. package/fs/asserts/module.f.d.ts +0 -4
  281. package/fs/asserts/module.f.js +0 -9
  282. package/fs/asserts/proof.f.d.ts +0 -8
  283. package/fs/asserts/proof.f.js +0 -51
  284. package/fs/bnf/data/module.f.d.ts +0 -30
  285. package/fs/bnf/descent/module.f.js +0 -119
  286. package/fs/bnf/proof.f.js +0 -104
  287. package/fs/cas/mcp/module.f.d.ts +0 -36
  288. package/fs/cas/mcp/module.f.js +0 -249
  289. package/fs/ci/config/module.f.d.ts +0 -43
  290. package/fs/ci/deno/module.f.js +0 -16
  291. package/fs/crypto/pow/proof.f.js +0 -161
  292. package/fs/djs/examples/m.f.d.ts +0 -2
  293. package/fs/djs/tokenizer/module.f.d.ts +0 -12
  294. package/fs/djs/tokenizer/module.f.js +0 -62
  295. package/fs/djs/tokenizer/proof.f.d.ts +0 -7
  296. package/fs/djs/tokenizer/proof.f.js +0 -543
  297. package/fs/djs/tokenizer-new/module.f.d.ts +0 -3
  298. package/fs/djs/tokenizer-new/module.f.js +0 -155
  299. package/fs/djs/transpiler/proof.f.js +0 -68
  300. package/fs/emergent_testing/all.test.js +0 -4
  301. package/fs/emergent_testing/scenarios/all.js +0 -1
  302. package/fs/fjs/module.f.d.ts +0 -2
  303. package/fs/fjs/module.js +0 -4
  304. package/fs/json/module.f.d.ts +0 -50
  305. package/fs/json/rpc/module.f.d.ts +0 -114
  306. package/fs/json/schema/module.f.d.ts +0 -77
  307. package/fs/text/ascii/proof.f.d.ts +0 -4
  308. package/fs/text/ascii/proof.f.js +0 -24
  309. package/fs/types/bigfloat/proof.f.js +0 -348
  310. package/fs/types/btree/find/proof.f.js +0 -151
  311. package/fs/types/btree/proof.f.d.ts +0 -7
  312. package/fs/types/btree/remove/proof.f.d.ts +0 -4
  313. package/fs/types/byte_set/proof.f.js +0 -120
  314. package/fs/types/function/operator/proof.f.d.ts +0 -12
  315. package/fs/types/list/proof.f.d.ts +0 -22
  316. package/fs/types/nibble_set/proof.f.js +0 -89
  317. package/fs/types/nullable/proof.f.js +0 -50
  318. package/fs/types/patricia_trie/proof.f.d.ts +0 -7
  319. package/fs/types/range/module.f.js +0 -2
  320. package/fs/types/range/proof.f.d.ts +0 -1
  321. package/fs/types/range/proof.f.js +0 -18
  322. package/fs/types/result/proof.f.d.ts +0 -6
  323. package/fs/types/result/proof.f.js +0 -52
  324. package/fs/types/string/proof.f.js +0 -118
  325. package/fs/types/string_set/proof.f.js +0 -82
  326. package/fs/website/proof.f.js +0 -16
  327. /package/{fs → fjs}/asn.1/module.f.d.ts +0 -0
  328. /package/{fs → fjs}/asn.1/proof.f.d.ts +0 -0
  329. /package/{fs → fjs}/base_n/module.f.d.ts +0 -0
  330. /package/{fs → fjs}/base_n/proof.f.d.ts +0 -0
  331. /package/{fs → fjs/basen}/base128/proof.f.d.ts +0 -0
  332. /package/{fs → fjs/basen}/cbase32/proof.f.d.ts +0 -0
  333. /package/{fs → fjs}/bnf/proof.f.d.ts +0 -0
  334. /package/{fs → fjs}/bnf/testlib.f.d.ts +0 -0
  335. /package/{fs → fjs}/cas/cli/module.f.d.ts +0 -0
  336. /package/{fs → fjs}/ci/bun/module.f.d.ts +0 -0
  337. /package/{fs → fjs}/ci/deno/module.f.d.ts +0 -0
  338. /package/{fs → fjs}/ci/module.f.d.ts +0 -0
  339. /package/{fs → fjs}/ci/playwright/module.f.d.ts +0 -0
  340. /package/{fs → fjs}/ci/proof.f.d.ts +0 -0
  341. /package/{fs → fjs}/ci/rust/module.f.d.ts +0 -0
  342. /package/{fs → fjs}/cli/module.f.d.ts +0 -0
  343. /package/{fs → fjs}/cli/proof.f.d.ts +0 -0
  344. /package/{fs/types → fjs/common}/monoid/module.f.js +0 -0
  345. /package/{fs/types → fjs/common}/monoid/proof.f.d.ts +0 -0
  346. /package/{fs → fjs}/crypto/hmac/module.f.d.ts +0 -0
  347. /package/{fs → fjs}/crypto/hmac/proof.f.d.ts +0 -0
  348. /package/{fs → fjs}/crypto/pow/module.f.d.ts +0 -0
  349. /package/{fs → fjs}/crypto/pow/proof.f.d.ts +0 -0
  350. /package/{fs → fjs}/crypto/secp/module.f.d.ts +0 -0
  351. /package/{fs → fjs}/crypto/secp/proof.f.d.ts +0 -0
  352. /package/{fs → fjs}/crypto/sha2/module.f.d.ts +0 -0
  353. /package/{fs → fjs}/crypto/sha2/proof.f.d.ts +0 -0
  354. /package/{fs → fjs}/crypto/sign/proof.f.d.ts +0 -0
  355. /package/{fs → fjs}/crypto/vdf/module.f.d.ts +0 -0
  356. /package/{fs → fjs}/crypto/vdf/proof.f.d.ts +0 -0
  357. /package/{fs → fjs}/dev/module.f.d.ts +0 -0
  358. /package/{fs → fjs}/dev/package_json/module.f.d.ts +0 -0
  359. /package/{fs → fjs}/dev/package_json/proof.f.d.ts +0 -0
  360. /package/{fs → fjs}/dev/proof.f.d.ts +0 -0
  361. /package/{fs → fjs}/djs/ast/module.f.d.ts +0 -0
  362. /package/{fs → fjs}/djs/ast/proof.f.d.ts +0 -0
  363. /package/{fs → fjs}/djs/examples/input.f.d.ts +0 -0
  364. /package/{fs → fjs}/djs/examples/input.f.js +0 -0
  365. /package/{fs → fjs}/djs/examples/m.f.js +0 -0
  366. /package/{fs → fjs}/djs/parser/proof.f.d.ts +0 -0
  367. /package/{fs → fjs}/djs/proof.f.d.ts +0 -0
  368. /package/{fs → fjs}/djs/serializer/module.f.d.ts +0 -0
  369. /package/{fs → fjs}/djs/serializer/proof.f.d.ts +0 -0
  370. /package/{fs → fjs}/effects/list/module.f.d.ts +0 -0
  371. /package/{fs → fjs}/effects/list/module.f.js +0 -0
  372. /package/{fs → fjs}/effects/memory/module.f.d.ts +0 -0
  373. /package/{fs → fjs}/effects/memory/proof.f.d.ts +0 -0
  374. /package/{fs → fjs}/effects/mock/module.f.d.ts +0 -0
  375. /package/{fs → fjs}/effects/mock/module.f.js +0 -0
  376. /package/{fs → fjs}/effects/module.d.ts +0 -0
  377. /package/{fs → fjs}/effects/module.f.d.ts +0 -0
  378. /package/{fs → fjs}/effects/module.js +0 -0
  379. /package/{fs → fjs}/effects/node/memory/module.d.ts +0 -0
  380. /package/{fs → fjs}/effects/node/memory/proof.d.ts +0 -0
  381. /package/{fs → fjs}/effects/node/virtual/module.f.d.ts +0 -0
  382. /package/{fs → fjs}/effects/proof.f.d.ts +0 -0
  383. /package/{fs → fjs}/emergent_testing/all.test.d.ts +0 -0
  384. /package/{fs → fjs}/emergent_testing/example.f.js +0 -0
  385. /package/{fs → fjs}/emergent_testing/module.f.d.ts +0 -0
  386. /package/{fs → fjs}/emergent_testing/scenarios/all.d.ts +0 -0
  387. /package/{fs → fjs}/emergent_testing/scenarios/async-subtests.fail.d.ts +0 -0
  388. /package/{fs → fjs}/emergent_testing/scenarios/async-subtests.fail.js +0 -0
  389. /package/{fs → fjs}/emergent_testing/scenarios/async-subtests.pass.d.ts +0 -0
  390. /package/{fs → fjs}/emergent_testing/scenarios/async-subtests.pass.js +0 -0
  391. /package/{fs → fjs}/emergent_testing/scenarios/async.fail.d.ts +0 -0
  392. /package/{fs → fjs}/emergent_testing/scenarios/async.fail.js +0 -0
  393. /package/{fs → fjs}/emergent_testing/scenarios/async.pass.d.ts +0 -0
  394. /package/{fs → fjs}/emergent_testing/scenarios/async.pass.js +0 -0
  395. /package/{fs → fjs}/emergent_testing/scenarios/fail.fail.d.ts +0 -0
  396. /package/{fs → fjs}/emergent_testing/scenarios/fail.fail.js +0 -0
  397. /package/{fs → fjs}/emergent_testing/scenarios/return-value.pass.d.ts +0 -0
  398. /package/{fs → fjs}/emergent_testing/scenarios/return-value.pass.js +0 -0
  399. /package/{fs → fjs}/emergent_testing/scenarios/thenable.pass.d.ts +0 -0
  400. /package/{fs → fjs}/emergent_testing/scenarios/thenable.pass.js +0 -0
  401. /package/{fs → fjs}/emergent_testing/scenarios/thenable2.pass.d.ts +0 -0
  402. /package/{fs → fjs}/emergent_testing/scenarios/thenable2.pass.js +0 -0
  403. /package/{fs → fjs}/emergent_testing/scenarios/throw.pass.d.ts +0 -0
  404. /package/{fs → fjs}/emergent_testing/scenarios/throw.pass.js +0 -0
  405. /package/{fs → fjs}/fsc/bnf.f.d.ts +0 -0
  406. /package/{fs → fjs}/fsc/json.f.d.ts +0 -0
  407. /package/{fs → fjs}/fsc/module.f.d.ts +0 -0
  408. /package/{fs → fjs}/fsc/proof.f.d.ts +0 -0
  409. /package/{fs → fjs}/fsm/module.f.d.ts +0 -0
  410. /package/{fs → fjs}/fsm/proof.f.d.ts +0 -0
  411. /package/{fs → fjs}/js/tokenizer/module.f.d.ts +0 -0
  412. /package/{fs → fjs}/js/tokenizer/proof.f.d.ts +0 -0
  413. /package/{fs → fjs}/mcp/proof.f.d.ts +0 -0
  414. /package/{fs → fjs}/mcp/stdio/proof.f.d.ts +0 -0
  415. /package/{fs → fjs/media}/html/proof.f.d.ts +0 -0
  416. /package/{fs → fjs/media}/json/parser/proof.f.d.ts +0 -0
  417. /package/{fs → fjs/media}/json/proof.f.d.ts +0 -0
  418. /package/{fs → fjs/media}/json/rpc/proof.f.d.ts +0 -0
  419. /package/{fs → fjs/media}/json/schema/proof.f.d.ts +0 -0
  420. /package/{fs → fjs/media}/json/serializer/proof.f.d.ts +0 -0
  421. /package/{fs → fjs/media}/json/tokenizer/proof.f.d.ts +0 -0
  422. /package/{fs/mime → fjs/media/type}/proof.f.d.ts +0 -0
  423. /package/{fs/fjs → fjs}/module.d.ts +0 -0
  424. /package/{fs → fjs}/path/module.f.d.ts +0 -0
  425. /package/{fs → fjs}/path/proof.f.d.ts +0 -0
  426. /package/{fs/fjs → fjs}/proof.f.d.ts +0 -0
  427. /package/{fs → fjs}/sul/id/module.f.d.ts +0 -0
  428. /package/{fs → fjs}/sul/id/proof.f.d.ts +0 -0
  429. /package/{fs → fjs}/sul/level/hash/module.f.d.ts +0 -0
  430. /package/{fs → fjs}/sul/level/hash/proof.f.d.ts +0 -0
  431. /package/{fs → fjs}/sul/level/literal/module.f.d.ts +0 -0
  432. /package/{fs → fjs}/sul/level/literal/proof.f.d.ts +0 -0
  433. /package/{fs → fjs}/sul/module.f.d.ts +0 -0
  434. /package/{fs → fjs}/sul/proof.f.d.ts +0 -0
  435. /package/{fs → fjs}/text/ascii/module.f.d.ts +0 -0
  436. /package/{fs → fjs}/text/ascii/module.f.js +0 -0
  437. /package/{fs → fjs}/text/code_point/module.f.d.ts +0 -0
  438. /package/{fs → fjs}/text/code_point/proof.f.d.ts +0 -0
  439. /package/{fs → fjs}/text/module.f.d.ts +0 -0
  440. /package/{fs → fjs}/text/proof.f.d.ts +0 -0
  441. /package/{fs → fjs}/text/sgr/module.f.d.ts +0 -0
  442. /package/{fs → fjs}/text/sgr/proof.f.d.ts +0 -0
  443. /package/{fs → fjs}/text/utf16/module.f.d.ts +0 -0
  444. /package/{fs → fjs}/text/utf16/proof.f.d.ts +0 -0
  445. /package/{fs → fjs}/text/utf8/module.f.d.ts +0 -0
  446. /package/{fs → fjs}/text/utf8/proof.f.d.ts +0 -0
  447. /package/{fs → fjs}/types/array/module.f.d.ts +0 -0
  448. /package/{fs → fjs}/types/array/proof.f.d.ts +0 -0
  449. /package/{fs → fjs}/types/bigfloat/module.f.d.ts +0 -0
  450. /package/{fs → fjs}/types/bigfloat/proof.f.d.ts +0 -0
  451. /package/{fs → fjs}/types/bigint/module.f.d.ts +0 -0
  452. /package/{fs → fjs}/types/bigint/proof.f.d.ts +0 -0
  453. /package/{fs → fjs}/types/bit_vec/module.f.d.ts +0 -0
  454. /package/{fs → fjs}/types/bit_vec/proof.f.d.ts +0 -0
  455. /package/{fs → fjs}/types/btree/find/module.f.d.ts +0 -0
  456. /package/{fs → fjs}/types/btree/module.f.d.ts +0 -0
  457. /package/{fs → fjs}/types/btree/remove/module.f.d.ts +0 -0
  458. /package/{fs → fjs}/types/btree/set/module.f.d.ts +0 -0
  459. /package/{fs → fjs}/types/btree/set/proof.f.d.ts +0 -0
  460. /package/{fs → fjs}/types/btree/types/module.f.d.ts +0 -0
  461. /package/{fs → fjs}/types/btree/types/module.f.js +0 -0
  462. /package/{fs → fjs}/types/byte_set/module.f.d.ts +0 -0
  463. /package/{fs → fjs}/types/byte_set/proof.f.d.ts +0 -0
  464. /package/{fs → fjs}/types/function/compare/module.f.d.ts +0 -0
  465. /package/{fs → fjs}/types/function/compare/module.f.js +0 -0
  466. /package/{fs/types/btree/find → fjs/types/function/compare}/proof.f.d.ts +0 -0
  467. /package/{fs → fjs}/types/function/module.f.d.ts +0 -0
  468. /package/{fs → fjs}/types/function/module.f.js +0 -0
  469. /package/{fs → fjs}/types/function/operator/module.f.d.ts +0 -0
  470. /package/{fs → fjs}/types/function/operator/module.f.js +0 -0
  471. /package/{fs/types/function/compare → fjs/types/function}/proof.f.d.ts +0 -0
  472. /package/{fs → fjs}/types/list/module.f.d.ts +0 -0
  473. /package/{fs → fjs}/types/map/module.f.d.ts +0 -0
  474. /package/{fs → fjs}/types/map/module.f.js +0 -0
  475. /package/{fs → fjs}/types/map/proof.f.d.ts +0 -0
  476. /package/{fs → fjs}/types/nibble_set/module.f.d.ts +0 -0
  477. /package/{fs → fjs}/types/nibble_set/module.f.js +0 -0
  478. /package/{fs → fjs}/types/nibble_set/proof.f.d.ts +0 -0
  479. /package/{fs → fjs}/types/nominal/module.f.d.ts +0 -0
  480. /package/{fs → fjs}/types/nominal/module.f.js +0 -0
  481. /package/{fs → fjs}/types/nominal/proof.f.d.ts +0 -0
  482. /package/{fs → fjs}/types/nullable/module.f.d.ts +0 -0
  483. /package/{fs → fjs}/types/nullable/proof.f.d.ts +0 -0
  484. /package/{fs → fjs}/types/number/module.f.d.ts +0 -0
  485. /package/{fs → fjs}/types/number/proof.f.d.ts +0 -0
  486. /package/{fs → fjs}/types/object/module.f.d.ts +0 -0
  487. /package/{fs → fjs}/types/object/proof.f.d.ts +0 -0
  488. /package/{fs → fjs}/types/option/module.f.d.ts +0 -0
  489. /package/{fs → fjs}/types/option/module.f.js +0 -0
  490. /package/{fs → fjs}/types/ordered_map/module.f.d.ts +0 -0
  491. /package/{fs → fjs}/types/ordered_map/proof.f.d.ts +0 -0
  492. /package/{fs → fjs}/types/patricia_trie/module.f.d.ts +0 -0
  493. /package/{fs → fjs}/types/patricia_trie/module.f.js +0 -0
  494. /package/{fs → fjs}/types/phantom/module.f.d.ts +0 -0
  495. /package/{fs → fjs}/types/phantom/module.f.js +0 -0
  496. /package/{fs → fjs}/types/prime_field/module.f.d.ts +0 -0
  497. /package/{fs → fjs}/types/prime_field/proof.f.d.ts +0 -0
  498. /package/{fs/types/function → fjs/types/range}/proof.f.d.ts +0 -0
  499. /package/{fs → fjs}/types/range_map/module.f.d.ts +0 -0
  500. /package/{fs → fjs}/types/range_map/proof.f.d.ts +0 -0
  501. /package/{fs → fjs}/types/result/module.d.ts +0 -0
  502. /package/{fs → fjs}/types/result/module.f.d.ts +0 -0
  503. /package/{fs → fjs}/types/result/module.f.js +0 -0
  504. /package/{fs → fjs}/types/rtti/parse/module.f.d.ts +0 -0
  505. /package/{fs → fjs}/types/rtti/parse/proof.f.d.ts +0 -0
  506. /package/{fs → fjs}/types/rtti/proof.f.d.ts +0 -0
  507. /package/{fs → fjs}/types/rtti/proof.f.js +0 -0
  508. /package/{fs → fjs}/types/rtti/ts/proof.f.d.ts +0 -0
  509. /package/{fs → fjs}/types/rtti/validate/module.f.d.ts +0 -0
  510. /package/{fs → fjs}/types/rtti/validate/proof.f.d.ts +0 -0
  511. /package/{fs → fjs}/types/sorted_list/module.f.d.ts +0 -0
  512. /package/{fs → fjs}/types/sorted_list/proof.f.d.ts +0 -0
  513. /package/{fs → fjs}/types/sorted_set/module.f.d.ts +0 -0
  514. /package/{fs → fjs}/types/sorted_set/proof.f.d.ts +0 -0
  515. /package/{fs → fjs}/types/string/module.f.d.ts +0 -0
  516. /package/{fs → fjs}/types/string/proof.f.d.ts +0 -0
  517. /package/{fs → fjs}/types/string_set/module.f.d.ts +0 -0
  518. /package/{fs → fjs}/types/string_set/proof.f.d.ts +0 -0
  519. /package/{fs → fjs}/types/ts/module.f.d.ts +0 -0
  520. /package/{fs → fjs}/types/ts/module.f.js +0 -0
  521. /package/{fs → fjs}/types/uint8array/module.f.d.ts +0 -0
  522. /package/{fs → fjs}/website/module.f.d.ts +0 -0
  523. /package/{fs → fjs}/website/proof.f.d.ts +0 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * MCP adapter for the content-addressable store and the Evo API layered on
3
+ * top of it.
4
+ *
5
+ * Maps `Cas<O>` operations onto MCP tools, so an agent that speaks MCP can
6
+ * store a blob and get back its hash, fetch a blob by hash, and enumerate
7
+ * what is stored — without shelling out to the `cas` CLI. The store itself
8
+ * (`fjs/cas/module.f.ts`) stays transport-agnostic; this is an additional
9
+ * front end alongside the CLI `main`. The same server also exposes
10
+ * `fjs/cas/evo`'s subject/head API (`evo_list`/`evo_head`/`evo_add`,
11
+ * `fjs/cas/evo/mcp`) — one process, one `~/.cas/` store, one in-memory Evo
12
+ * cache scanned once at startup (`initEvo`).
13
+ *
14
+ * ## Tools
15
+ *
16
+ * | Tool | args | action | result |
17
+ * |-------------|-------------------------------------------------|---------------|--------------------------------------|
18
+ * | `cas_add` | `{ content, type? }` | `c.write(...)`| hash (cBase32) |
19
+ * | `cas_get` | `{ hash, content?: boolean }` | `c.read(key)` | JSON `{length,mimeType,type[,uri][,text\|blob]}` |
20
+ * | `cas_list` | `{}` | `c.list()` | hashes, one per line |
21
+ * | `evo_list` | `{}` | `e.list()` | subjects, one per line |
22
+ * | `evo_head` | `{ subject }` | `e.head(...)` | head hashes, one per line |
23
+ * | `evo_add` | `{ parents, snapshot?, subject?, archived? }` | `e.add(...)` | hash (cBase32) |
24
+ *
25
+ * ## `cas_add` input encoding
26
+ *
27
+ * The optional `type` field controls how `content` is interpreted:
28
+ * - `'text'` (default, or omitted): `content` is a UTF-8 string stored as raw
29
+ * bytes. Most agent-generated content (scripts, JSON, prompts) can be stored
30
+ * without any encoding step.
31
+ * - `'base64'`: `content` is RFC 4648 base64, decoded to bytes before storage.
32
+ * Use this for pre-encoded binary payloads.
33
+ *
34
+ * Inline content (either encoding) is capped at 128 KiB (`maxLength`). There is
35
+ * no MCP route for larger content — the server never opens a local path named by
36
+ * the client (see the invariant in `fjs/cas/mcp/README.md`); large files go
37
+ * through the `cas` CLI (`cas add <path>`) instead, run directly by the user.
38
+ *
39
+ * ## `cas_get` output
40
+ *
41
+ * Always returns a JSON object `{ length, mimeType, type[, uri][, text | blob] }`.
42
+ * These field names mirror the MCP resource-contents shape (`resources/read`
43
+ * results), so the tool view and the future resource view of a blob use the same
44
+ * vocabulary: `mimeType` (not `mime_type`), `uri` (not `url`) — the resource URI
45
+ * under which the same blob will be readable via `resources/read` — and `text` /
46
+ * `blob` (not a `type`-tagged `content`) for inline payloads. `type` is always
47
+ * present (`'text'` or `'base64'`) as the discriminator for which of `text` /
48
+ * `blob` a later `content: true` fetch would populate — MCP allows extra fields,
49
+ * so `type` and `length` simply stay alongside the required resource-contents
50
+ * fields. A single classifier — the `fjs/media/type` detector state machine (length ×
51
+ * magic-byte eliminator × UTF-8 DFA) — produces the same three-way verdict on
52
+ * both paths, so there is no second, divergent copy of the rules:
53
+ *
54
+ * 1. **Magic-byte hit** (PNG/JPEG/GIF/WebP/PDF/ZIP) → `type: 'base64'` with the
55
+ * detected `mimeType`.
56
+ * 2. **Whole-blob-valid UTF-8** → `type: 'text'`, `mimeType: 'text/plain'`.
57
+ * 3. **Fallback** → `type: 'base64'`, `mimeType: 'application/octet-stream'`.
58
+ *
59
+ * **Metadata-only (`content: false`, the default) is size-independent for
60
+ * non-text and oversized blobs.** It folds the read stream through
61
+ * `fjs/media/type` `detectStream` and never buffers the blob. Because a single
62
+ * `Vec` caps at `maxLength` bits (128 KiB), the old drain-into-one-`Vec`
63
+ * approach failed on any blob larger than one chunk even when only metadata
64
+ * was asked for; streaming detection returns correct
65
+ * `{ length, mimeType, type[, uri] }` regardless of size. A dialect (e.g.
66
+ * `vnd.fjs.revision`, see `fjs/media/module.f.ts`) can only be recognized by
67
+ * parsing the whole blob as JSON, so when the streaming verdict is
68
+ * whole-blob-valid text within the same bounded inline cap as `content: true`
69
+ * (`maxLengthBytes`), one extra bounded read materializes the blob purely to
70
+ * refine `mimeType` through the dialect-aware detector; a larger or non-text
71
+ * blob is never a dialect match and is returned from the streaming verdict
72
+ * alone, unbuffered.
73
+ *
74
+ * **`content: true`** first derives `{ length, mimeType, type }` with the same
75
+ * size-independent `fjs/media/type` `detectStream` machine (to decide whether the
76
+ * blob even fits inline), then materializes the bytes (via `collectRead`, bounded
77
+ * by `maxLength`) and re-derives the verdict from the dialect-aware detector
78
+ * (`fjs/media/module.f.ts` `detect`) — now that the whole blob is in hand, a
79
+ * dialect match is reflected in the result — before encoding the inline payload
80
+ * by `type` — a `fjs/text/utf8` `fromVec` string on `text` (for `type: 'text'`),
81
+ * base64 on `blob` (for `type: 'base64'`). A blob larger than `maxLength` (128
82
+ * KiB) cannot be buffered into one `Vec`, so it is rejected here with a
83
+ * descriptive *"too large"* error (carrying the byte size and `uri`) rather than
84
+ * being misreported as absent; it should be fetched via `uri` or inspected with
85
+ * metadata-only `cas_get`.
86
+ *
87
+ * ## Encoding split: hashes vs. content
88
+ *
89
+ * `Cas<O>` deals in `Vec` (bit vectors); MCP models only `textContent` today.
90
+ * **Hashes** travel as cBase32 (`fjs/basen/cbase32`) — the canonical CAS hash format,
91
+ * shared with the CLI and the on-disk store layout. **Content** encoding is
92
+ * determined at read time as described above.
93
+ *
94
+ * ## Error convention
95
+ *
96
+ * MCP draws a line the dispatcher already respects: *protocol* failures
97
+ * (unknown method, malformed JSON-RPC params) are JSON-RPC errors handled by
98
+ * `mcpStep`. *Tool* failures come back as a normal `tools/call` result with
99
+ * `isError: true` and a text explanation, so the model can read and react:
100
+ * - `type: 'base64'` with malformed content (base64 `decode` → `null`) → `isError`
101
+ * - malformed `hash` (`cBase32ToVec` → `null`) → `isError`
102
+ * - `cas_get` on an absent hash (`c.read` → `undefined`) → `isError`
103
+ * - `cas_get` with `content: true` on a blob larger than `maxLength` → `isError`
104
+ * (distinct "too large" message, not "no such hash")
105
+ * - unknown tool `name` → `isError`
106
+ *
107
+ * @module
108
+ */
109
+ import { string, option, or, boolean } from '../../types/rtti/module.f.js';
110
+ import { stringify } from '../../media/json/module.f.js';
111
+ import { pure } from '../../effects/module.f.js';
112
+ import { create } from '../../effects/memory/module.f.js';
113
+ import { cBase32ToVec, vecToCBase32 } from '../../basen/cbase32/module.f.js';
114
+ import { decode as base64Decode, encode as base64Encode } from '../../basen/base64/module.f.js';
115
+ import { tryUtf8 } from '../../text/module.f.js';
116
+ import { detectStream } from '../../media/type/module.f.js';
117
+ import { detect as detectDialect } from '../../media/module.f.js';
118
+ import { maxLengthBytes } from '../../types/bit_vec/module.f.js';
119
+ import { ok, error } from '../../types/result/module.f.js';
120
+ import {} from '../../effects/node/module.f.js';
121
+ import { stdioTransport } from '../../mcp/stdio/module.f.js';
122
+ import { mcpStep, uninitializedState, toolEntry, fromRegistry, errorResult, okResult, } from '../../mcp/module.f.js';
123
+ import { collectRead, fileCas } from '../module.f.js';
124
+ import { fromVec } from '../../text/utf8/module.f.js';
125
+ import { identity } from '../../types/function/module.f.js';
126
+ import { sha256 } from '../../crypto/sha2/module.f.js';
127
+ import { nonEmpty, empty as elEmpty } from '../../effects/list/module.f.js';
128
+ import { initEvo, evo, syncRevision } from '../evo/module.f.js';
129
+ import { evoToolRegistry } from '../evo/mcp/module.f.js';
130
+ // ── Argument schemas (declared once, used for both inputSchema and validate) ─────
131
+ /** Arguments for `cas_add`: content to store, with optional encoding type. */
132
+ export const casAddArgs = {
133
+ content: string,
134
+ type: or('text', 'base64', undefined)
135
+ };
136
+ /** Arguments for `cas_get`: the cBase32 hash to look up; optionally request inline content. */
137
+ export const casGetArgs = {
138
+ hash: string,
139
+ content: option(boolean)
140
+ };
141
+ /** Arguments for `cas_list`: none. */
142
+ export const casListArgs = {};
143
+ // ── Tool registry ──────────────────────────────────────────────────────────────
144
+ const toJson = stringify(identity);
145
+ /**
146
+ * Registry of all CAS tools, bound to `home` and the Evo cache at
147
+ * `cacheKey`. `cas_add` is the only tool that writes, so it is the only one
148
+ * that needs `cacheKey`: a successfully stored blob is folded into the Evo
149
+ * cache via `syncRevision` when it happens to be a `vnd.fjs.revision` — a
150
+ * plain `cas_add` and `evo_add` are two ways to reach the same store, and
151
+ * this keeps `evo_list`/`evo_head` honest about either one without a
152
+ * rescan.
153
+ */
154
+ export const casToolRegistry = (home) => (cacheKey) => {
155
+ const c = fileCas(sha256)(home);
156
+ return [
157
+ toolEntry('cas_add', 'Store content and return its hash (cBase32). Pass type:"base64" for binary; omit or pass type:"text" for UTF-8 text (default). Inline content is capped at 128 KiB (131072 bytes) — larger content is rejected. For larger content, store the file with the `cas` CLI instead: run `npx functionalscript cas add <path>` yourself if you have shell access, or give the user that exact command to run — it prints the resulting hash on stdout.', casAddArgs, ({ type, content }) => {
158
+ // type:'text' or 'base64' — resolve content to Vec, store via c.write()
159
+ let x = type === 'base64'
160
+ ? base64Decode(content)
161
+ : tryUtf8(content);
162
+ return x === null
163
+ ? pure(errorResult('too large or malformed — for large content, run `npx functionalscript cas add <path>` (or have the user run it) instead'))
164
+ // The resolved content fits in one chunk; feed it as a single-item stream.
165
+ : c.write(nonEmpty(ok(x), elEmpty())).step((writeResult) => {
166
+ if (writeResult[0] === 'error') {
167
+ return pure(errorResult('write'));
168
+ }
169
+ const hash = writeResult[1];
170
+ return syncRevision(cacheKey)(hash)(x).step(() => pure(okResult(vecToCBase32(hash))));
171
+ });
172
+ }),
173
+ toolEntry('cas_get', 'Inspect a blob by hash. Always returns JSON {length,mimeType,type[,uri]} where type is "text" or "base64". Pass content:true to also include the inline payload as text (type:"text") or blob (type:"base64"), but content is capped at 128 KiB (131072 bytes) — a larger blob is rejected with an error. To download a blob, prefer the uri field returned in the result instead of requesting inline content.', casGetArgs, r => {
174
+ const key = cBase32ToVec(r.hash);
175
+ if (key === null) {
176
+ return pure(errorResult(`invalid cBase32 hash: ${r.hash}`));
177
+ }
178
+ const uri = c.url(key);
179
+ return detectStream(c.read(key)).step(([tag, detected]) => {
180
+ if (tag === 'error') {
181
+ return pure(errorResult(`no such hash: ${r.hash}`));
182
+ }
183
+ const { length, mime_type: mimeType, type } = detected;
184
+ const meta = { length: Number(length), mimeType, type, uri };
185
+ if (r.content !== true) {
186
+ // A dialect match can only be decided from the whole parsed blob;
187
+ // only attempt the extra bounded read when it stands a chance
188
+ // (whole-blob text within the same cap `content: true` allows).
189
+ if (type !== 'text' || length > maxLengthBytes) {
190
+ return pure(okResult(toJson(meta)));
191
+ }
192
+ return collectRead(c.read(key)).step(([collectTag, value]) => {
193
+ // Already known to fit from the streaming pass above, so an
194
+ // error here means the hash vanished between reads; fall back
195
+ // to the streaming verdict rather than fail the whole request.
196
+ if (collectTag === 'error') {
197
+ return pure(okResult(toJson(meta)));
198
+ }
199
+ const refined = detectDialect(value);
200
+ return pure(okResult(toJson({ ...meta, mimeType: refined.mime_type })));
201
+ });
202
+ }
203
+ // A single `Vec` caps at `maxLength` bits (`maxLengthBytes` bytes), so
204
+ // a larger blob cannot be buffered for inline transfer. Report the
205
+ // size and point at the size-independent alternatives instead of
206
+ // misreporting an existing blob as `no such hash`.
207
+ if (length > maxLengthBytes) {
208
+ return pure(errorResult(`blob too large to fetch inline (${length} bytes, limit ${maxLengthBytes} bytes); use the uri field (${uri}) or omit content for metadata`));
209
+ }
210
+ return collectRead(c.read(key)).step(([collectTag, value]) => {
211
+ if (collectTag === 'error') {
212
+ return pure(errorResult(`no such hash: ${r.hash}`));
213
+ }
214
+ // Re-derive the verdict from the now-materialized blob so a
215
+ // dialect match — only decidable with the whole parsed JSON in
216
+ // hand — is reflected in the inline result too, not just the
217
+ // streaming guess.
218
+ const refined = detectDialect(value);
219
+ const refinedMeta = { length: Number(refined.length), mimeType: refined.mime_type, type: refined.type, uri };
220
+ if (refined.type === 'text') {
221
+ // `type: 'text'` means the detector validated `value` as UTF-8,
222
+ // so `fromVec` is non-null here; guard defensively regardless.
223
+ const str = fromVec(value);
224
+ return pure(str === null
225
+ ? errorResult(`content is not byte-aligned: ${r.hash}`)
226
+ : okResult(toJson({ ...refinedMeta, text: str })));
227
+ }
228
+ const blob = base64Encode(value);
229
+ return pure(blob === null
230
+ ? errorResult(`content is not byte-aligned: ${r.hash}`)
231
+ : okResult(toJson({ ...refinedMeta, blob })));
232
+ });
233
+ });
234
+ }),
235
+ toolEntry('cas_list', 'List all stored content hashes (cBase32), one per line.', casListArgs, () => c.list().step(hashes => pure(okResult(hashes.map(vecToCBase32).join('\n'))))),
236
+ ];
237
+ };
238
+ // ── Handlers ────────────────────────────────────────────────────────────────────
239
+ /**
240
+ * MCP handlers for `FileCas` plus the Evo API (`fjs/cas/evo`) layered on it,
241
+ * bound to `home` and an already-built Evo cache slot (see `initEvo`).
242
+ */
243
+ export const casMcpHandlers = (home) => (cacheKey) => fromRegistry([...casToolRegistry(home)(cacheKey), ...evoToolRegistry(evo(fileCas(sha256)(home))(cacheKey))]);
244
+ // ── Session configuration ───────────────────────────────────────────────────────
245
+ /**
246
+ * Static MCP configuration for the CAS server: advertises the `tools`
247
+ * capability, identifies the server, and pins the protocol version.
248
+ */
249
+ export const casConfig = {
250
+ serverInfo: { name: 'functionalscript-cas', version: '0.30.0' },
251
+ capabilities: { tools: {} },
252
+ protocolVersion: '2024-11-05',
253
+ };
254
+ // ── Server ──────────────────────────────────────────────────────────────────────
255
+ /**
256
+ * Runs the combined CAS + Evo MCP server over stdio: scans `~/.cas/` once to
257
+ * build the Evo subject/head cache (`initEvo`), allocates the session-state
258
+ * slot, builds the `mcpStep` for the merged tool registry, and drives the
259
+ * read → parse → dispatch → write loop until stdin EOF.
260
+ */
261
+ export const casMcpServer = (home) => initEvo(fileCas(sha256)(home)).step(cacheKey => create(uninitializedState).step(sessionKey => stdioTransport(mcpStep(casConfig)(casMcpHandlers(home)(cacheKey))(sessionKey))));
262
+ // ── Tests ────────────────────────────────────────────────────────────────────
263
+ export const proof = {
264
+ // casMcpServer is never called in integration tests because it drives a
265
+ // real stdio server; call it here to cover its Effect-building body.
266
+ casMcpServer: () => { casMcpServer('/'); },
267
+ };
@@ -7,7 +7,10 @@ export declare const proof: {
7
7
  getContentBase64InflationOverflowWritesInternalError: () => void;
8
8
  getContentBase64NearBoundarySucceeds: () => void;
9
9
  getContentDoubleEscapedOverflowWritesInternalError: () => void;
10
- toolsListAdvertisesThreeTools: () => void;
10
+ toolsListAdvertisesSixTools: () => void;
11
+ evoAddListHeadRoundTripsThroughCasServer: () => void;
12
+ evoAddDomainErrorIsErrorThroughCasServer: () => void;
13
+ casAddSyncsEvoCacheForRevisionContent: () => void;
11
14
  addReturnsHash: () => void;
12
15
  textAddGetMetaRoundTrips: () => void;
13
16
  textAddGetContentRoundTrips: () => void;
@@ -16,13 +19,15 @@ export declare const proof: {
16
19
  addGetRoundTrips: () => void;
17
20
  getUntypedReturnsText: () => void;
18
21
  getTypedReturnsBinaryJson: () => void;
22
+ getMetaRecognizesRevisionDialect: () => void;
23
+ getContentRecognizesRevisionDialect: () => void;
19
24
  listEnumeratesStoredHashes: () => void;
20
25
  addInvalidContentIsError: () => void;
21
26
  addBadLengthContentIsError: () => void;
22
27
  addBase64OverLimitIsError: () => void;
23
28
  addTextOverLimitIsError: () => void;
24
29
  addTextAtLimitSucceeds: () => void;
25
- addBase64AtLimitIsError: () => void;
30
+ addBase64AtLimitSucceeds: () => void;
26
31
  getUnterminatedHashIsError: () => void;
27
32
  addMissingContentIsError: () => void;
28
33
  getMissingHashArgumentIsError: () => void;
@@ -1,20 +1,22 @@
1
- import { assert, assertEq } from "../../asserts/module.f.js";
2
- import { pure } from "../../effects/module.f.js";
3
- import { run } from "../../effects/mock/module.f.js";
4
- import { asBase, asNominal, create } from "../../effects/memory/module.f.js";
5
- import { msb, u8ListToVec, vec8, repeat, length, maxLengthBytes } from "../../types/bit_vec/module.f.js";
6
- import { vecToCBase32 } from "../../cbase32/module.f.js";
7
- import { encode as base64Encode } from "../../base64/module.f.js";
8
- import { utf8 } from "../../text/module.f.js";
9
- import { fileCas } from "../module.f.js";
10
- import { sha256 } from "../../crypto/sha2/module.f.js";
11
- import { nonEmpty, empty as elEmpty } from "../../effects/list/module.f.js";
12
- import { mcpStep, uninitializedState, } from "../../mcp/module.f.js";
13
- import { emptyState, virtual } from "../../effects/node/virtual/module.f.js";
14
- import { casConfig, casMcpHandlers } from "./module.f.js";
15
- import { ok as resultOk } from "../../types/result/module.f.js";
16
- import { stdioTransport } from "../../mcp/stdio/module.f.js";
17
- import { fromVec } from "../../types/uint8array/module.f.js";
1
+ import { assert, assertEq } from '../../asserts/module.f.js';
2
+ import { pure } from '../../effects/module.f.js';
3
+ import { run } from '../../effects/mock/module.f.js';
4
+ import { asBase, asNominal, create } from '../../effects/memory/module.f.js';
5
+ import { msb, u8ListToVec, vec8, repeat, length, maxLengthBytes } from '../../types/bit_vec/module.f.js';
6
+ import { vecToCBase32 } from '../../basen/cbase32/module.f.js';
7
+ import { encode as base64Encode } from '../../basen/base64/module.f.js';
8
+ import { utf8 } from '../../text/module.f.js';
9
+ import { fileCas } from '../module.f.js';
10
+ import { dialect as revisionDialect, mediaType as revisionMediaType } from '../../media/revision/module.f.js';
11
+ import { sha256 } from '../../crypto/sha2/module.f.js';
12
+ import { nonEmpty, empty as elEmpty } from '../../effects/list/module.f.js';
13
+ import { mcpStep, uninitializedState, } from '../../mcp/module.f.js';
14
+ import { emptyState, virtual } from '../../effects/node/virtual/module.f.js';
15
+ import { casConfig, casMcpHandlers } from './module.f.js';
16
+ import { ok as resultOk } from '../../types/result/module.f.js';
17
+ import { stdioTransport } from '../../mcp/stdio/module.f.js';
18
+ import { fromVec } from '../../types/uint8array/module.f.js';
19
+ import { initEvo } from '../evo/module.f.js';
18
20
  const initialTestState = { memory: { next: 0, values: {} } };
19
21
  const mock = {
20
22
  memCreate: value => state => {
@@ -55,10 +57,10 @@ const feed = (step) => (msgs) => {
55
57
  // Rename/ReadBytes/RandomInt/Mkdir). Uses fileKvStore so upload and get share
56
58
  // the same filesystem-backed CAS.
57
59
  const runSessionVirtual = (root, home = '/home/user') => (msgs) => {
58
- const effect = create(uninitializedState).step(sessionKey => {
59
- const step = mcpStep(casConfig)(casMcpHandlers(home))(sessionKey);
60
+ const effect = initEvo(fileCas(sha256)(home)).step(cacheKey => create(uninitializedState).step(sessionKey => {
61
+ const step = mcpStep(casConfig)(casMcpHandlers(home)(cacheKey))(sessionKey);
60
62
  return feed(step)(msgs);
61
- });
63
+ }));
62
64
  return virtual({ ...emptyState, root })(effect)[1];
63
65
  };
64
66
  // Seeds a blob directly into the virtual store via `c.write`, bypassing the
@@ -90,10 +92,10 @@ const toBytes = (s) => [...fromVec(utf8(s))];
90
92
  // `session`/`runSessionVirtual`, which collect `mcpStep`'s `Response` values
91
93
  // as plain JS objects and never serialize/encode them, this is the only
92
94
  // helper that can observe the transport's oversized-response fallback (see
93
- // `fs/mcp/stdio/module.f.ts` `writeResponse`).
95
+ // `fjs/mcp/stdio/module.f.ts` `writeResponse`).
94
96
  const runStdio = (root, home = '/home/user') => (msgs) => {
95
97
  const input = [init, initialized, ...msgs].map(m => JSON.stringify(m)).join('\n') + '\n';
96
- const effect = create(uninitializedState).step(sessionKey => stdioTransport(mcpStep(casConfig)(casMcpHandlers(home))(sessionKey)));
98
+ const effect = initEvo(fileCas(sha256)(home)).step(cacheKey => create(uninitializedState).step(sessionKey => stdioTransport(mcpStep(casConfig)(casMcpHandlers(home)(cacheKey))(sessionKey))));
97
99
  const stdout = virtual({ ...emptyState, root, stdin: toBytes(input) })(effect)[0].stdout;
98
100
  // Only requests get a written line (notifications, like `initialized`,
99
101
  // write nothing) — drop the `init` response, keep one line per `msgs` entry.
@@ -104,10 +106,13 @@ const item0 = (resp) => resultOf(resp).content[0];
104
106
  const textOf = (resp) => item0(resp).text;
105
107
  // A plain text sample for text add→get round-trips.
106
108
  const textSample = 'hello, world!';
109
+ // A valid `vnd.fjs.revision` blob: every required field present, including the
110
+ // explicit `snapshot` and `generation` the format now mandates.
111
+ const revisionSample = `{"dialect":"${revisionDialect}","subject":"8","parents":[],"snapshot":"8","generation":0}`;
107
112
  // A base64-encoded binary payload for binary add→get round-trips.
108
113
  const binarySample = base64Encode(vec8(0x2an));
109
114
  // A base64 blob whose leading bytes are the PNG magic-byte signature, so
110
- // `cas_get` detects its type and returns base64 with mime_type image/png.
115
+ // `cas_get` detects its type and returns base64 with mimeType image/png.
111
116
  const pngSample = base64Encode(u8ListToVec(msb)([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x01]));
112
117
  // Returns the RFC 4648 base64 encoding of `n` zero bytes, computed directly
113
118
  // without bigint arithmetic — independent of `base64.encode` so these tests
@@ -141,9 +146,10 @@ const largeMultiChunkBlobMeta = (chunk0, chunk1, expectedType, expectedMime) =>
141
146
  assert(!resultOf(metaResp).isError);
142
147
  const meta = JSON.parse(textOf(metaResp));
143
148
  assertEq(meta.type, expectedType);
144
- assertEq(meta.mime_type, expectedMime);
149
+ assertEq(meta.mimeType, expectedMime);
145
150
  assertEq(meta.length, Number((length(chunk0) + length(chunk1)) / 8n));
146
- assertEq(meta.content, undefined);
151
+ assertEq(meta.text, undefined);
152
+ assertEq(meta.blob, undefined);
147
153
  };
148
154
  // A full `maxLengthBytes`-long chunk of repeated ASCII 'a' — valid UTF-8.
149
155
  const asciiChunk = repeat(maxLengthBytes)(vec8(0x61n));
@@ -202,12 +208,12 @@ export const proof = {
202
208
  // the JSON-RPC envelope is even added. The transport's `writeResponse`
203
209
  // (`tryUtf8`) must catch this and write a JSON-RPC internal-error response —
204
210
  // carrying the *original request's* `id` — instead of crashing the process.
205
- // See `fs/mcp/stdio/module.f.ts` `writeResponse`.
211
+ // See `fjs/mcp/stdio/module.f.ts` `writeResponse`.
206
212
  //
207
213
  // This test originally timed out under `bun test`'s native 5s per-test
208
214
  // limit (12-14s observed in CI on PR #1201) — the cost was in
209
215
  // `base64Encode`, quadratic before the `baseN.vecToString` fix (see
210
- // `fs/base64/proof.f.ts` `encodeLargeVecIsSlow`). Now well under budget on
216
+ // `fjs/basen/base64/proof.f.ts` `encodeLargeVecIsSlow`). Now well under budget on
211
217
  // both engines.
212
218
  getContentBase64InflationOverflowWritesInternalError: () => {
213
219
  const [root, hash] = seedBlob({})([oversizedBase64Chunk]);
@@ -251,14 +257,41 @@ export const proof = {
251
257
  assertEq(err.error?.code, -32603);
252
258
  assertEq(err.id, 2);
253
259
  },
254
- toolsListAdvertisesThreeTools: () => {
260
+ toolsListAdvertisesSixTools: () => {
255
261
  const [resp] = runSessionVirtual({})([init, initialized, list(2)]).slice(2);
256
262
  const tools = resp.result.tools;
257
- assertEq(tools.length, 3);
258
- assertEq(tools.map(t => t.name).join(','), 'cas_add,cas_get,cas_list');
263
+ assertEq(tools.length, 6);
264
+ assertEq(tools.map(t => t.name).join(','), 'cas_add,cas_get,cas_list,evo_list,evo_head,evo_add');
259
265
  const add = resp.result.tools[0];
260
266
  assertEq(add.inputSchema.type, 'object');
261
267
  },
268
+ // The same server also exposes Evo (fjs/cas/evo): add a revision, then
269
+ // find it via evo_list/evo_head — one process, one store, one cache.
270
+ evoAddListHeadRoundTripsThroughCasServer: () => {
271
+ const [addResp, listResp, headResp] = session(call(2, 'evo_add', { parents: [], subject: 'doc', snapshot: vecToCBase32(vec8(0x1n)) }), call(3, 'evo_list', {}), call(4, 'evo_head', { subject: 'doc' }));
272
+ assert(!resultOf(addResp).isError);
273
+ const hash = textOf(addResp);
274
+ assert(hash.length > 0);
275
+ assertEq(textOf(listResp), '["doc"]');
276
+ assertEq(textOf(headResp), hash);
277
+ },
278
+ evoAddDomainErrorIsErrorThroughCasServer: () => {
279
+ // Valid arguments, but the domain rule fails: `subject` is required
280
+ // unless there is exactly one parent.
281
+ const [resp] = session(call(2, 'evo_add', { parents: [] }));
282
+ assertEq(resultOf(resp).isError, true);
283
+ assert(textOf(resp).includes('subject is required'));
284
+ },
285
+ // A plain `cas_add` of `vnd.fjs.revision` content is folded into the Evo
286
+ // cache too (`syncRevision`), not just `evo_add` — `cas_add`/`evo_add`
287
+ // are two ways to reach the same store and cache.
288
+ casAddSyncsEvoCacheForRevisionContent: () => {
289
+ const [addResp, listResp, headResp] = session(call(2, 'cas_add', { content: revisionSample }), call(3, 'evo_list', {}), call(4, 'evo_head', { subject: '8' }));
290
+ assert(!resultOf(addResp).isError);
291
+ const hash = textOf(addResp);
292
+ assertEq(textOf(listResp), '["8"]');
293
+ assertEq(textOf(headResp), hash);
294
+ },
262
295
  addReturnsHash: () => {
263
296
  const [resp] = session(call(2, 'cas_add', { content: textSample }));
264
297
  assert(!resultOf(resp).isError);
@@ -271,10 +304,10 @@ export const proof = {
271
304
  const [, getResp] = session(call(2, 'cas_add', { content: textSample }), call(3, 'cas_get', { hash }));
272
305
  assert(!resultOf(getResp).isError);
273
306
  const result = JSON.parse(textOf(getResp));
274
- assertEq(result.mime_type, 'text/plain');
307
+ assertEq(result.mimeType, 'text/plain');
275
308
  assertEq(result.type, 'text');
276
309
  assertEq(result.length, textSample.length);
277
- assertEq(result.content, undefined);
310
+ assertEq(result.text, undefined);
278
311
  },
279
312
  // cas_get with content:true returns inline content.
280
313
  textAddGetContentRoundTrips: () => {
@@ -284,8 +317,8 @@ export const proof = {
284
317
  assert(!resultOf(getResp).isError);
285
318
  const result = JSON.parse(textOf(getResp));
286
319
  assertEq(result.type, 'text');
287
- assertEq(result.mime_type, 'text/plain');
288
- assertEq(result.content, textSample);
320
+ assertEq(result.mimeType, 'text/plain');
321
+ assertEq(result.text, textSample);
289
322
  },
290
323
  // Binary add→get round-trip: store as base64, retrieve metadata without content.
291
324
  binaryAddGetMetaRoundTrips: () => {
@@ -294,9 +327,9 @@ export const proof = {
294
327
  const [, getResp] = session(call(2, 'cas_add', { content: binarySample, type: 'base64' }), call(3, 'cas_get', { hash }));
295
328
  assert(!resultOf(getResp).isError);
296
329
  const result = JSON.parse(textOf(getResp));
297
- assertEq(result.content, undefined);
330
+ assertEq(result.text, undefined);
298
331
  assertEq(result.type, 'text');
299
- assertEq(result.mime_type, 'text/plain');
332
+ assertEq(result.mimeType, 'text/plain');
300
333
  },
301
334
  // Binary add→get with content:true returns inline base64 content.
302
335
  binaryAddGetContentRoundTrips: () => {
@@ -306,7 +339,7 @@ export const proof = {
306
339
  assert(!resultOf(getResp).isError);
307
340
  const result = JSON.parse(textOf(getResp));
308
341
  assertEq(result.type, 'text');
309
- assertEq(result.content, '*');
342
+ assertEq(result.text, '*');
310
343
  },
311
344
  addGetRoundTrips: () => {
312
345
  const [addResp] = session(call(2, 'cas_add', { content: textSample }));
@@ -314,7 +347,7 @@ export const proof = {
314
347
  const [, getResp] = session(call(2, 'cas_add', { content: textSample }), call(3, 'cas_get', { hash, content: true }));
315
348
  assert(!resultOf(getResp).isError);
316
349
  const result = JSON.parse(textOf(getResp));
317
- assertEq(result.content, textSample);
350
+ assertEq(result.text, textSample);
318
351
  },
319
352
  // Text content (no magic-byte match, valid UTF-8) comes back with type:'text' when content requested.
320
353
  getUntypedReturnsText: () => {
@@ -324,9 +357,9 @@ export const proof = {
324
357
  assertEq(item0(getResp) === null ? null : item0(getResp).type, 'text');
325
358
  const result = JSON.parse(textOf(getResp));
326
359
  assertEq(result.type, 'text');
327
- assertEq(result.mime_type, 'text/plain');
360
+ assertEq(result.mimeType, 'text/plain');
328
361
  },
329
- // Bytes with a recognised PNG signature come back as base64 with mime_type image/png when content requested.
362
+ // Bytes with a recognised PNG signature come back as base64 with mimeType image/png when content requested.
330
363
  getTypedReturnsBinaryJson: () => {
331
364
  const [addResp] = session(call(2, 'cas_add', { content: pngSample, type: 'base64' }));
332
365
  const hash = textOf(addResp);
@@ -335,8 +368,33 @@ export const proof = {
335
368
  assertEq(item0(getResp).type, 'text');
336
369
  const result = JSON.parse(textOf(getResp));
337
370
  assertEq(result.type, 'base64');
338
- assertEq(result.mime_type, 'image/png');
339
- assertEq(result.content, pngSample);
371
+ assertEq(result.mimeType, 'image/png');
372
+ assertEq(result.blob, pngSample);
373
+ },
374
+ // A stored `vnd.fjs.revision` blob is recognized by metadata-only
375
+ // `cas_get` (content:false, the default) — the CAS read path routes the
376
+ // bounded, whole-blob-text case through the dialect-aware detector rather
377
+ // than only reporting the streaming text/plain verdict.
378
+ getMetaRecognizesRevisionDialect: () => {
379
+ const [addResp] = session(call(2, 'cas_add', { content: revisionSample }));
380
+ const hash = textOf(addResp);
381
+ const [, metaResp] = session(call(2, 'cas_add', { content: revisionSample }), call(3, 'cas_get', { hash }));
382
+ assert(!resultOf(metaResp).isError);
383
+ const meta = JSON.parse(textOf(metaResp));
384
+ assertEq(meta.mimeType, revisionMediaType);
385
+ assertEq(meta.type, 'text');
386
+ },
387
+ // Same dialect recognition on the `content: true` path, alongside the
388
+ // inline text payload.
389
+ getContentRecognizesRevisionDialect: () => {
390
+ const [addResp] = session(call(2, 'cas_add', { content: revisionSample }));
391
+ const hash = textOf(addResp);
392
+ const [, getResp] = session(call(2, 'cas_add', { content: revisionSample }), call(3, 'cas_get', { hash, content: true }));
393
+ assert(!resultOf(getResp).isError);
394
+ const result = JSON.parse(textOf(getResp));
395
+ assertEq(result.mimeType, revisionMediaType);
396
+ assertEq(result.type, 'text');
397
+ assertEq(result.text, revisionSample);
340
398
  },
341
399
  listEnumeratesStoredHashes: () => {
342
400
  const [addResp, listResp] = session(call(2, 'cas_add', { content: textSample }), call(3, 'cas_list', {}));
@@ -375,16 +433,14 @@ export const proof = {
375
433
  assert(!resultOf(resp).isError);
376
434
  assert(textOf(resp).length > 0);
377
435
  },
378
- // base64 of exactly maxLengthBytes — currently returns isError because
379
- // base64Decode measures the raw pre-trim body (1_048_578 bits) against
380
- // maxLength before stripping the 2 padding bits that would land it exactly at
381
- // maxLength. Assert the current failing behavior; flip to a success assertion
382
- // once `fs/base64/todo/decode-rejects-max-size-input.md` is fixed.
383
- addBase64AtLimitIsError: () => {
436
+ // base64 of exactly maxLengthBytes — base64Decode trims the encoding's
437
+ // padding bits from the last character before measuring the result
438
+ // against maxLength, so a payload landing exactly at the limit decodes
439
+ // and stores cleanly.
440
+ addBase64AtLimitSucceeds: () => {
384
441
  const [resp] = session(call(2, 'cas_add', { content: base64OfA(maxLengthBytes), type: 'base64' }));
385
- assertEq(resultOf(resp).isError, true);
386
- assert(textOf(resp).includes('too large or malformed'));
387
- assert(textOf(resp).includes('cas add'));
442
+ assert(!resultOf(resp).isError);
443
+ assert(textOf(resp).length > 0);
388
444
  },
389
445
  getUnterminatedHashIsError: () => {
390
446
  const [resp] = session(call(2, 'cas_get', { hash: '0' }));
@@ -423,10 +479,10 @@ export const proof = {
423
479
  const [, metaResp] = session(call(2, 'cas_add', { content: 'text content' }), call(3, 'cas_get', { hash }));
424
480
  assert(!resultOf(metaResp).isError);
425
481
  const meta = JSON.parse(textOf(metaResp));
426
- assertEq(meta.mime_type, 'text/plain');
482
+ assertEq(meta.mimeType, 'text/plain');
427
483
  assertEq(meta.type, 'text');
428
484
  assertEq(meta.length, 12);
429
- assertEq(meta.content, undefined);
485
+ assertEq(meta.text, undefined);
430
486
  },
431
487
  getMetaBinaryBlob: () => {
432
488
  const [addResp] = session(call(2, 'cas_add', { content: pngSample, type: 'base64' }));
@@ -434,10 +490,10 @@ export const proof = {
434
490
  const [, metaResp] = session(call(2, 'cas_add', { content: pngSample, type: 'base64' }), call(3, 'cas_get', { hash }));
435
491
  assert(!resultOf(metaResp).isError);
436
492
  const meta = JSON.parse(textOf(metaResp));
437
- assertEq(meta.mime_type, 'image/png');
493
+ assertEq(meta.mimeType, 'image/png');
438
494
  assertEq(meta.type, 'base64');
439
495
  assertEq(meta.length, 10);
440
- assertEq(meta.content, undefined);
496
+ assertEq(meta.blob, undefined);
441
497
  },
442
498
  getMetaOctetStreamForUnknownBinary: () => {
443
499
  const binaryContent = u8ListToVec(msb)([0xFF, 0xFE, 0x00, 0x01]);
@@ -447,9 +503,9 @@ export const proof = {
447
503
  const [, metaResp] = session(call(2, 'cas_add', { content: binaryB64, type: 'base64' }), call(3, 'cas_get', { hash }));
448
504
  assert(!resultOf(metaResp).isError);
449
505
  const meta = JSON.parse(textOf(metaResp));
450
- assertEq(meta.mime_type, 'application/octet-stream');
506
+ assertEq(meta.mimeType, 'application/octet-stream');
451
507
  assertEq(meta.type, 'base64');
452
- assertEq(meta.content, undefined);
508
+ assertEq(meta.blob, undefined);
453
509
  },
454
510
  // A NUL-bearing blob is valid UTF-8 yet binary: cas_get must report
455
511
  // base64/octet-stream, not text/plain.
@@ -461,7 +517,7 @@ export const proof = {
461
517
  const [, metaResp] = session(call(2, 'cas_add', { content: nulB64, type: 'base64' }), call(3, 'cas_get', { hash }));
462
518
  assert(!resultOf(metaResp).isError);
463
519
  const meta = JSON.parse(textOf(metaResp));
464
- assertEq(meta.mime_type, 'application/octet-stream');
520
+ assertEq(meta.mimeType, 'application/octet-stream');
465
521
  assertEq(meta.type, 'base64');
466
522
  },
467
523
  getMetaMissingHashIsError: () => {
@@ -482,8 +538,8 @@ export const proof = {
482
538
  const [, getResp] = session(call(2, 'cas_add', { content: binaryB64, type: 'base64' }), call(3, 'cas_get', { hash, content: true }));
483
539
  assert(!resultOf(getResp).isError);
484
540
  const result = JSON.parse(textOf(getResp));
485
- assertEq(result.mime_type, 'application/octet-stream');
541
+ assertEq(result.mimeType, 'application/octet-stream');
486
542
  assertEq(result.type, 'base64');
487
- assertEq(result.content, binaryB64);
543
+ assertEq(result.blob, binaryB64);
488
544
  },
489
545
  };