functionalscript 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/fjs/asn.1/module.f.mjs +8 -1
- package/fjs/asn.1/proof.f.d.mts +10 -0
- package/fjs/asn.1/proof.f.mjs +16 -0
- package/fjs/basen/base128/module.f.mjs +22 -5
- package/fjs/bnf/data/module.f.d.mts +32 -6
- package/fjs/bnf/data/module.f.mjs +112 -7
- package/fjs/bnf/data/proof.f.d.mts +2 -0
- package/fjs/bnf/data/proof.f.mjs +74 -3
- package/fjs/bnf/data/types.d.ts +20 -2
- package/fjs/bnf/descent/module.f.d.mts +28 -14
- package/fjs/bnf/descent/module.f.mjs +122 -77
- package/fjs/bnf/descent/proof.f.d.mts +2 -0
- package/fjs/bnf/descent/proof.f.mjs +117 -31
- package/fjs/bnf/descent/types.d.ts +12 -14
- package/fjs/bnf/ll1/module.f.d.mts +64 -22
- package/fjs/bnf/ll1/module.f.mjs +214 -154
- package/fjs/bnf/ll1/proof.f.d.mts +15 -2
- package/fjs/bnf/ll1/proof.f.mjs +323 -149
- package/fjs/bnf/ll1/types.d.ts +16 -24
- package/fjs/bnf/matcher/module.f.d.mts +66 -0
- package/fjs/bnf/matcher/module.f.mjs +81 -0
- package/fjs/bnf/matcher/proof.f.d.mts +10 -0
- package/fjs/bnf/matcher/proof.f.mjs +79 -0
- package/fjs/bnf/matcher/types.d.ts +54 -0
- package/fjs/bnf/testlib.f.d.mts +31 -0
- package/fjs/bnf/testlib.f.mjs +80 -0
- package/fjs/cas/cli/module.f.d.mts +1 -1
- package/fjs/cas/cli/module.f.mjs +14 -20
- package/fjs/cas/cli/proof.f.d.mts +1 -3
- package/fjs/cas/cli/proof.f.mjs +44 -33
- package/fjs/cas/evo/module.f.d.mts +64 -18
- package/fjs/cas/evo/module.f.mjs +148 -70
- package/fjs/cas/evo/proof.f.d.mts +10 -1
- package/fjs/cas/evo/proof.f.mjs +305 -223
- package/fjs/cas/evo/types.d.ts +45 -9
- package/fjs/cas/module.f.d.mts +18 -32
- package/fjs/cas/module.f.mjs +129 -128
- package/fjs/cas/proof.f.d.mts +11 -8
- package/fjs/cas/proof.f.mjs +259 -147
- package/fjs/cas/types.d.ts +24 -10
- package/fjs/ci/config/module.f.d.mts +2 -2
- package/fjs/ci/config/module.f.mjs +2 -2
- package/fjs/ci/module.f.d.mts +5 -5
- package/fjs/ci/module.f.mjs +8 -7
- package/fjs/ci/nix/module.f.d.mts +7 -5
- package/fjs/ci/nix/module.f.mjs +13 -12
- package/fjs/ci/nix/proof.f.mjs +2 -2
- package/fjs/ci/proof.f.mjs +9 -5
- package/fjs/cli/module.f.d.mts +4 -6
- package/fjs/cli/module.f.mjs +4 -8
- package/fjs/cli/proof.f.mjs +17 -16
- package/fjs/cli/types.d.ts +2 -3
- package/fjs/common/monoid/types.d.ts +1 -1
- package/fjs/crypto/hmac/module.f.mjs +2 -2
- package/fjs/crypto/sha2/module.f.mjs +3 -1
- package/fjs/crypto/sha2/proof.f.d.mts +1 -0
- package/fjs/crypto/sha2/proof.f.mjs +24 -0
- package/fjs/crypto/sha2/types.d.ts +11 -0
- package/fjs/crypto/sign/module.f.mjs +2 -2
- package/fjs/dev/module.f.d.mts +13 -4
- package/fjs/dev/module.f.mjs +56 -27
- package/fjs/dev/update/module.f.d.mts +9 -4
- package/fjs/dev/update/module.f.mjs +14 -10
- package/fjs/dev/update/proof.f.d.mts +1 -3
- package/fjs/dev/update/proof.f.mjs +10 -5
- package/fjs/djs/module.f.d.mts +13 -5
- package/fjs/djs/module.f.mjs +31 -16
- package/fjs/djs/parser/module.f.d.mts +13 -3
- package/fjs/djs/parser/module.f.mjs +117 -16
- package/fjs/djs/parser/proof.f.d.mts +5 -1
- package/fjs/djs/parser/proof.f.mjs +274 -12
- package/fjs/djs/parser/types.d.ts +7 -1
- package/fjs/djs/proof.f.d.mts +18 -2
- package/fjs/djs/proof.f.mjs +187 -12
- package/fjs/djs/serializer/module.f.d.mts +25 -8
- package/fjs/djs/serializer/module.f.mjs +61 -15
- package/fjs/djs/serializer/proof.f.d.mts +5 -0
- package/fjs/djs/serializer/proof.f.mjs +23 -1
- package/fjs/djs/tokenizer/module.f.d.mts +17 -5
- package/fjs/djs/tokenizer/module.f.mjs +99 -60
- package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
- package/fjs/djs/tokenizer/proof.f.mjs +74 -67
- package/fjs/djs/transpiler/module.f.d.mts +12 -7
- package/fjs/djs/transpiler/module.f.mjs +82 -56
- package/fjs/djs/transpiler/types.d.ts +7 -3
- package/fjs/djs/types.d.ts +7 -1
- package/fjs/effects/list/module.f.d.mts +14 -11
- package/fjs/effects/list/module.f.mjs +13 -11
- package/fjs/effects/list/types.d.ts +27 -7
- package/fjs/effects/memory/module.f.d.mts +2 -1
- package/fjs/effects/memory/module.f.mjs +3 -4
- package/fjs/effects/memory/proof.f.mjs +13 -7
- package/fjs/effects/memory/types.d.ts +4 -3
- package/fjs/effects/mock/module.f.d.mts +20 -4
- package/fjs/effects/mock/module.f.mjs +37 -5
- package/fjs/effects/mock/types.d.ts +10 -1
- package/fjs/effects/module.d.mts +4 -2
- package/fjs/effects/module.f.d.mts +466 -280
- package/fjs/effects/module.f.mjs +537 -299
- package/fjs/effects/module.mjs +2 -1
- package/fjs/effects/node/memory/module.d.mts +4 -2
- package/fjs/effects/node/memory/module.mjs +6 -3
- package/fjs/effects/node/memory/proof.mjs +10 -4
- package/fjs/effects/node/module.d.mts +4 -3
- package/fjs/effects/node/module.f.d.mts +168 -33
- package/fjs/effects/node/module.f.mjs +256 -52
- package/fjs/effects/node/module.mjs +57 -34
- package/fjs/effects/node/proof.f.d.mts +28 -2
- package/fjs/effects/node/proof.f.mjs +161 -42
- package/fjs/effects/node/types.d.ts +106 -18
- package/fjs/effects/node/virtual/module.f.d.mts +18 -4
- package/fjs/effects/node/virtual/module.f.mjs +110 -68
- package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
- package/fjs/effects/node/virtual/proof.f.mjs +190 -9
- package/fjs/effects/proof.f.d.mts +69 -37
- package/fjs/effects/proof.f.mjs +410 -130
- package/fjs/effects/types.d.ts +161 -33
- package/fjs/emergent_testing/module.f.d.mts +19 -12
- package/fjs/emergent_testing/module.f.mjs +93 -33
- package/fjs/emergent_testing/proof.f.d.mts +21 -7
- package/fjs/emergent_testing/proof.f.mjs +166 -32
- package/fjs/emergent_testing/types.d.ts +22 -4
- package/fjs/fsm/module.f.d.mts +14 -4
- package/fjs/fsm/module.f.mjs +54 -37
- package/fjs/fsm/proof.f.d.mts +2 -0
- package/fjs/fsm/proof.f.mjs +83 -114
- package/fjs/js/keywords/module.f.d.mts +52 -0
- package/fjs/js/keywords/module.f.mjs +72 -0
- package/fjs/js/keywords/proof.f.d.mts +3 -0
- package/fjs/js/keywords/proof.f.mjs +13 -0
- package/fjs/js/tokenizer/module.f.d.mts +26 -6
- package/fjs/js/tokenizer/module.f.mjs +145 -159
- package/fjs/js/tokenizer/proof.f.d.mts +1 -0
- package/fjs/js/tokenizer/proof.f.mjs +54 -24
- package/fjs/js/tokenizer/types.d.ts +33 -24
- package/fjs/mcp/cas/module.f.d.mts +1 -6
- package/fjs/mcp/cas/module.f.mjs +55 -51
- package/fjs/mcp/cas/proof.f.d.mts +15 -0
- package/fjs/mcp/cas/proof.f.mjs +174 -0
- package/fjs/mcp/evo/module.f.d.mts +19 -10
- package/fjs/mcp/evo/module.f.mjs +48 -27
- package/fjs/mcp/evo/proof.f.d.mts +6 -1
- package/fjs/mcp/evo/proof.f.mjs +115 -31
- package/fjs/mcp/module.f.d.mts +4 -4
- package/fjs/mcp/module.f.mjs +6 -6
- package/fjs/mcp/proof.f.d.mts +5 -3
- package/fjs/mcp/proof.f.mjs +112 -46
- package/fjs/media/html/module.f.mjs +1 -1
- package/fjs/media/json/extended/module.f.d.mts +82 -0
- package/fjs/media/json/extended/module.f.mjs +153 -0
- package/fjs/media/json/extended/proof.f.d.mts +42 -0
- package/fjs/media/json/extended/proof.f.mjs +127 -0
- package/fjs/media/json/extended/types.d.ts +23 -0
- package/fjs/media/json/module.f.d.mts +8 -2
- package/fjs/media/json/module.f.mjs +43 -41
- package/fjs/media/json/number/module.f.d.mts +59 -0
- package/fjs/media/json/number/module.f.mjs +136 -0
- package/fjs/media/json/number/proof.f.d.mts +24 -0
- package/fjs/media/json/number/proof.f.mjs +86 -0
- package/fjs/media/json/number/types.d.ts +28 -0
- package/fjs/media/json/parser/module.f.d.mts +25 -13
- package/fjs/media/json/parser/module.f.mjs +114 -70
- package/fjs/media/json/parser/proof.f.d.mts +5 -0
- package/fjs/media/json/parser/proof.f.mjs +31 -1
- package/fjs/media/json/parser/types.d.ts +33 -14
- package/fjs/media/json/rtti/module.f.d.mts +1 -1
- package/fjs/media/json/rtti/module.f.mjs +1 -1
- package/fjs/media/json/rtti/proof.f.mjs +9 -9
- package/fjs/media/json/schema/module.f.mjs +3 -13
- package/fjs/media/json/schema/proof.f.d.mts +0 -1
- package/fjs/media/json/schema/proof.f.mjs +1 -2
- package/fjs/media/json/serializer/module.f.d.mts +32 -1
- package/fjs/media/json/serializer/module.f.mjs +64 -2
- package/fjs/media/json/tokenizer/module.f.mjs +7 -3
- package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
- package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
- package/fjs/media/json/types.d.ts +36 -10
- package/fjs/media/lock/module.f.d.mts +100 -0
- package/fjs/media/lock/module.f.mjs +125 -0
- package/fjs/media/lock/proof.f.d.mts +33 -0
- package/fjs/media/lock/proof.f.mjs +196 -0
- package/fjs/media/lock/types.d.ts +15 -0
- package/fjs/media/module.f.d.mts +6 -5
- package/fjs/media/module.f.mjs +8 -7
- package/fjs/media/note/module.f.d.mts +121 -0
- package/fjs/media/note/module.f.mjs +131 -0
- package/fjs/media/note/proof.f.d.mts +29 -0
- package/fjs/media/note/proof.f.mjs +150 -0
- package/fjs/media/note/types.d.ts +10 -0
- package/fjs/media/proof.f.d.mts +4 -1
- package/fjs/media/proof.f.mjs +40 -21
- package/fjs/media/revision/module.f.d.mts +78 -7
- package/fjs/media/revision/module.f.mjs +119 -12
- package/fjs/media/revision/proof.f.d.mts +10 -0
- package/fjs/media/revision/proof.f.mjs +88 -0
- package/fjs/media/revision/types.d.ts +34 -5
- package/fjs/media/type/module.f.d.mts +33 -15
- package/fjs/media/type/module.f.mjs +35 -29
- package/fjs/media/type/proof.f.d.mts +2 -1
- package/fjs/media/type/proof.f.mjs +30 -10
- package/fjs/module.f.mjs +29 -8
- package/fjs/nanvm/proof.f.mjs +3 -3
- package/fjs/nanvm/rust/module.f.mjs +1 -1
- package/fjs/nanvm/update/module.f.d.mts +4 -4
- package/fjs/nanvm/update/module.f.mjs +8 -9
- package/fjs/nanvm/update/proof.f.mjs +4 -3
- package/fjs/proof.f.d.mts +3 -3
- package/fjs/proof.f.mjs +36 -10
- package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
- package/fjs/protocol/json_rpc/module.f.mjs +3 -3
- package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
- package/fjs/protocol/mcp/module.f.d.mts +10 -13
- package/fjs/protocol/mcp/module.f.mjs +74 -58
- package/fjs/protocol/mcp/proof.f.d.mts +13 -4
- package/fjs/protocol/mcp/proof.f.mjs +193 -61
- package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
- package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
- package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
- package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
- package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
- package/fjs/protocol/mcp/types.d.ts +17 -6
- package/fjs/sul/id/module.f.d.mts +0 -1
- package/fjs/sul/id/module.f.mjs +2 -3
- package/fjs/sul/level/hash/module.f.mjs +2 -1
- package/fjs/sul/level/hash/proof.f.mjs +2 -2
- package/fjs/sul/module.f.mjs +18 -13
- package/fjs/text/code_point/module.f.d.mts +8 -0
- package/fjs/text/code_point/module.f.mjs +8 -1
- package/fjs/text/code_point/proof.f.d.mts +1 -0
- package/fjs/text/code_point/proof.f.mjs +11 -0
- package/fjs/text/sgr/module.f.d.mts +4 -6
- package/fjs/text/sgr/module.f.mjs +6 -7
- package/fjs/text/utf16/module.f.mjs +7 -2
- package/fjs/text/utf16/proof.f.mjs +3 -3
- package/fjs/text/utf8/module.f.mjs +4 -2
- package/fjs/types/array/module.f.mjs +14 -2
- package/fjs/types/bit_vec/module.f.d.mts +0 -2
- package/fjs/types/bit_vec/module.f.mjs +46 -32
- package/fjs/types/bit_vec/proof.f.mjs +2 -2
- package/fjs/types/btree/remove/module.f.mjs +1 -1
- package/fjs/types/btree/set/module.f.mjs +9 -11
- package/fjs/types/btree/set/proof.f.mjs +12 -0
- package/fjs/types/byte_set/module.f.d.mts +11 -4
- package/fjs/types/byte_set/module.f.mjs +14 -6
- package/fjs/types/byte_set/proof.f.mjs +7 -7
- package/fjs/types/function/compare/module.f.mjs +10 -3
- package/fjs/types/list/module.f.d.mts +1 -1
- package/fjs/types/list/module.f.mjs +1 -1
- package/fjs/types/nullable/module.f.d.mts +18 -4
- package/fjs/types/nullable/module.f.mjs +21 -4
- package/fjs/types/nullable/proof.f.d.mts +4 -0
- package/fjs/types/nullable/proof.f.mjs +15 -0
- package/fjs/types/object/module.f.d.mts +12 -2
- package/fjs/types/object/module.f.mjs +11 -1
- package/fjs/types/patricia_trie/module.f.mjs +26 -11
- package/fjs/types/result/module.f.d.mts +3 -3
- package/fjs/types/result/module.f.mjs +3 -3
- package/fjs/types/rtti/common/module.f.d.mts +25 -28
- package/fjs/types/rtti/common/module.f.mjs +36 -32
- package/fjs/types/rtti/common/proof.f.mjs +5 -5
- package/fjs/types/rtti/data/module.f.d.mts +14 -0
- package/fjs/types/rtti/data/module.f.mjs +25 -2
- package/fjs/types/rtti/data/proof.f.d.mts +1 -0
- package/fjs/types/rtti/data/proof.f.mjs +25 -2
- package/fjs/types/rtti/parse/module.f.d.mts +24 -14
- package/fjs/types/rtti/parse/module.f.mjs +37 -28
- package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
- package/fjs/types/rtti/parse/proof.f.mjs +33 -14
- package/fjs/types/rtti/proof.f.mjs +3 -1
- package/fjs/types/rtti/ts/module.f.mjs +13 -17
- package/fjs/types/rtti/ts/types.d.ts +14 -1
- package/fjs/types/sorted_set/module.f.d.mts +18 -0
- package/fjs/types/sorted_set/module.f.mjs +22 -0
- package/fjs/types/sorted_set/proof.f.d.mts +1 -0
- package/fjs/types/sorted_set/proof.f.mjs +16 -1
- package/fjs/types/uint8array/module.f.d.mts +1 -1
- package/fjs/types/uint8array/module.f.mjs +1 -1
- package/fjs/website/module.f.d.mts +3 -3
- package/fjs/website/module.f.mjs +4 -7
- package/fjs/website/proof.f.mjs +2 -1
- package/package.json +2 -2
- package/fjs/dev/package_json/module.f.d.mts +0 -39
- package/fjs/dev/package_json/module.f.mjs +0 -40
- package/fjs/dev/package_json/proof.f.d.mts +0 -6
- package/fjs/dev/package_json/proof.f.mjs +0 -32
- package/fjs/effects/eff/module.f.d.mts +0 -20
- package/fjs/effects/eff/module.f.mjs +0 -70
- package/fjs/effects/eff/proof.f.d.mts +0 -15
- package/fjs/effects/eff/proof.f.mjs +0 -69
- package/fjs/effects/eff/types.d.ts +0 -71
- package/fjs/types/rtti/validate/module.f.d.mts +0 -41
- package/fjs/types/rtti/validate/module.f.mjs +0 -171
- package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
- package/fjs/types/rtti/validate/proof.f.mjs +0 -437
- package/fjs/types/rtti/validate/types.d.ts +0 -6
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import { Effect } from '../../effects/types.ts'
|
|
3
|
+
* @import { Result } from '../../types/result/types.ts'
|
|
4
|
+
* @import { FileCasOperation } from '../../cas/types.ts'
|
|
5
|
+
* @import { MemOp } from '../../effects/memory/types.ts'
|
|
6
|
+
* @import { Cache } from '../../cas/evo/types.ts'
|
|
7
|
+
* @import { Key } from '../../effects/memory/types.ts'
|
|
8
|
+
* @import { ToolsCallResult } from '../../protocol/mcp/types.ts'
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { casToolRegistry } from './module.f.mjs'
|
|
12
|
+
import { match } from '../../effects/module.f.mjs'
|
|
13
|
+
import { error, ok } from '../../types/result/module.f.mjs'
|
|
14
|
+
import { ioError } from '../../effects/node/module.f.mjs'
|
|
15
|
+
import { vec, vec8 } from '../../types/bit_vec/module.f.mjs'
|
|
16
|
+
import { vecToCBase32 } from '../../basen/cbase32/module.f.mjs'
|
|
17
|
+
import { assert, assertEq } from '../../asserts/module.f.mjs'
|
|
18
|
+
import { number as rttiNumber, string as rttiString } from '../../types/rtti/module.f.mjs'
|
|
19
|
+
import { parse as rttiParse } from '../../types/rtti/parse/module.f.mjs'
|
|
20
|
+
import { unwrap } from '../../types/result/module.f.mjs'
|
|
21
|
+
import { parse as parseJson } from '../../media/json/module.f.mjs'
|
|
22
|
+
|
|
23
|
+
// A harmless "always succeeds" response for a command, used by `drive` once a
|
|
24
|
+
// test's overrides for that command are exhausted — same technique as
|
|
25
|
+
// `fjs/cas/proof.f.mjs`'s `drive`, extended with `MemOp` since `cas_add` also
|
|
26
|
+
// touches the Evo cache on its success path.
|
|
27
|
+
/** @type {(cmd: string) => unknown} */
|
|
28
|
+
const defaultResponse = cmd => {
|
|
29
|
+
switch (cmd) {
|
|
30
|
+
case 'now': return ok(0)
|
|
31
|
+
case 'randomInt': return ok(0)
|
|
32
|
+
case 'mkdir': case 'createExclusive': case 'rename': case 'rm':
|
|
33
|
+
case 'writeBytes': case 'access':
|
|
34
|
+
return ok(undefined)
|
|
35
|
+
case 'readdir': return ok(/** @type {readonly unknown[]} */ ([]))
|
|
36
|
+
case 'stat': return ok({ size: 0 })
|
|
37
|
+
// An empty chunk reads as end-of-stream, so a `readBytes` call with no
|
|
38
|
+
// override reads as an immediately-empty file by default.
|
|
39
|
+
case 'readBytes': return ok(vec(0n)(0n))
|
|
40
|
+
case 'memCreate': return ok(/** @type {unknown} */ ('mem-key'))
|
|
41
|
+
case 'memRead': return ok(undefined)
|
|
42
|
+
case 'memWrite': return ok(undefined)
|
|
43
|
+
default: return ok(undefined)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Drives a `FileCasOperation | MemOp` effect to completion with synthetic op
|
|
49
|
+
* responses instead of a filesystem. `overrides[cmd]` is a queue consumed in
|
|
50
|
+
* call order; once a command's queue is empty (or was never given),
|
|
51
|
+
* `defaultResponse` supplies an always-succeeds value.
|
|
52
|
+
*
|
|
53
|
+
* `cas_add`'s write-failure branch and `cas_get`'s "hash vanished between
|
|
54
|
+
* reads" branches are real only under a race (a failing disk, a concurrent
|
|
55
|
+
* writer, a GC sweep) between two of the tool's own steps — the same shape of
|
|
56
|
+
* branch `fjs/cas/proof.f.mjs` reaches with its own `drive` helper, applied
|
|
57
|
+
* here one layer up at the MCP tool boundary.
|
|
58
|
+
*
|
|
59
|
+
* The result is unwrapped: a tool handler answers
|
|
60
|
+
* `Effect<…, ToolsCallResult, never>`, having absorbed its failures into
|
|
61
|
+
* `isError`, so callers want the answer rather than the `ok` around it. The
|
|
62
|
+
* `never` channel is what makes that unwrap total.
|
|
63
|
+
*
|
|
64
|
+
* @type {(overrides: Partial<Record<string, unknown[]>>) => (e: Effect<FileCasOperation | MemOp, unknown, never>) => unknown}
|
|
65
|
+
*/
|
|
66
|
+
const drive = overrides => {
|
|
67
|
+
/** @type {(cmd: string) => unknown} */
|
|
68
|
+
const next = cmd => {
|
|
69
|
+
const queue = overrides[cmd]
|
|
70
|
+
return queue !== undefined && queue.length > 0 ? queue.shift() : defaultResponse(cmd)
|
|
71
|
+
}
|
|
72
|
+
const handlers = /** @type {Parameters<typeof match>[0]} */ ({
|
|
73
|
+
access: () => next('access'),
|
|
74
|
+
createExclusive: () => next('createExclusive'),
|
|
75
|
+
mkdir: () => next('mkdir'),
|
|
76
|
+
now: () => next('now'),
|
|
77
|
+
randomInt: () => next('randomInt'),
|
|
78
|
+
readBytes: () => next('readBytes'),
|
|
79
|
+
readdir: () => next('readdir'),
|
|
80
|
+
rename: () => next('rename'),
|
|
81
|
+
rm: () => next('rm'),
|
|
82
|
+
stat: () => next('stat'),
|
|
83
|
+
writeBytes: () => next('writeBytes'),
|
|
84
|
+
memCreate: () => next('memCreate'),
|
|
85
|
+
memRead: () => next('memRead'),
|
|
86
|
+
memWrite: () => next('memWrite'),
|
|
87
|
+
})
|
|
88
|
+
const matcher = match(handlers)
|
|
89
|
+
/** @type {(e: Effect<FileCasOperation | MemOp, unknown, unknown>) => Result<unknown, unknown>} */
|
|
90
|
+
const run_ = e => {
|
|
91
|
+
const m = matcher(e)
|
|
92
|
+
return m[0] === 'done' ? m[1] : run_(m[2](/** @type {any} */ (m[1])))
|
|
93
|
+
}
|
|
94
|
+
return e => unwrap(run_(e))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// `syncRevision` is only reached on a *successful* write, which none of these
|
|
98
|
+
// cases exercise, so the cache key's actual identity never matters — only its
|
|
99
|
+
// type does.
|
|
100
|
+
const cacheKey = /** @type {Key<Cache>} */ (/** @type {any} */ ('unused-cache-key'))
|
|
101
|
+
|
|
102
|
+
const registry = casToolRegistry('.')(cacheKey)
|
|
103
|
+
|
|
104
|
+
/** @type {(name: string) => (args: any) => Effect<FileCasOperation | MemOp, ToolsCallResult, never>} */
|
|
105
|
+
const toolHandle = name => {
|
|
106
|
+
const entry = registry.find(t => t.name === name)
|
|
107
|
+
assert(entry !== undefined, `no such tool: ${name}`)
|
|
108
|
+
return /** @type {NonNullable<typeof entry>} */ (entry).handle
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Any well-formed cBase32 hash works: none of these cases resolve it against a
|
|
112
|
+
// real store, since every filesystem op is driven synthetically.
|
|
113
|
+
const someHash = vecToCBase32(vec(256n)(0n))
|
|
114
|
+
|
|
115
|
+
const meta = /** @type {const} */ ({
|
|
116
|
+
length: rttiNumber,
|
|
117
|
+
mimeType: rttiString,
|
|
118
|
+
type: rttiString,
|
|
119
|
+
uri: rttiString,
|
|
120
|
+
})
|
|
121
|
+
const parseMeta = rttiParse(meta)
|
|
122
|
+
|
|
123
|
+
export const proof = {
|
|
124
|
+
// cas_list: a store that exists but cannot be walked is a tool-level error
|
|
125
|
+
// carrying the host's own words — neither a panic (which is what it used
|
|
126
|
+
// to be, one `unwrap` deep) nor an empty listing, which would tell the
|
|
127
|
+
// client the store holds nothing.
|
|
128
|
+
casListStorageErrorReturnsError: () => {
|
|
129
|
+
const result = /** @type {ToolsCallResult} */ (
|
|
130
|
+
drive({ access: [error(ioError({ code: 'EACCES', message: 'permission denied' }))] })(toolHandle('cas_list')({}))
|
|
131
|
+
)
|
|
132
|
+
assert(result.isError === true, ['expected isError', result])
|
|
133
|
+
},
|
|
134
|
+
// cas_add: a writeBytes failure mid-upload (disk full, permissions) is
|
|
135
|
+
// reported as a tool-level error, not a thrown exception or a silent
|
|
136
|
+
// success.
|
|
137
|
+
casAddWriteErrorReturnsError: () => {
|
|
138
|
+
const result = /** @type {ToolsCallResult} */ (
|
|
139
|
+
drive({ writeBytes: [error(ioError({ message: 'disk full' }))] })(toolHandle('cas_add')({ content: 'hello' }))
|
|
140
|
+
)
|
|
141
|
+
assert(result.isError === true, ['expected isError', result])
|
|
142
|
+
},
|
|
143
|
+
// cas_get, content:false: the streaming metadata pass finds a small
|
|
144
|
+
// whole-blob-text hash, so it starts a second, independent read to refine
|
|
145
|
+
// `mimeType` via the dialect-aware detector. If that second read finds the
|
|
146
|
+
// hash gone (a GC sweep raced it away), the code falls back to the
|
|
147
|
+
// streaming verdict rather than fail the whole request.
|
|
148
|
+
casGetMetadataRefineHashVanishesFallsBackToStreamingVerdict: () => {
|
|
149
|
+
const result = /** @type {ToolsCallResult} */ (
|
|
150
|
+
drive({ readBytes: [ok(vec8(0x41n)), ok(vec(0n)(0n)), error(ioError({ message: 'vanished' }))] })
|
|
151
|
+
(toolHandle('cas_get')({ hash: someHash, content: false }))
|
|
152
|
+
)
|
|
153
|
+
assert(result.isError !== true, ['expected ok result', result])
|
|
154
|
+
const text = result.content[0]
|
|
155
|
+
assert(text.type === 'text', ['expected text content', text])
|
|
156
|
+
const parsed = unwrap(parseMeta(unwrap(parseJson(text.text))))
|
|
157
|
+
assertEq(parsed.type, 'text')
|
|
158
|
+
assertEq(parsed.mimeType, 'text/plain')
|
|
159
|
+
assertEq(parsed.length, 1)
|
|
160
|
+
},
|
|
161
|
+
// cas_get, content:true: the streaming metadata pass succeeds and the blob
|
|
162
|
+
// fits inline, so a second read materializes it. If that second read finds
|
|
163
|
+
// the hash gone, the whole request fails — there is no streaming verdict
|
|
164
|
+
// to fall back to once inline content was actually promised.
|
|
165
|
+
casGetContentFetchHashVanishesReturnsError: () => {
|
|
166
|
+
const result = /** @type {ToolsCallResult} */ (
|
|
167
|
+
drive({ readBytes: [ok(vec8(0x41n)), ok(vec(0n)(0n)), error(ioError({ message: 'vanished' }))] })
|
|
168
|
+
(toolHandle('cas_get')({ hash: someHash, content: true }))
|
|
169
|
+
)
|
|
170
|
+
assert(result.isError === true, ['expected isError', result])
|
|
171
|
+
const text = result.content[0]
|
|
172
|
+
assert(text.type === 'text' && text.text.includes('no such hash'), ['expected no-such-hash message', text])
|
|
173
|
+
},
|
|
174
|
+
}
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
*
|
|
9
9
|
* | Tool | args | action | result |
|
|
10
10
|
* |----------------|-----------------------------------------------|-------------------|--------------------------------------|
|
|
11
|
-
* | `evo_list` | `{ archived? }`
|
|
12
|
-
* | `evo_head` | `{ subject }`
|
|
13
|
-
* | `evo_revision` | `{ hash }`
|
|
14
|
-
* | `evo_add` | `{ parents, snapshot?, subject?, archived? }` | `e.add(...)` | hash (cBase32) |
|
|
11
|
+
* | `evo_list` | `{ archived? }` | `e.list(...)` | subjects, as a JSON array of strings |
|
|
12
|
+
* | `evo_head` | `{ subject }` | `e.head(...)` | head hashes, one per line |
|
|
13
|
+
* | `evo_revision` | `{ hash }` | `e.revision(...)` | the revision, as JSON `RevisionData` |
|
|
14
|
+
* | `evo_add` | `{ parents, snapshot?, subject?, archived?, lock? }` | `e.add(...)` | hash (cBase32) |
|
|
15
15
|
*
|
|
16
16
|
* `evo_add` and `evo_revision` speak the same structure — `fjs/cas/evo`'s
|
|
17
17
|
* `RevisionData` — in opposite directions, so a revision read back can be
|
|
18
|
-
* added again as-is
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* added again as-is, `lock` scopes and all. The one field `evo_revision`
|
|
19
|
+
* returns that `evo_add` does not accept is `generation`, which the server
|
|
20
|
+
* computes, and rtti's struct validation
|
|
21
21
|
* ignores properties the schema does not name, so a whole `evo_revision`
|
|
22
22
|
* result can be passed straight back to `evo_add`.
|
|
23
23
|
*
|
|
@@ -43,11 +43,10 @@
|
|
|
43
43
|
*
|
|
44
44
|
* @module
|
|
45
45
|
*
|
|
46
|
-
* @import {
|
|
46
|
+
* @import { Operation } from '../../effects/types.ts'
|
|
47
47
|
* @import { MemOp } from '../../effects/memory/types.ts'
|
|
48
|
-
* @import { ToolEntry
|
|
48
|
+
* @import { ToolEntry } from '../../protocol/mcp/types.ts'
|
|
49
49
|
* @import { Evo } from '../../cas/evo/types.ts'
|
|
50
|
-
* @import { Ts } from '../../types/rtti/ts/types.ts'
|
|
51
50
|
*/
|
|
52
51
|
import type { Operation } from '../../effects/types.ts';
|
|
53
52
|
import type { MemOp } from '../../effects/memory/types.ts';
|
|
@@ -72,12 +71,22 @@ export declare const evoRevisionArgs: {
|
|
|
72
71
|
* Arguments for `evo_add`: a new revision, per `fjs/cas/evo`'s
|
|
73
72
|
* `RevisionData` — every field of it the caller supplies, i.e. all but
|
|
74
73
|
* `generation`, which the server computes.
|
|
74
|
+
*
|
|
75
|
+
* `lock` is the media format's own field schema
|
|
76
|
+
* (`fjs/media/revision`'s `lockField`), not a restatement of it, so the
|
|
77
|
+
* advertised `inputSchema` and what the server accepts cannot drift apart. It
|
|
78
|
+
* therefore accepts either form the format does — the bindings inline, or the
|
|
79
|
+
* hash of a `vnd.fjs.lock` blob holding them. The map half is recursive, which
|
|
80
|
+
* makes it the one argument whose JSON Schema reaches a named `$defs` rule
|
|
81
|
+
* through a local `$ref` rather than being inlined whole — see
|
|
82
|
+
* `fjs/media/json/schema`.
|
|
75
83
|
*/
|
|
76
84
|
export declare const evoAddArgs: {
|
|
77
85
|
readonly parents: import("../../types/rtti/types.ts").Type1<"array", import("../../types/rtti/types.ts")._Type0<"string">>;
|
|
78
86
|
readonly snapshot: import("../../types/rtti/types.ts").Or<readonly [import("../../types/rtti/types.ts")._Type0<"string">, undefined]>;
|
|
79
87
|
readonly subject: import("../../types/rtti/types.ts").Or<readonly [import("../../types/rtti/types.ts")._Type0<"string">, undefined]>;
|
|
80
88
|
readonly archived: import("../../types/rtti/types.ts").Or<readonly [true, undefined]>;
|
|
89
|
+
readonly lock: import("../../types/rtti/types.ts").Or<readonly [import("../../media/revision/types.ts").LockFieldSchema, undefined]>;
|
|
81
90
|
};
|
|
82
91
|
/**
|
|
83
92
|
* Registry of all Evo tools, bound to an `Evo<O>`.
|
package/fjs/mcp/evo/module.f.mjs
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
*
|
|
9
9
|
* | Tool | args | action | result |
|
|
10
10
|
* |----------------|-----------------------------------------------|-------------------|--------------------------------------|
|
|
11
|
-
* | `evo_list` | `{ archived? }`
|
|
12
|
-
* | `evo_head` | `{ subject }`
|
|
13
|
-
* | `evo_revision` | `{ hash }`
|
|
14
|
-
* | `evo_add` | `{ parents, snapshot?, subject?, archived? }` | `e.add(...)` | hash (cBase32) |
|
|
11
|
+
* | `evo_list` | `{ archived? }` | `e.list(...)` | subjects, as a JSON array of strings |
|
|
12
|
+
* | `evo_head` | `{ subject }` | `e.head(...)` | head hashes, one per line |
|
|
13
|
+
* | `evo_revision` | `{ hash }` | `e.revision(...)` | the revision, as JSON `RevisionData` |
|
|
14
|
+
* | `evo_add` | `{ parents, snapshot?, subject?, archived?, lock? }` | `e.add(...)` | hash (cBase32) |
|
|
15
15
|
*
|
|
16
16
|
* `evo_add` and `evo_revision` speak the same structure — `fjs/cas/evo`'s
|
|
17
17
|
* `RevisionData` — in opposite directions, so a revision read back can be
|
|
18
|
-
* added again as-is
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* added again as-is, `lock` scopes and all. The one field `evo_revision`
|
|
19
|
+
* returns that `evo_add` does not accept is `generation`, which the server
|
|
20
|
+
* computes, and rtti's struct validation
|
|
21
21
|
* ignores properties the schema does not name, so a whole `evo_revision`
|
|
22
22
|
* result can be passed straight back to `evo_add`.
|
|
23
23
|
*
|
|
@@ -43,15 +43,16 @@
|
|
|
43
43
|
*
|
|
44
44
|
* @module
|
|
45
45
|
*
|
|
46
|
-
* @import {
|
|
46
|
+
* @import { Operation } from '../../effects/types.ts'
|
|
47
47
|
* @import { MemOp } from '../../effects/memory/types.ts'
|
|
48
|
-
* @import { ToolEntry
|
|
48
|
+
* @import { ToolEntry } from '../../protocol/mcp/types.ts'
|
|
49
49
|
* @import { Evo } from '../../cas/evo/types.ts'
|
|
50
|
-
* @import { Ts } from '../../types/rtti/ts/types.ts'
|
|
51
50
|
*/
|
|
52
51
|
|
|
53
52
|
import { string, option, array } from '../../types/rtti/module.f.mjs'
|
|
54
|
-
import {
|
|
53
|
+
import { lockField } from '../../media/revision/module.f.mjs'
|
|
54
|
+
import { pureOk, resultStep } from '../../effects/module.f.mjs'
|
|
55
|
+
import { evoSummary } from '../../cas/evo/module.f.mjs'
|
|
55
56
|
import {
|
|
56
57
|
toolEntry, errorResult, okResult,
|
|
57
58
|
} from '../../protocol/mcp/module.f.mjs'
|
|
@@ -82,12 +83,22 @@ export const evoRevisionArgs = /** @type {const} */ ({
|
|
|
82
83
|
* Arguments for `evo_add`: a new revision, per `fjs/cas/evo`'s
|
|
83
84
|
* `RevisionData` — every field of it the caller supplies, i.e. all but
|
|
84
85
|
* `generation`, which the server computes.
|
|
86
|
+
*
|
|
87
|
+
* `lock` is the media format's own field schema
|
|
88
|
+
* (`fjs/media/revision`'s `lockField`), not a restatement of it, so the
|
|
89
|
+
* advertised `inputSchema` and what the server accepts cannot drift apart. It
|
|
90
|
+
* therefore accepts either form the format does — the bindings inline, or the
|
|
91
|
+
* hash of a `vnd.fjs.lock` blob holding them. The map half is recursive, which
|
|
92
|
+
* makes it the one argument whose JSON Schema reaches a named `$defs` rule
|
|
93
|
+
* through a local `$ref` rather than being inlined whole — see
|
|
94
|
+
* `fjs/media/json/schema`.
|
|
85
95
|
*/
|
|
86
96
|
export const evoAddArgs = /** @type {const} */ ({
|
|
87
97
|
parents: array(string),
|
|
88
98
|
snapshot: option(string),
|
|
89
99
|
subject: option(string),
|
|
90
100
|
archived: option(true),
|
|
101
|
+
lock: option(lockField),
|
|
91
102
|
})
|
|
92
103
|
|
|
93
104
|
// ── Tool registry ────────────────────────────────────────────────────────────────
|
|
@@ -110,44 +121,54 @@ export const evoToolRegistry = e => [
|
|
|
110
121
|
// constrained to a newline-free alphabet), so a `join('\n')` line
|
|
111
122
|
// format could not represent an empty subject or one containing a
|
|
112
123
|
// newline without ambiguity — JSON encoding can.
|
|
113
|
-
|
|
114
|
-
|
|
124
|
+
|
|
125
|
+
// A cache slot the runner cannot reach is a tool-level error, not a
|
|
126
|
+
// panic: the client asked a question the server could not answer, and
|
|
127
|
+
// saying so is an ordinary `isError` result.
|
|
128
|
+
(({ archived }) => resultStep(
|
|
115
129
|
e.list(archived),
|
|
116
|
-
|
|
130
|
+
r => pureOk(r[0] === 'error'
|
|
131
|
+
? errorResult(evoSummary(r[1]))
|
|
132
|
+
: okResult(toJson(r[1])))
|
|
117
133
|
)),
|
|
118
134
|
),
|
|
119
135
|
toolEntry(
|
|
120
136
|
'evo_head',
|
|
121
137
|
'List the current head hashes (cBase32) of a subject, one per line. Empty when the subject is unknown.',
|
|
122
138
|
evoHeadArgs,
|
|
123
|
-
|
|
124
|
-
(({ subject }) => step(
|
|
139
|
+
({ subject }) => resultStep(
|
|
125
140
|
e.head(subject),
|
|
126
|
-
|
|
127
|
-
|
|
141
|
+
r => pureOk(r[0] === 'error'
|
|
142
|
+
? errorResult(evoSummary(r[1]))
|
|
143
|
+
: okResult(r[1].join('\n'))),
|
|
144
|
+
),
|
|
128
145
|
),
|
|
129
146
|
toolEntry(
|
|
130
147
|
'evo_revision',
|
|
131
|
-
'Read one revision by hash, as JSON: `{ subject, parents, snapshot, generation, archived? }`. `parents[0]` is the mainline parent and every further entry is a merged-in branch; `parents` and `snapshot` come back in their canonical cBase32 spelling, so they compare directly against `evo_head` output. Errors when the hash is not cBase32, is not present in the store, could not be read, or does not hold a `vnd.fjs.revision` blob — use `cas_get` for raw bytes of non-revision content.',
|
|
148
|
+
'Read one revision by hash, as JSON: `{ subject, parents, snapshot, generation, archived?, lock? }`. `parents[0]` is the mainline parent and every further entry is a merged-in branch; `parents` and `snapshot` come back in their canonical cBase32 spelling, so they compare directly against `evo_head` output. Errors when the hash is not cBase32, is not present in the store, could not be read, or does not hold a `vnd.fjs.revision` blob — use `cas_get` for raw bytes of non-revision content.',
|
|
132
149
|
evoRevisionArgs,
|
|
133
150
|
// The revision goes out as JSON in a text content item, like
|
|
134
151
|
// `evo_list`'s. An encoded response that outgrows the transport cap is
|
|
135
152
|
// the transport's `-32603`, not a tool-level error — see "Result size"
|
|
136
153
|
// in the module doc.
|
|
137
|
-
|
|
138
|
-
(({ hash }) =>
|
|
154
|
+
|
|
155
|
+
(({ hash }) => resultStep(
|
|
139
156
|
e.revision(hash),
|
|
140
|
-
|
|
157
|
+
r => pureOk(r[0] === 'error' ? errorResult(evoSummary(r[1])) : okResult(toJson(r[1])))
|
|
141
158
|
)),
|
|
142
159
|
),
|
|
143
160
|
toolEntry(
|
|
144
161
|
'evo_add',
|
|
145
|
-
'Add a new revision (a `vnd.fjs.revision` blob) and return its hash (cBase32). `subject` is required unless there is exactly one parent, from which it is inherited. `snapshot`, when omitted, is resolved from the parents (zero parents → `subject`, one parent → the parent\'s snapshot; a merge requires an explicit `snapshot`) and written explicitly. `generation` is computed by the server.',
|
|
162
|
+
'Add a new revision (a `vnd.fjs.revision` blob) and return its hash (cBase32). `subject` is required unless there is exactly one parent, from which it is inherited. `snapshot`, when omitted, is resolved from the parents (zero parents → `subject`, one parent → the parent\'s snapshot; a merge requires an explicit `snapshot`) and written explicitly. `generation` is computed by the server. `lock` is optional resolver input: a map from dependency subject to the cBase32 hash of the content it resolves to, or to a nested map scoping further bindings under that subject (use nesting only for conflicting choices a flat map cannot express, e.g. two dependencies needing different versions of a third). Pass a cBase32 hash instead of a map to share one already stored as a `vnd.fjs.lock` blob; the server records the reference and does not follow it.',
|
|
146
163
|
evoAddArgs,
|
|
147
|
-
|
|
148
|
-
|
|
164
|
+
// Two failures, one MCP shape: a rejected revision and an unreachable
|
|
165
|
+
// cache slot are both `isError` to the client, and both carry a message
|
|
166
|
+
// it can read. They stay distinguishable by tag — `evoSummary` is the
|
|
167
|
+
// renderer that switches on it — so telling them apart never needed
|
|
168
|
+
// them to arrive in separate layers.
|
|
169
|
+
input => resultStep(
|
|
149
170
|
e.add(input),
|
|
150
|
-
|
|
151
|
-
)
|
|
171
|
+
r => pureOk(r[0] === 'error' ? errorResult(evoSummary(r[1])) : okResult(r[1]))
|
|
172
|
+
),
|
|
152
173
|
),
|
|
153
174
|
]
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @import { Evo } from '../../cas/evo/types.ts'
|
|
3
3
|
* @import { ToolEntry, ToolsCallResult } from '../../protocol/mcp/types.ts'
|
|
4
|
-
* @import { Operation } from '../../effects/types.ts'
|
|
4
|
+
* @import { NotImplemented, Operation } from '../../effects/types.ts'
|
|
5
|
+
* @import { Result } from '../../types/result/types.ts'
|
|
6
|
+
* @import { State } from '../../effects/node/virtual/types.ts'
|
|
5
7
|
*/
|
|
6
8
|
export declare const proof: {
|
|
9
|
+
channelFailureIsToolError: () => void;
|
|
7
10
|
toolNamesMatchTheDesign: () => void;
|
|
8
11
|
evoListReflectsTheCache: () => void;
|
|
9
12
|
evoListEncodesArbitrarySubjectsAsJson: () => void;
|
|
@@ -13,5 +16,7 @@ export declare const proof: {
|
|
|
13
16
|
evoRevisionReturnsRevisionJson: () => void;
|
|
14
17
|
evoRevisionDomainErrorIsError: () => void;
|
|
15
18
|
evoAddSuccessReturnsHash: () => void;
|
|
19
|
+
evoAddAndRevisionCarryNestedLocks: () => void;
|
|
20
|
+
evoAddInputSchemaPublishesTheLockRecursion: () => void;
|
|
16
21
|
evoAddDomainErrorIsError: () => void;
|
|
17
22
|
};
|