functionalscript 0.39.0 → 0.41.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 +1 -1
- package/fjs/bnf/descent/module.f.d.ts +43 -2
- package/fjs/bnf/descent/module.f.js +37 -12
- package/fjs/bnf/descent/proof.f.d.ts +1 -0
- package/fjs/bnf/descent/proof.f.js +73 -32
- package/fjs/bnf/ll1/module.f.js +2 -2
- package/fjs/cas/evo/module.f.d.ts +28 -8
- package/fjs/cas/evo/module.f.js +43 -10
- package/fjs/cas/evo/proof.f.d.ts +4 -0
- package/fjs/cas/evo/proof.f.js +82 -1
- package/fjs/ci/config/module.f.d.ts +10 -7
- package/fjs/ci/config/module.f.js +23 -8
- package/fjs/ci/module.f.js +12 -5
- package/fjs/ci/nix/module.f.d.ts +61 -0
- package/fjs/ci/nix/module.f.js +92 -0
- package/fjs/ci/nix/proof.f.d.ts +23 -0
- package/fjs/ci/nix/proof.f.js +109 -0
- package/fjs/ci/node/module.f.d.ts +23 -1
- package/fjs/ci/node/module.f.js +47 -3
- package/fjs/ci/node/proof.f.d.ts +3 -0
- package/fjs/ci/node/proof.f.js +17 -0
- package/fjs/ci/proof.f.d.ts +2 -0
- package/fjs/ci/proof.f.js +47 -9
- package/fjs/dev/module.f.d.ts +1 -0
- package/fjs/dev/module.f.js +13 -2
- package/fjs/dev/update/module.f.d.ts +11 -0
- package/fjs/dev/update/module.f.js +20 -0
- package/fjs/dev/update/proof.f.d.ts +7 -0
- package/fjs/dev/update/proof.f.js +35 -0
- package/fjs/djs/ast/module.f.d.ts +47 -0
- package/fjs/djs/ast/module.f.js +9 -0
- package/fjs/djs/tokenizer/module.f.js +2 -2
- package/fjs/djs/tokenizer/proof.f.d.ts +1 -0
- package/fjs/djs/tokenizer/proof.f.js +70 -16
- package/fjs/effects/module.f.d.ts +20 -0
- package/fjs/effects/module.f.js +25 -1
- package/fjs/effects/node/module.d.ts +3 -3
- package/fjs/effects/node/module.f.d.ts +17 -7
- package/fjs/effects/node/module.f.js +22 -0
- package/fjs/effects/node/module.js +12 -12
- package/fjs/effects/node/proof.f.d.ts +1 -0
- package/fjs/effects/node/proof.f.js +14 -1
- package/fjs/effects/node/virtual/module.f.js +1 -1
- package/fjs/effects/proof.f.d.ts +5 -0
- package/fjs/effects/proof.f.js +22 -0
- package/fjs/emergent_testing/all.test.js +2 -1
- package/fjs/emergent_testing/module.f.d.ts +3 -3
- package/fjs/emergent_testing/module.f.js +8 -10
- package/fjs/emergent_testing/proof.f.js +2 -2
- package/fjs/emergent_testing/scenarios/thenable.pass.js +1 -1
- package/fjs/fsc/module.f.js +4 -4
- package/fjs/fsm/module.f.js +1 -1
- package/fjs/js/tokenizer/module.f.d.ts +1 -0
- package/fjs/js/tokenizer/module.f.js +13 -6
- package/fjs/{cas/mcp → mcp/cas}/module.f.d.ts +3 -25
- package/fjs/{cas/mcp → mcp/cas}/module.f.js +18 -58
- package/fjs/mcp/evo/module.f.d.ts +32 -0
- package/fjs/{cas/evo/mcp → mcp/evo}/module.f.js +19 -14
- package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.d.ts +1 -0
- package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.js +23 -7
- package/fjs/mcp/module.f.d.ts +54 -237
- package/fjs/mcp/module.f.js +55 -258
- package/fjs/mcp/proof.f.d.ts +43 -32
- package/fjs/mcp/proof.f.js +508 -200
- package/fjs/media/nix/module.f.d.ts +30 -0
- package/fjs/media/nix/module.f.js +166 -0
- package/fjs/media/nix/proof.f.d.ts +32 -0
- package/fjs/media/nix/proof.f.js +127 -0
- package/fjs/module.f.js +1 -1
- package/fjs/protocol/json_rpc/module.f.d.ts +114 -0
- package/fjs/{media/json/rpc → protocol/json_rpc}/module.f.js +3 -3
- package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.js +3 -3
- package/fjs/protocol/mcp/module.f.d.ts +239 -0
- package/fjs/protocol/mcp/module.f.js +272 -0
- package/fjs/protocol/mcp/proof.f.d.ts +34 -0
- package/fjs/protocol/mcp/proof.f.js +208 -0
- package/fjs/{mcp → protocol/mcp}/stdio/module.f.d.ts +5 -5
- package/fjs/{mcp → protocol/mcp}/stdio/module.f.js +11 -11
- package/fjs/{mcp → protocol/mcp}/stdio/proof.f.js +9 -9
- package/fjs/types/range_map/module.f.d.ts +14 -13
- package/fjs/types/range_map/module.f.js +18 -13
- package/fjs/types/range_map/proof.f.js +26 -39
- package/fjs/types/range_set/module.f.d.ts +5 -0
- package/fjs/types/range_set/module.f.js +16 -0
- package/fjs/types/range_set/proof.f.d.ts +1 -0
- package/fjs/types/range_set/proof.f.js +19 -0
- package/package.json +5 -5
- package/fjs/cas/evo/mcp/module.f.d.ts +0 -27
- package/fjs/cas/mcp/proof.f.d.ts +0 -45
- package/fjs/cas/mcp/proof.f.js +0 -545
- package/fjs/ci/playwright/module.f.d.ts +0 -2
- package/fjs/ci/playwright/module.f.js +0 -25
- package/fjs/media/json/rpc/module.f.d.ts +0 -114
- /package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.d.ts +0 -0
- /package/fjs/{mcp → protocol/mcp}/stdio/proof.f.d.ts +0 -0
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* | Tool | args | action | result |
|
|
10
10
|
* |----------------|-----------------------------------------------|-------------------|--------------------------------------|
|
|
11
|
-
* | `evo_list` | `{}`
|
|
11
|
+
* | `evo_list` | `{ archived? }` | `e.list(...)` | subjects, as a JSON array of strings |
|
|
12
12
|
* | `evo_head` | `{ subject }` | `e.head(...)` | head hashes, one per line |
|
|
13
13
|
* | `evo_revision` | `{ hash }` | `e.revision(...)` | the revision, as JSON `RevisionData` |
|
|
14
14
|
* | `evo_add` | `{ parents, snapshot?, subject?, archived? }` | `e.add(...)` | hash (cBase32) |
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* content, so the JSON-RPC serializer escapes it a second time on the way
|
|
28
28
|
* out and a modest result can encode to a much longer line (a subject of
|
|
29
29
|
* quote characters is the worst case). A response whose encoded line exceeds
|
|
30
|
-
* the transport cap is not lost: `fjs/mcp/stdio` retries with a small
|
|
30
|
+
* the transport cap is not lost: `fjs/protocol/mcp/stdio` retries with a small
|
|
31
31
|
* `-32603` body carrying the request's `id`, so every request still gets a
|
|
32
32
|
* response and the process never crashes. That is the transport's contract
|
|
33
33
|
* for every tool — `cas_get` has proofs for the same double-escaping path —
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* known only by encoding it, which is the transport's job, and guessing from
|
|
36
36
|
* an unencoded size is exactly the size estimate that must never be made.
|
|
37
37
|
*
|
|
38
|
-
* These tools are not served by their own process: `fjs/
|
|
38
|
+
* These tools are not served by their own process: `fjs/mcp` (the same
|
|
39
39
|
* server as `cas_add`/`cas_get`/`cas_list`) builds one `Evo<O>` from its own
|
|
40
40
|
* `Cas<O>` and cache slot, concatenates `evoToolRegistry` onto its own
|
|
41
41
|
* registry, and serves everything from that single process — one `~/.cas/`
|
|
@@ -43,16 +43,21 @@
|
|
|
43
43
|
*
|
|
44
44
|
* @module
|
|
45
45
|
*/
|
|
46
|
-
import { string, option, array } from '
|
|
47
|
-
import { pure, step } from '
|
|
48
|
-
import {} from '
|
|
49
|
-
import { toolEntry, errorResult, okResult, } from '
|
|
50
|
-
import { stringify } from '
|
|
51
|
-
import { identity } from '
|
|
52
|
-
import {} from '
|
|
46
|
+
import { string, option, array } from '../../types/rtti/module.f.js';
|
|
47
|
+
import { pure, step } from '../../effects/module.f.js';
|
|
48
|
+
import {} from '../../effects/memory/module.f.js';
|
|
49
|
+
import { toolEntry, errorResult, okResult, } from '../../protocol/mcp/module.f.js';
|
|
50
|
+
import { stringify } from '../../media/json/module.f.js';
|
|
51
|
+
import { identity } from '../../types/function/module.f.js';
|
|
52
|
+
import {} from '../../cas/evo/module.f.js';
|
|
53
53
|
// ── Argument schemas (declared once, used for both inputSchema and validate) ─────
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Arguments for `evo_list`: an optional status filter, forwarded unchanged to
|
|
56
|
+
* `Evo.list` — omitted lists the active subjects, `true` the archived ones.
|
|
57
|
+
*/
|
|
58
|
+
export const evoListArgs = {
|
|
59
|
+
archived: option(true),
|
|
60
|
+
};
|
|
56
61
|
/** Arguments for `evo_head`: the subject whose current heads are requested. */
|
|
57
62
|
export const evoHeadArgs = {
|
|
58
63
|
subject: string,
|
|
@@ -77,12 +82,12 @@ export const evoAddArgs = {
|
|
|
77
82
|
const toJson = stringify(identity);
|
|
78
83
|
/** Registry of all Evo tools, bound to an `Evo<O>`. */
|
|
79
84
|
export const evoToolRegistry = (e) => [
|
|
80
|
-
toolEntry('evo_list', 'List
|
|
85
|
+
toolEntry('evo_list', 'List subjects, as a JSON array of strings. By default only the active ones: a subject is active while at least one of its current heads is not archived. Pass `archived: true` to list the archived subjects instead — those with at least one current head, all of them archived. A subject with no current heads is in neither list.', evoListArgs,
|
|
81
86
|
// Subjects are arbitrary caller-supplied strings (unlike hashes, not
|
|
82
87
|
// constrained to a newline-free alphabet), so a `join('\n')` line
|
|
83
88
|
// format could not represent an empty subject or one containing a
|
|
84
89
|
// newline without ambiguity — JSON encoding can.
|
|
85
|
-
() => step(e.list(), subjects => pure(okResult(toJson(subjects))))),
|
|
90
|
+
({ archived }) => step(e.list(archived), subjects => pure(okResult(toJson(subjects))))),
|
|
86
91
|
toolEntry('evo_head', 'List the current head hashes (cBase32) of a subject, one per line. Empty when the subject is unknown.', evoHeadArgs, ({ subject }) => step(e.head(subject), heads => pure(okResult(heads.join('\n'))))),
|
|
87
92
|
toolEntry('evo_revision', '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.', evoRevisionArgs,
|
|
88
93
|
// The revision goes out as JSON in a text content item, like
|
|
@@ -2,6 +2,7 @@ export declare const proof: {
|
|
|
2
2
|
toolNamesMatchTheDesign: () => void;
|
|
3
3
|
evoListReflectsTheCache: () => void;
|
|
4
4
|
evoListEncodesArbitrarySubjectsAsJson: () => void;
|
|
5
|
+
evoListForwardsTheArchivedFilter: () => void;
|
|
5
6
|
evoHeadReflectsTheCache: () => void;
|
|
6
7
|
evoHeadMissingSubjectIsInvalidArguments: () => void;
|
|
7
8
|
evoRevisionReturnsRevisionJson: () => void;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { assert, assertEq } from '
|
|
2
|
-
import { fileCas } from '../../module.f.js';
|
|
3
|
-
import { sha256 } from '
|
|
4
|
-
import { emptyState, virtual } from '
|
|
5
|
-
import { vec8 } from '
|
|
6
|
-
import { vecToCBase32 } from '
|
|
7
|
-
import { initEvo, evo } from '
|
|
1
|
+
import { assert, assertEq } from '../../asserts/module.f.js';
|
|
2
|
+
import { fileCas } from '../../cas/module.f.js';
|
|
3
|
+
import { sha256 } from '../../crypto/sha2/module.f.js';
|
|
4
|
+
import { emptyState, virtual } from '../../effects/node/virtual/module.f.js';
|
|
5
|
+
import { vec8 } from '../../types/bit_vec/module.f.js';
|
|
6
|
+
import { vecToCBase32 } from '../../basen/cbase32/module.f.js';
|
|
7
|
+
import { initEvo, evo } from '../../cas/evo/module.f.js';
|
|
8
8
|
import { evoToolRegistry } from './module.f.js';
|
|
9
9
|
const home = '/home/user';
|
|
10
10
|
const findEntry = (registry, name) => {
|
|
@@ -57,6 +57,22 @@ export const proof = {
|
|
|
57
57
|
assert(subjects.includes('line one\nline two'), ['unexpected subjects', subjects]);
|
|
58
58
|
assert(subjects.includes(''), ['unexpected subjects', subjects]);
|
|
59
59
|
},
|
|
60
|
+
// The `archived` argument is a pass-through to `Evo.list`'s status filter:
|
|
61
|
+
// omitted lists the active subjects, `true` the archived ones.
|
|
62
|
+
evoListForwardsTheArchivedFilter: () => {
|
|
63
|
+
const c = fileCas(sha256)(home);
|
|
64
|
+
const [state0, cacheKey] = virtual(emptyState)(initEvo(c));
|
|
65
|
+
const e = evo(c)(cacheKey);
|
|
66
|
+
const [state1, add] = virtual(state0)(e.add({ parents: [], subject: 'gone', snapshot: vecToCBase32(vec8(0x2cn)), archived: true }));
|
|
67
|
+
assert(add[0] === 'ok', ['expected add ok', add]);
|
|
68
|
+
const entry = findEntry(evoToolRegistry(e), 'evo_list');
|
|
69
|
+
const [state2, active] = virtual(state1)(entry.handle({}));
|
|
70
|
+
assert(!active.isError);
|
|
71
|
+
assertEq(textOf(active), '[]');
|
|
72
|
+
const [, archived] = virtual(state2)(entry.handle({ archived: true }));
|
|
73
|
+
assert(!archived.isError);
|
|
74
|
+
assertEq(textOf(archived), '["gone"]');
|
|
75
|
+
},
|
|
60
76
|
evoHeadReflectsTheCache: () => {
|
|
61
77
|
const c = fileCas(sha256)(home);
|
|
62
78
|
const [state0, cacheKey] = virtual(emptyState)(initEvo(c));
|
package/fjs/mcp/module.f.d.ts
CHANGED
|
@@ -1,239 +1,56 @@
|
|
|
1
|
-
import { unknown, type Unknown } from '../media/json/module.f.ts';
|
|
2
|
-
import type { Ts } from '../types/rtti/ts/module.f.ts';
|
|
3
|
-
import { type Operation, type Effect } from '../effects/module.f.ts';
|
|
4
|
-
import { type Key, type MemOp } from '../effects/memory/module.f.ts';
|
|
5
|
-
import { type Response } from '../media/json/rpc/module.f.ts';
|
|
6
|
-
import type { Type } from '../types/rtti/module.f.ts';
|
|
7
|
-
/** Name + version pair sent in `initialize` requests and responses. */
|
|
8
|
-
export declare const implementation: {
|
|
9
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
10
|
-
readonly version: import("../types/rtti/module.f.ts").String;
|
|
11
|
-
};
|
|
12
|
-
export type Implementation = Ts<typeof implementation>;
|
|
13
|
-
/** Server capabilities advertised in the `initialize` response. */
|
|
14
|
-
export declare const serverCapabilities: {
|
|
15
|
-
readonly tools: import("../types/rtti/module.f.ts").Or<readonly [{
|
|
16
|
-
readonly listChanged: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").Boolean, undefined]>;
|
|
17
|
-
}, undefined]>;
|
|
18
|
-
};
|
|
19
|
-
export type ServerCapabilities = Ts<typeof serverCapabilities>;
|
|
20
|
-
/** Params for the `initialize` request. */
|
|
21
|
-
export declare const initializeParams: {
|
|
22
|
-
readonly protocolVersion: import("../types/rtti/module.f.ts").String;
|
|
23
|
-
readonly capabilities: typeof unknown;
|
|
24
|
-
readonly clientInfo: {
|
|
25
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
26
|
-
readonly version: import("../types/rtti/module.f.ts").String;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
export type InitializeParams = Ts<typeof initializeParams>;
|
|
30
|
-
/** Result for the `initialize` request. */
|
|
31
|
-
export declare const initializeResult: {
|
|
32
|
-
readonly protocolVersion: import("../types/rtti/module.f.ts").String;
|
|
33
|
-
readonly capabilities: {
|
|
34
|
-
readonly tools: import("../types/rtti/module.f.ts").Or<readonly [{
|
|
35
|
-
readonly listChanged: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").Boolean, undefined]>;
|
|
36
|
-
}, undefined]>;
|
|
37
|
-
};
|
|
38
|
-
readonly serverInfo: {
|
|
39
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
40
|
-
readonly version: import("../types/rtti/module.f.ts").String;
|
|
41
|
-
};
|
|
42
|
-
readonly instructions: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
43
|
-
};
|
|
44
|
-
export type InitializeResult = Ts<typeof initializeResult>;
|
|
45
|
-
/** Plain-text content item returned by a tool call. */
|
|
46
|
-
export declare const textContent: {
|
|
47
|
-
readonly type: 'text';
|
|
48
|
-
readonly text: import("../types/rtti/module.f.ts").String;
|
|
49
|
-
};
|
|
50
|
-
export type TextContent = Ts<typeof textContent>;
|
|
51
|
-
/**
|
|
52
|
-
* A binary resource carried inside an {@link embeddedResource}: a base64
|
|
53
|
-
* `blob`, an addressing `uri`, and an optional `mimeType`. This is MCP's
|
|
54
|
-
* `BlobResource` shape — the idiomatic way to return typed binary content so a
|
|
55
|
-
* `mimeType` travels alongside the bytes and clients know how to route them.
|
|
56
|
-
*/
|
|
57
|
-
export declare const blobResource: {
|
|
58
|
-
readonly uri: import("../types/rtti/module.f.ts").String;
|
|
59
|
-
readonly mimeType: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
60
|
-
readonly blob: import("../types/rtti/module.f.ts").String;
|
|
61
|
-
};
|
|
62
|
-
export type BlobResource = Ts<typeof blobResource>;
|
|
63
|
-
/** An `EmbeddedResource` content item wrapping a {@link blobResource}. */
|
|
64
|
-
export declare const embeddedResource: {
|
|
65
|
-
readonly type: 'resource';
|
|
66
|
-
readonly resource: {
|
|
67
|
-
readonly uri: import("../types/rtti/module.f.ts").String;
|
|
68
|
-
readonly mimeType: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
69
|
-
readonly blob: import("../types/rtti/module.f.ts").String;
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
export type EmbeddedResource = Ts<typeof embeddedResource>;
|
|
73
|
-
/**
|
|
74
|
-
* A single item in a `tools/call` result's `content` array: either plain
|
|
75
|
-
* {@link textContent} or an {@link embeddedResource} for typed binary. The
|
|
76
|
-
* `image` and `audio` variants are not modelled yet.
|
|
77
|
-
*/
|
|
78
|
-
export declare const contentItem: import("../types/rtti/module.f.ts").Or<[{
|
|
79
|
-
readonly type: 'text';
|
|
80
|
-
readonly text: import("../types/rtti/module.f.ts").String;
|
|
81
|
-
}, {
|
|
82
|
-
readonly type: 'resource';
|
|
83
|
-
readonly resource: {
|
|
84
|
-
readonly uri: import("../types/rtti/module.f.ts").String;
|
|
85
|
-
readonly mimeType: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
86
|
-
readonly blob: import("../types/rtti/module.f.ts").String;
|
|
87
|
-
};
|
|
88
|
-
}]>;
|
|
89
|
-
export type ContentItem = Ts<typeof contentItem>;
|
|
90
|
-
/**
|
|
91
|
-
* A tool descriptor returned by `tools/list`.
|
|
92
|
-
* `inputSchema` is a JSON Schema object — use `toJsonSchema` to derive it from
|
|
93
|
-
* an rtti schema.
|
|
94
|
-
*/
|
|
95
|
-
export declare const tool: {
|
|
96
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
97
|
-
readonly description: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
98
|
-
readonly inputSchema: typeof unknown;
|
|
99
|
-
};
|
|
100
|
-
export type Tool = Ts<typeof tool>;
|
|
101
|
-
/**
|
|
102
|
-
* Params for the `tools/list` request. `cursor` is an opaque pagination token
|
|
103
|
-
* from a previous `ToolsListResult.nextCursor`.
|
|
104
|
-
*/
|
|
105
|
-
export declare const toolsListParams: {
|
|
106
|
-
readonly cursor: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
107
|
-
};
|
|
108
|
-
export type ToolsListParams = Ts<typeof toolsListParams>;
|
|
109
|
-
export declare const toolsListResult: {
|
|
110
|
-
readonly tools: import("../types/rtti/module.f.ts").Type1<"array", {
|
|
111
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
112
|
-
readonly description: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
113
|
-
readonly inputSchema: typeof unknown;
|
|
114
|
-
}>;
|
|
115
|
-
readonly nextCursor: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
116
|
-
};
|
|
117
|
-
export type ToolsListResult = Ts<typeof toolsListResult>;
|
|
118
|
-
export declare const toolsCallParams: {
|
|
119
|
-
readonly name: import("../types/rtti/module.f.ts").String;
|
|
120
|
-
readonly arguments: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").Type1<"record", typeof unknown>, undefined]>;
|
|
121
|
-
};
|
|
122
|
-
export type ToolsCallParams = Ts<typeof toolsCallParams>;
|
|
123
|
-
export declare const toolsCallResult: {
|
|
124
|
-
readonly content: import("../types/rtti/module.f.ts").Type1<"array", import("../types/rtti/module.f.ts").Or<[{
|
|
125
|
-
readonly type: 'text';
|
|
126
|
-
readonly text: import("../types/rtti/module.f.ts").String;
|
|
127
|
-
}, {
|
|
128
|
-
readonly type: 'resource';
|
|
129
|
-
readonly resource: {
|
|
130
|
-
readonly uri: import("../types/rtti/module.f.ts").String;
|
|
131
|
-
readonly mimeType: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").String, undefined]>;
|
|
132
|
-
readonly blob: import("../types/rtti/module.f.ts").String;
|
|
133
|
-
};
|
|
134
|
-
}]>>;
|
|
135
|
-
readonly isError: import("../types/rtti/module.f.ts").Or<readonly [import("../types/rtti/module.f.ts").Boolean, undefined]>;
|
|
136
|
-
};
|
|
137
|
-
export type ToolsCallResult = Ts<typeof toolsCallResult>;
|
|
138
|
-
/** Per-method handlers for a hello-world MCP tool server. */
|
|
139
|
-
export type McpHandlers<O extends Operation> = {
|
|
140
|
-
readonly toolsList: (params: ToolsListParams) => Effect<O, ToolsListResult>;
|
|
141
|
-
readonly toolsCall: (params: ToolsCallParams) => Effect<O, ToolsCallResult>;
|
|
142
|
-
};
|
|
143
1
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
2
|
+
* The FJS MCP server: the composition root the `fjs mcp` / `m` CLI command
|
|
3
|
+
* runs. Session configuration (`McpConfig`), the top-level entry point
|
|
4
|
+
* (`casMcpServer`, wiring `mcpStep` + `stdioTransport` from
|
|
5
|
+
* `fjs/protocol/mcp/`), and the composed tool registry — nothing CAS- or
|
|
6
|
+
* Evo-specific lives here, it only knows about tool *registries*, not what is
|
|
7
|
+
* in them, so a future non-CAS tool set can land as a new sibling of
|
|
8
|
+
* `fjs/mcp/cas/` and `fjs/mcp/evo/` without touching either of them.
|
|
9
|
+
*
|
|
10
|
+
* ## Tools
|
|
11
|
+
*
|
|
12
|
+
* | Tool | args | action | result |
|
|
13
|
+
* |----------------|------------------------------------------------|------------------|--------------------------------------|
|
|
14
|
+
* | `cas_add` | `{ content, type? }` | `c.write(...)` | hash (cBase32) |
|
|
15
|
+
* | `cas_get` | `{ hash, content?: boolean }` | `c.read(key)` | JSON `{length,mimeType,type[,uri][,text\|blob]}` |
|
|
16
|
+
* | `cas_list` | `{}` | `c.list()` | hashes, one per line |
|
|
17
|
+
* | `evo_list` | `{ archived? }` | `e.list(...)` | subjects, as a JSON array of strings |
|
|
18
|
+
* | `evo_head` | `{ subject }` | `e.head(...)` | head hashes, one per line |
|
|
19
|
+
* | `evo_revision` | `{ hash }` | `e.revision(...)`| the revision, as JSON |
|
|
20
|
+
* | `evo_add` | `{ parents, snapshot?, subject?, archived? }` | `e.add(...)` | hash (cBase32) |
|
|
21
|
+
*
|
|
22
|
+
* `cas_add`/`cas_get`/`cas_list` are `fjs/mcp/cas` — see that module for tool
|
|
23
|
+
* documentation (input encoding, output shape, error convention). `evo_*` is
|
|
24
|
+
* `fjs/mcp/evo`. Both tool sets run in one process, sharing one `~/.cas/`
|
|
25
|
+
* store and one in-memory Evo cache scanned once at startup (`initEvo`).
|
|
26
|
+
*
|
|
27
|
+
* @module
|
|
28
|
+
*/
|
|
29
|
+
import { type Effect } from '../effects/module.f.ts';
|
|
30
|
+
import { type MemOp } from '../effects/memory/module.f.ts';
|
|
31
|
+
import { type Read, type Write } from '../effects/node/module.f.ts';
|
|
32
|
+
import { type McpConfig, type McpHandlers } from '../protocol/mcp/module.f.ts';
|
|
33
|
+
import { type FileCasOperation } from '../cas/module.f.ts';
|
|
34
|
+
import { type Cache } from '../cas/evo/module.f.ts';
|
|
35
|
+
import type { Key } from '../effects/memory/module.f.ts';
|
|
36
|
+
/**
|
|
37
|
+
* MCP handlers for `FileCas` (`fjs/mcp/cas`) plus the Evo API (`fjs/mcp/evo`)
|
|
38
|
+
* layered on it, bound to `home` and an already-built Evo cache slot (see
|
|
39
|
+
* `initEvo`).
|
|
40
|
+
*/
|
|
41
|
+
export declare const casMcpHandlers: (home: string) => (cacheKey: Key<Cache>) => McpHandlers<FileCasOperation | MemOp>;
|
|
42
|
+
/**
|
|
43
|
+
* Static MCP configuration for the CAS server: advertises the `tools`
|
|
44
|
+
* capability, identifies the server, and pins the protocol version.
|
|
45
|
+
*/
|
|
46
|
+
export declare const casConfig: McpConfig;
|
|
47
|
+
/**
|
|
48
|
+
* Runs the combined CAS + Evo MCP server over stdio: scans `~/.cas/` once to
|
|
49
|
+
* build the Evo subject/head cache (`initEvo`), allocates the session-state
|
|
50
|
+
* slot, builds the `mcpStep` for the merged tool registry, and drives the
|
|
51
|
+
* read → parse → dispatch → write loop until stdin EOF.
|
|
52
|
+
*/
|
|
53
|
+
export declare const casMcpServer: (home: string) => Effect<Read | Write | MemOp | FileCasOperation, void>;
|
|
54
|
+
export declare const proof: {
|
|
55
|
+
casMcpServer: () => void;
|
|
154
56
|
};
|
|
155
|
-
/**
|
|
156
|
-
* Creates a type-safe tool entry that binds an RTTI schema with a handler.
|
|
157
|
-
*
|
|
158
|
-
* The builder validates arguments at runtime using the RTTI and passes pre-validated
|
|
159
|
-
* arguments (typed as `Ts<T>`) to the handler. This eliminates manual validation
|
|
160
|
-
* boilerplate and type assertions.
|
|
161
|
-
*
|
|
162
|
-
* @param name - The tool name (used in `tools/call` requests)
|
|
163
|
-
* @param description - Human-readable description for `tools/list`
|
|
164
|
-
* @param inputRtti - Runtime type info for input validation
|
|
165
|
-
* @param handle - Handler receiving validated arguments of type `Ts<inputRtti>`
|
|
166
|
-
* @returns A `ToolEntry` ready to be added to a registry
|
|
167
|
-
*/
|
|
168
|
-
export declare const toolEntry: <T extends Type, O extends Operation>(name: string, description: string, inputRtti: T, handle: (args: Ts<T>) => Effect<O, ToolsCallResult>) => ToolEntry<O>;
|
|
169
|
-
/**
|
|
170
|
-
* Helper to create a successful single-text-block tool result.
|
|
171
|
-
*
|
|
172
|
-
* @param text - The text to return to the client
|
|
173
|
-
* @returns A `ToolsCallResult` with the text content
|
|
174
|
-
*/
|
|
175
|
-
export declare const okResult: (text: string) => ToolsCallResult;
|
|
176
|
-
/**
|
|
177
|
-
* Helper to create a tool-level error result with plain text explanation.
|
|
178
|
-
*
|
|
179
|
-
* @param text - The error message to return to the client
|
|
180
|
-
* @returns A `ToolsCallResult` with `isError: true` and the text explanation
|
|
181
|
-
*/
|
|
182
|
-
export declare const errorResult: (text: string) => ToolsCallResult;
|
|
183
|
-
/**
|
|
184
|
-
* Builds `McpHandlers` from a registry of tool entries.
|
|
185
|
-
*
|
|
186
|
-
* This factory generates `toolsList` and `toolsCall` handlers that work with a
|
|
187
|
-
* declarative registry, eliminating boilerplate. The `toolsList` handler converts
|
|
188
|
-
* entries into MCP `Tool` descriptors, and `toolsCall` dispatches by name and
|
|
189
|
-
* delegates to the appropriate handler.
|
|
190
|
-
*
|
|
191
|
-
* @param registry - Array of tool entries
|
|
192
|
-
* @returns Complete `McpHandlers` ready for use with `mcpStep`
|
|
193
|
-
*/
|
|
194
|
-
export declare const fromRegistry: <O extends Operation>(registry: readonly ToolEntry<O>[]) => McpHandlers<O>;
|
|
195
|
-
/** Top-level handler: maps a raw JSON value to a JSON-RPC response (or `null` for notifications). */
|
|
196
|
-
export type Handle<O extends Operation> = (value: Unknown) => Effect<O, Response | null>;
|
|
197
|
-
/** MCP error -32002: the client called a method before `initialize`. */
|
|
198
|
-
export declare const notInitialized: import("../types/rtti/ts/module.f.ts").StructTs<{
|
|
199
|
-
readonly code: import("../types/rtti/module.f.ts").Number;
|
|
200
|
-
readonly message: import("../types/rtti/module.f.ts").String;
|
|
201
|
-
readonly data: import("../types/rtti/module.f.ts").Or<readonly [typeof unknown, undefined]>;
|
|
202
|
-
}>;
|
|
203
|
-
/** State carried before the peer sends `initialize`. */
|
|
204
|
-
export type Uninitialized = readonly ['uninitialized'];
|
|
205
|
-
/** State after `initialize` response was sent but before `notifications/initialized` arrives. */
|
|
206
|
-
export type Initializing = readonly ['initializing'];
|
|
207
|
-
/** State carried after a successful `initialize` exchange. */
|
|
208
|
-
export type InitializedState = true;
|
|
209
|
-
/** The three phases of an MCP session. */
|
|
210
|
-
export type McpSessionState = Uninitialized | Initializing | readonly ['initialized', InitializedState];
|
|
211
|
-
/** Initial session state — always start here. */
|
|
212
|
-
export declare const uninitializedState: McpSessionState;
|
|
213
|
-
/** Static configuration supplied by the server implementer. */
|
|
214
|
-
export type McpConfig = {
|
|
215
|
-
readonly serverInfo: Implementation;
|
|
216
|
-
readonly capabilities: ServerCapabilities;
|
|
217
|
-
readonly protocolVersion: string;
|
|
218
|
-
};
|
|
219
|
-
/**
|
|
220
|
-
* State-machine step for an MCP session using memory effects.
|
|
221
|
-
*
|
|
222
|
-
* Given configuration, handlers, and a memory key holding the session state,
|
|
223
|
-
* returns a function `(value) => Effect<MemOp | O, Response | null>`.
|
|
224
|
-
*
|
|
225
|
-
* Rules:
|
|
226
|
-
* - `ping` returns an empty success regardless of session state; non-object
|
|
227
|
-
* params → -32602.
|
|
228
|
-
* - `initialize` is accepted only while uninitialized; a second call returns -32600.
|
|
229
|
-
* On success the state moves to `initializing`, not `initialized`.
|
|
230
|
-
* - `notifications/initialized` (no `id`) transitions `initializing` → `initialized`;
|
|
231
|
-
* a malformed one (non-object params) is ignored and the session stays gated;
|
|
232
|
-
* other notifications are silently ignored in any state.
|
|
233
|
-
* - Any other method before `notifications/initialized` → error -32002 (not initialized).
|
|
234
|
-
* - Methods gated by a capability (e.g. `tools/list`) → -32601 when the capability
|
|
235
|
-
* is absent.
|
|
236
|
-
* - `tools/list` params (an optional pagination `cursor`) are validated and passed
|
|
237
|
-
* to the handler; invalid params → -32602.
|
|
238
|
-
*/
|
|
239
|
-
export declare const mcpStep: ({ protocolVersion, capabilities, serverInfo, }: McpConfig) => <O extends Operation>(handlers: McpHandlers<O>) => (stateKey: Key<McpSessionState>) => (value: Unknown) => Effect<MemOp | O, Response | null>;
|