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.
Files changed (95) hide show
  1. package/README.md +1 -1
  2. package/fjs/bnf/descent/module.f.d.ts +43 -2
  3. package/fjs/bnf/descent/module.f.js +37 -12
  4. package/fjs/bnf/descent/proof.f.d.ts +1 -0
  5. package/fjs/bnf/descent/proof.f.js +73 -32
  6. package/fjs/bnf/ll1/module.f.js +2 -2
  7. package/fjs/cas/evo/module.f.d.ts +28 -8
  8. package/fjs/cas/evo/module.f.js +43 -10
  9. package/fjs/cas/evo/proof.f.d.ts +4 -0
  10. package/fjs/cas/evo/proof.f.js +82 -1
  11. package/fjs/ci/config/module.f.d.ts +10 -7
  12. package/fjs/ci/config/module.f.js +23 -8
  13. package/fjs/ci/module.f.js +12 -5
  14. package/fjs/ci/nix/module.f.d.ts +61 -0
  15. package/fjs/ci/nix/module.f.js +92 -0
  16. package/fjs/ci/nix/proof.f.d.ts +23 -0
  17. package/fjs/ci/nix/proof.f.js +109 -0
  18. package/fjs/ci/node/module.f.d.ts +23 -1
  19. package/fjs/ci/node/module.f.js +47 -3
  20. package/fjs/ci/node/proof.f.d.ts +3 -0
  21. package/fjs/ci/node/proof.f.js +17 -0
  22. package/fjs/ci/proof.f.d.ts +2 -0
  23. package/fjs/ci/proof.f.js +47 -9
  24. package/fjs/dev/module.f.d.ts +1 -0
  25. package/fjs/dev/module.f.js +13 -2
  26. package/fjs/dev/update/module.f.d.ts +11 -0
  27. package/fjs/dev/update/module.f.js +20 -0
  28. package/fjs/dev/update/proof.f.d.ts +7 -0
  29. package/fjs/dev/update/proof.f.js +35 -0
  30. package/fjs/djs/ast/module.f.d.ts +47 -0
  31. package/fjs/djs/ast/module.f.js +9 -0
  32. package/fjs/djs/tokenizer/module.f.js +2 -2
  33. package/fjs/djs/tokenizer/proof.f.d.ts +1 -0
  34. package/fjs/djs/tokenizer/proof.f.js +70 -16
  35. package/fjs/effects/module.f.d.ts +20 -0
  36. package/fjs/effects/module.f.js +25 -1
  37. package/fjs/effects/node/module.d.ts +3 -3
  38. package/fjs/effects/node/module.f.d.ts +17 -7
  39. package/fjs/effects/node/module.f.js +22 -0
  40. package/fjs/effects/node/module.js +12 -12
  41. package/fjs/effects/node/proof.f.d.ts +1 -0
  42. package/fjs/effects/node/proof.f.js +14 -1
  43. package/fjs/effects/node/virtual/module.f.js +1 -1
  44. package/fjs/effects/proof.f.d.ts +5 -0
  45. package/fjs/effects/proof.f.js +22 -0
  46. package/fjs/emergent_testing/all.test.js +2 -1
  47. package/fjs/emergent_testing/module.f.d.ts +3 -3
  48. package/fjs/emergent_testing/module.f.js +8 -10
  49. package/fjs/emergent_testing/proof.f.js +2 -2
  50. package/fjs/emergent_testing/scenarios/thenable.pass.js +1 -1
  51. package/fjs/fsc/module.f.js +4 -4
  52. package/fjs/fsm/module.f.js +1 -1
  53. package/fjs/js/tokenizer/module.f.d.ts +1 -0
  54. package/fjs/js/tokenizer/module.f.js +13 -6
  55. package/fjs/{cas/mcp → mcp/cas}/module.f.d.ts +3 -25
  56. package/fjs/{cas/mcp → mcp/cas}/module.f.js +18 -58
  57. package/fjs/mcp/evo/module.f.d.ts +32 -0
  58. package/fjs/{cas/evo/mcp → mcp/evo}/module.f.js +19 -14
  59. package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.d.ts +1 -0
  60. package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.js +23 -7
  61. package/fjs/mcp/module.f.d.ts +54 -237
  62. package/fjs/mcp/module.f.js +55 -258
  63. package/fjs/mcp/proof.f.d.ts +43 -32
  64. package/fjs/mcp/proof.f.js +508 -200
  65. package/fjs/media/nix/module.f.d.ts +30 -0
  66. package/fjs/media/nix/module.f.js +166 -0
  67. package/fjs/media/nix/proof.f.d.ts +32 -0
  68. package/fjs/media/nix/proof.f.js +127 -0
  69. package/fjs/module.f.js +1 -1
  70. package/fjs/protocol/json_rpc/module.f.d.ts +114 -0
  71. package/fjs/{media/json/rpc → protocol/json_rpc}/module.f.js +3 -3
  72. package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.js +3 -3
  73. package/fjs/protocol/mcp/module.f.d.ts +239 -0
  74. package/fjs/protocol/mcp/module.f.js +272 -0
  75. package/fjs/protocol/mcp/proof.f.d.ts +34 -0
  76. package/fjs/protocol/mcp/proof.f.js +208 -0
  77. package/fjs/{mcp → protocol/mcp}/stdio/module.f.d.ts +5 -5
  78. package/fjs/{mcp → protocol/mcp}/stdio/module.f.js +11 -11
  79. package/fjs/{mcp → protocol/mcp}/stdio/proof.f.js +9 -9
  80. package/fjs/types/range_map/module.f.d.ts +14 -13
  81. package/fjs/types/range_map/module.f.js +18 -13
  82. package/fjs/types/range_map/proof.f.js +26 -39
  83. package/fjs/types/range_set/module.f.d.ts +5 -0
  84. package/fjs/types/range_set/module.f.js +16 -0
  85. package/fjs/types/range_set/proof.f.d.ts +1 -0
  86. package/fjs/types/range_set/proof.f.js +19 -0
  87. package/package.json +5 -5
  88. package/fjs/cas/evo/mcp/module.f.d.ts +0 -27
  89. package/fjs/cas/mcp/proof.f.d.ts +0 -45
  90. package/fjs/cas/mcp/proof.f.js +0 -545
  91. package/fjs/ci/playwright/module.f.d.ts +0 -2
  92. package/fjs/ci/playwright/module.f.js +0 -25
  93. package/fjs/media/json/rpc/module.f.d.ts +0 -114
  94. /package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.d.ts +0 -0
  95. /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` | `{}` | `e.list()` | subjects, as a JSON array of strings |
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/cas/mcp` (the same
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 '../../../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 '../../../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 '../module.f.js';
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
- /** Arguments for `evo_list`: none. */
55
- export const evoListArgs = {};
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 all subjects with at least one stored revision, as a JSON array of strings.', evoListArgs,
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 '../../../asserts/module.f.js';
2
- import { fileCas } from '../../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 '../module.f.js';
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));
@@ -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
- * A single declarative tool entry combining metadata, input schema, and type-safe handler.
145
- *
146
- * The handler receives pre-validated arguments of type `Ts<inputRtti>`, eliminating the need
147
- * for manual validation or type casting. All validation is encapsulated in the entry.
148
- */
149
- export type ToolEntry<O extends Operation> = {
150
- readonly name: string;
151
- readonly description: string;
152
- readonly inputRtti: Type;
153
- readonly handle: (args: Unknown) => Effect<O, ToolsCallResult>;
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>;