@savvy-web/mcp 3.2.3 → 3.3.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/errors.js +23 -81
- package/index.d.ts +39 -59
- package/index.js +2 -3
- package/main.d.ts +17 -12
- package/main.js +16 -21
- package/package.json +6 -3
- package/server.js +20 -176
- package/tools/biome-check.js +10 -29
- package/tools/changeset-deps-detect.js +4 -48
- package/tools/changeset-deps-regen.js +4 -50
- package/tools/changeset-inspect.js +4 -78
- package/tools/changeset-preview.js +4 -27
- package/tools/changeset-validate.js +8 -31
- package/tools/repos-inspect.js +5 -83
- package/tools/repos-manage.js +18 -142
- package/tools/turbo-inspect.js +4 -58
- package/tools/workspace-info.js +4 -26
- package/version.js +1 -1
- package/internal/project-root.js +0 -25
- package/markdown.js +0 -33
- package/tools/md-inline.js +0 -22
package/errors.js
CHANGED
|
@@ -1,117 +1,59 @@
|
|
|
1
|
+
import { ToolFailure } from "@effected/mcp";
|
|
1
2
|
import { Schema } from "effect";
|
|
2
3
|
|
|
3
4
|
//#region src/errors.ts
|
|
4
5
|
/**
|
|
5
|
-
* The one typed failure union every savvy-mcp tool declares, plus the helpers
|
|
6
|
-
* that keep each member's `message` self-contained on the wire.
|
|
7
|
-
*
|
|
8
|
-
* @remarks
|
|
9
|
-
* Under `failureMode: "error"` (the only mode these tools use) a declared
|
|
10
|
-
* typed failure reaches the client as
|
|
11
|
-
* `{ isError: true, content: [{ type: "text", text: error.message }] }` and
|
|
12
|
-
* `structuredContent` is never populated for it
|
|
13
|
-
* (rc.116's `registerToolkit`, `declaredFailureResult` in
|
|
14
|
-
* `.repos/effect/packages/effect/src/unstable/ai/McpServer.ts` — see the
|
|
15
|
-
* header of `server.ts`). So a structured `remediation`
|
|
16
|
-
* field is invisible to a real client: every member folds its hint into
|
|
17
|
-
* `message` at construction through {@link composeRemediatedMessage}, and any
|
|
18
|
-
* caller-supplied value echoed back passes through {@link truncateEchoed}.
|
|
19
|
-
*
|
|
20
|
-
* @packageDocumentation
|
|
21
|
-
*/
|
|
22
|
-
/** What a caller should do next about a failed tool call. @public */
|
|
23
|
-
const Remediation = Schema.Struct({
|
|
24
|
-
hint: Schema.String,
|
|
25
|
-
suggestedTool: Schema.optionalKey(Schema.String)
|
|
26
|
-
});
|
|
27
|
-
/**
|
|
28
|
-
* Compose a self-contained wire message from a raw cause message and its
|
|
29
|
-
* remediation: the human message, then the hint, then `Try <suggestedTool>.`
|
|
30
|
-
* when one is present. Every {@link McpToolError} member's `message` is built
|
|
31
|
-
* through this at construction, because `message` is the only field a
|
|
32
|
-
* declared failure delivers to the wire.
|
|
33
|
-
*
|
|
34
|
-
* @public
|
|
35
|
-
*/
|
|
36
|
-
const composeRemediatedMessage = (message, remediation) => remediation.suggestedTool === void 0 ? `${message} ${remediation.hint}` : `${message} ${remediation.hint} Try ${remediation.suggestedTool}.`;
|
|
37
|
-
const ECHO_LIMIT = 200;
|
|
38
|
-
/**
|
|
39
|
-
* The limit for an ENGINE message echoed through {@link engineError} or an
|
|
40
|
-
* argument-decode message: wider than {@link truncateEchoed}'s default because
|
|
41
|
-
* the engine's own rendering (a git stderr, a decode path) is the diagnostic,
|
|
42
|
-
* but still bounded — the kit embeds caller values (`base`, `task`, the
|
|
43
|
-
* decoded value) in those messages untruncated.
|
|
44
|
-
*/
|
|
45
|
-
const ENGINE_ECHO_LIMIT = 2e3;
|
|
46
|
-
/**
|
|
47
|
-
* Truncate a caller-supplied value before it is echoed back inside an error's
|
|
48
|
-
* `message`. Without this a pathological argument (a multi-megabyte `cwd`,
|
|
49
|
-
* say) is echoed once in the response's `content[0].text` and once more in the
|
|
50
|
-
* corresponding log line, burning an agent's context twice on what is usually
|
|
51
|
-
* a typo.
|
|
52
|
-
*
|
|
53
|
-
* @public
|
|
54
|
-
*/
|
|
55
|
-
const truncateEchoed = (value, limit = ECHO_LIMIT) => value.length > limit ? `${value.slice(0, limit)}…` : value;
|
|
56
|
-
/**
|
|
57
6
|
* No workspace root was found walking up from the requested directory.
|
|
58
|
-
* `message` is composed through
|
|
59
|
-
*
|
|
7
|
+
* `message` is composed through `ToolFailure.message` at construction, so it
|
|
8
|
+
* is what reaches the wire as `content[0].text`.
|
|
60
9
|
*
|
|
61
10
|
* @public
|
|
62
11
|
*/
|
|
63
12
|
var WorkspaceNotFound = class extends Schema.TaggedError()("WorkspaceNotFound", {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
remediation: Remediation
|
|
13
|
+
...ToolFailure.fields,
|
|
14
|
+
cwd: Schema.String
|
|
67
15
|
}) {};
|
|
68
16
|
/**
|
|
69
17
|
* A tool argument was structurally acceptable but semantically invalid — a
|
|
70
18
|
* `repos_manage` action missing the field it needs, a `biome_check` path
|
|
71
19
|
* outside the workspace, a `changeset_validate` directory that does not
|
|
72
|
-
* exist. `message` is composed through
|
|
20
|
+
* exist. `message` is composed through `ToolFailure.message`.
|
|
73
21
|
*
|
|
74
22
|
* @public
|
|
75
23
|
*/
|
|
76
24
|
var InvalidArgument = class extends Schema.TaggedError()("InvalidArgument", {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
remediation: Remediation
|
|
25
|
+
...ToolFailure.fields,
|
|
26
|
+
argument: Schema.String
|
|
80
27
|
}) {};
|
|
81
28
|
/**
|
|
82
29
|
* A silk-effects engine program failed with one of its own typed errors
|
|
83
30
|
* (`TurboError`, `GitError`, `ReposConfigError`, …). `source` carries that
|
|
84
31
|
* error's `_tag`; `message` is its own rendering plus the remediation,
|
|
85
|
-
* composed through
|
|
32
|
+
* composed through `ToolFailure.message`.
|
|
86
33
|
*
|
|
87
34
|
* @public
|
|
88
35
|
*/
|
|
89
36
|
var EngineError = class extends Schema.TaggedError()("EngineError", {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
remediation: Remediation
|
|
37
|
+
...ToolFailure.fields,
|
|
38
|
+
source: Schema.String
|
|
93
39
|
}) {};
|
|
94
40
|
/**
|
|
95
41
|
* No Biome binary could be located. `message` is composed through
|
|
96
|
-
*
|
|
42
|
+
* `ToolFailure.message`.
|
|
97
43
|
*
|
|
98
44
|
* @public
|
|
99
45
|
*/
|
|
100
|
-
var BiomeUnavailable = class extends Schema.TaggedError()("BiomeUnavailable", {
|
|
101
|
-
message: Schema.String,
|
|
102
|
-
remediation: Remediation
|
|
103
|
-
}) {};
|
|
46
|
+
var BiomeUnavailable = class extends Schema.TaggedError()("BiomeUnavailable", { ...ToolFailure.fields }) {};
|
|
104
47
|
/**
|
|
105
48
|
* Biome itself failed (exit status above 1, a spawn error, or a timeout) —
|
|
106
49
|
* distinct from "lint issues found", which is a successful result. `message`
|
|
107
|
-
* is composed through
|
|
50
|
+
* is composed through `ToolFailure.message`.
|
|
108
51
|
*
|
|
109
52
|
* @public
|
|
110
53
|
*/
|
|
111
54
|
var BiomeFailed = class extends Schema.TaggedError()("BiomeFailed", {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
remediation: Remediation
|
|
55
|
+
...ToolFailure.fields,
|
|
56
|
+
exitCode: Schema.optionalKey(Schema.Number)
|
|
115
57
|
}) {};
|
|
116
58
|
/** The one failure schema every savvy-mcp tool declares. @public */
|
|
117
59
|
const McpToolError = Schema.Union([
|
|
@@ -130,13 +72,13 @@ const WORKSPACE_REMEDIATION = {
|
|
|
130
72
|
* Build a {@link WorkspaceNotFound} for the directory the caller asked about.
|
|
131
73
|
* The kit's own `WorkspaceRootNotFoundError` message renders the search path
|
|
132
74
|
* and probed markers; it is not echoed because it embeds the untruncated
|
|
133
|
-
* caller value, which `cwd` already carries through
|
|
75
|
+
* caller value, which `cwd` already carries through `ToolFailure.truncate`.
|
|
134
76
|
*
|
|
135
77
|
* @public
|
|
136
78
|
*/
|
|
137
79
|
const workspaceNotFound = (cwd) => new WorkspaceNotFound({
|
|
138
80
|
cwd,
|
|
139
|
-
message:
|
|
81
|
+
message: ToolFailure.message(`No workspace root was found walking up from "${ToolFailure.truncate(cwd)}".`, WORKSPACE_REMEDIATION),
|
|
140
82
|
remediation: WORKSPACE_REMEDIATION
|
|
141
83
|
});
|
|
142
84
|
/**
|
|
@@ -147,21 +89,21 @@ const workspaceNotFound = (cwd) => new WorkspaceNotFound({
|
|
|
147
89
|
*/
|
|
148
90
|
const invalidArgument = (argument, raw, remediation) => new InvalidArgument({
|
|
149
91
|
argument,
|
|
150
|
-
message:
|
|
92
|
+
message: ToolFailure.message(raw, remediation),
|
|
151
93
|
remediation
|
|
152
94
|
});
|
|
153
95
|
/**
|
|
154
96
|
* Build an {@link EngineError} from a silk-effects typed error. Every engine
|
|
155
97
|
* error in this server renders itself through a `message` getter, so that
|
|
156
|
-
* rendering is the raw message — passed through
|
|
157
|
-
*
|
|
98
|
+
* rendering is the raw message — passed through `ToolFailure.truncate` at
|
|
99
|
+
* `ToolFailure.ENGINE_ECHO_LIMIT`, since the kit embeds caller values in it;
|
|
158
100
|
* `source` keeps the tag for anything that inspects the typed error directly.
|
|
159
101
|
*
|
|
160
102
|
* @public
|
|
161
103
|
*/
|
|
162
104
|
const engineError = (cause, remediation) => new EngineError({
|
|
163
105
|
source: cause._tag,
|
|
164
|
-
message:
|
|
106
|
+
message: ToolFailure.message(ToolFailure.truncate(cause.message, ToolFailure.ENGINE_ECHO_LIMIT), remediation),
|
|
165
107
|
remediation
|
|
166
108
|
});
|
|
167
109
|
/**
|
|
@@ -179,4 +121,4 @@ const engineError = (cause, remediation) => new EngineError({
|
|
|
179
121
|
const mapEngineError = (requestedCwd, remediation) => (cause) => cause._tag === "WorkspaceRootNotFoundError" ? workspaceNotFound(requestedCwd) : engineError(cause, remediation);
|
|
180
122
|
|
|
181
123
|
//#endregion
|
|
182
|
-
export { BiomeFailed, BiomeUnavailable,
|
|
124
|
+
export { BiomeFailed, BiomeUnavailable, EngineError, InvalidArgument, McpToolError, WorkspaceNotFound, engineError, invalidArgument, mapEngineError, workspaceNotFound };
|
package/index.d.ts
CHANGED
|
@@ -1,82 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Distribution } from "@effected/engine";
|
|
2
|
+
import { FileSystem, Layer, Path, Schema, Stdio } from "effect";
|
|
2
3
|
import { WorkspaceRoot } from "@effected/workspaces";
|
|
3
4
|
import { Changesets, Repos, SilkWorkspaceAnalyzer, Turbo } from "@savvy-web/silk-effects";
|
|
4
5
|
import { ChildProcessSpawner } from "effect/unstable/process";
|
|
5
6
|
import { Tool, Toolkit } from "effect/unstable/ai";
|
|
6
7
|
//#region src/errors.d.ts
|
|
7
|
-
/** What a caller should do next about a failed tool call. @public */
|
|
8
|
-
export declare const Remediation: Schema.Struct<{
|
|
9
|
-
readonly hint: Schema.String;
|
|
10
|
-
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
11
|
-
}>;
|
|
12
|
-
/** @public */
|
|
13
|
-
export type Remediation = typeof Remediation.Type;
|
|
14
|
-
/**
|
|
15
|
-
* Compose a self-contained wire message from a raw cause message and its
|
|
16
|
-
* remediation: the human message, then the hint, then `Try <suggestedTool>.`
|
|
17
|
-
* when one is present. Every {@link McpToolError} member's `message` is built
|
|
18
|
-
* through this at construction, because `message` is the only field a
|
|
19
|
-
* declared failure delivers to the wire.
|
|
20
|
-
*
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export declare const composeRemediatedMessage: (message: string, remediation: Remediation) => string;
|
|
24
|
-
/**
|
|
25
|
-
* Truncate a caller-supplied value before it is echoed back inside an error's
|
|
26
|
-
* `message`. Without this a pathological argument (a multi-megabyte `cwd`,
|
|
27
|
-
* say) is echoed once in the response's `content[0].text` and once more in the
|
|
28
|
-
* corresponding log line, burning an agent's context twice on what is usually
|
|
29
|
-
* a typo.
|
|
30
|
-
*
|
|
31
|
-
* @public
|
|
32
|
-
*/
|
|
33
|
-
export declare const truncateEchoed: (value: string, limit?: number) => string;
|
|
34
8
|
declare const WorkspaceNotFound_base: Schema.Class<WorkspaceNotFound, Schema.TaggedStruct<"WorkspaceNotFound", {
|
|
35
|
-
readonly cwd: Schema.String;
|
|
36
9
|
readonly message: Schema.String;
|
|
37
10
|
readonly remediation: Schema.Struct<{
|
|
38
11
|
readonly hint: Schema.String;
|
|
39
12
|
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
13
|
+
readonly suggestedArgs: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
40
14
|
}>;
|
|
15
|
+
readonly cwd: Schema.String;
|
|
41
16
|
}>, import("effect/Cause").YieldableError>;
|
|
42
17
|
/**
|
|
43
18
|
* No workspace root was found walking up from the requested directory.
|
|
44
|
-
* `message` is composed through
|
|
45
|
-
*
|
|
19
|
+
* `message` is composed through `ToolFailure.message` at construction, so it
|
|
20
|
+
* is what reaches the wire as `content[0].text`.
|
|
46
21
|
*
|
|
47
22
|
* @public
|
|
48
23
|
*/
|
|
49
24
|
export declare class WorkspaceNotFound extends WorkspaceNotFound_base {}
|
|
50
25
|
declare const InvalidArgument_base: Schema.Class<InvalidArgument, Schema.TaggedStruct<"InvalidArgument", {
|
|
51
|
-
readonly argument: Schema.String;
|
|
52
26
|
readonly message: Schema.String;
|
|
53
27
|
readonly remediation: Schema.Struct<{
|
|
54
28
|
readonly hint: Schema.String;
|
|
55
29
|
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
30
|
+
readonly suggestedArgs: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
56
31
|
}>;
|
|
32
|
+
readonly argument: Schema.String;
|
|
57
33
|
}>, import("effect/Cause").YieldableError>;
|
|
58
34
|
/**
|
|
59
35
|
* A tool argument was structurally acceptable but semantically invalid — a
|
|
60
36
|
* `repos_manage` action missing the field it needs, a `biome_check` path
|
|
61
37
|
* outside the workspace, a `changeset_validate` directory that does not
|
|
62
|
-
* exist. `message` is composed through
|
|
38
|
+
* exist. `message` is composed through `ToolFailure.message`.
|
|
63
39
|
*
|
|
64
40
|
* @public
|
|
65
41
|
*/
|
|
66
42
|
export declare class InvalidArgument extends InvalidArgument_base {}
|
|
67
43
|
declare const EngineError_base: Schema.Class<EngineError, Schema.TaggedStruct<"EngineError", {
|
|
68
|
-
readonly source: Schema.String;
|
|
69
44
|
readonly message: Schema.String;
|
|
70
45
|
readonly remediation: Schema.Struct<{
|
|
71
46
|
readonly hint: Schema.String;
|
|
72
47
|
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
48
|
+
readonly suggestedArgs: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
73
49
|
}>;
|
|
50
|
+
readonly source: Schema.String;
|
|
74
51
|
}>, import("effect/Cause").YieldableError>;
|
|
75
52
|
/**
|
|
76
53
|
* A silk-effects engine program failed with one of its own typed errors
|
|
77
54
|
* (`TurboError`, `GitError`, `ReposConfigError`, …). `source` carries that
|
|
78
55
|
* error's `_tag`; `message` is its own rendering plus the remediation,
|
|
79
|
-
* composed through
|
|
56
|
+
* composed through `ToolFailure.message`.
|
|
80
57
|
*
|
|
81
58
|
* @public
|
|
82
59
|
*/
|
|
@@ -86,27 +63,29 @@ declare const BiomeUnavailable_base: Schema.Class<BiomeUnavailable, Schema.Tagge
|
|
|
86
63
|
readonly remediation: Schema.Struct<{
|
|
87
64
|
readonly hint: Schema.String;
|
|
88
65
|
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
66
|
+
readonly suggestedArgs: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
89
67
|
}>;
|
|
90
68
|
}>, import("effect/Cause").YieldableError>;
|
|
91
69
|
/**
|
|
92
70
|
* No Biome binary could be located. `message` is composed through
|
|
93
|
-
*
|
|
71
|
+
* `ToolFailure.message`.
|
|
94
72
|
*
|
|
95
73
|
* @public
|
|
96
74
|
*/
|
|
97
75
|
export declare class BiomeUnavailable extends BiomeUnavailable_base {}
|
|
98
76
|
declare const BiomeFailed_base: Schema.Class<BiomeFailed, Schema.TaggedStruct<"BiomeFailed", {
|
|
99
|
-
readonly exitCode: Schema.optionalKey<Schema.Number>;
|
|
100
77
|
readonly message: Schema.String;
|
|
101
78
|
readonly remediation: Schema.Struct<{
|
|
102
79
|
readonly hint: Schema.String;
|
|
103
80
|
readonly suggestedTool: Schema.optionalKey<Schema.String>;
|
|
81
|
+
readonly suggestedArgs: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
104
82
|
}>;
|
|
83
|
+
readonly exitCode: Schema.optionalKey<Schema.Number>;
|
|
105
84
|
}>, import("effect/Cause").YieldableError>;
|
|
106
85
|
/**
|
|
107
86
|
* Biome itself failed (exit status above 1, a spawn error, or a timeout) —
|
|
108
87
|
* distinct from "lint issues found", which is a successful result. `message`
|
|
109
|
-
* is composed through
|
|
88
|
+
* is composed through `ToolFailure.message`.
|
|
110
89
|
*
|
|
111
90
|
* @public
|
|
112
91
|
*/
|
|
@@ -116,18 +95,6 @@ export declare const McpToolError: Schema.Union<readonly [typeof WorkspaceNotFou
|
|
|
116
95
|
/** @public */
|
|
117
96
|
export type McpToolError = typeof McpToolError.Type;
|
|
118
97
|
//#endregion
|
|
119
|
-
//#region src/markdown.d.ts
|
|
120
|
-
declare const SilkMarkdown_base: Context.ServiceClass<SilkMarkdown, "@savvy-web/mcp/SilkMarkdown", (data: unknown) => string>;
|
|
121
|
-
/**
|
|
122
|
-
* Renders a tool's decoded success value as the markdown transcript an agent
|
|
123
|
-
* reads. Typed over `unknown` because the annotation is read generically at
|
|
124
|
-
* registration; each tool supplies `Schema.decodeUnknownSync(<X>AsMarkdown)`,
|
|
125
|
-
* whose own decoder is the type guard.
|
|
126
|
-
*
|
|
127
|
-
* @public
|
|
128
|
-
*/
|
|
129
|
-
export declare class SilkMarkdown extends SilkMarkdown_base {}
|
|
130
|
-
//#endregion
|
|
131
98
|
//#region src/runtime.d.ts
|
|
132
99
|
/**
|
|
133
100
|
* Every service the MCP runtime provides to the tool handlers.
|
|
@@ -173,25 +140,38 @@ export declare const makeSilkRuntimeLayer: (cwd: string) => Layer.Layer<McpServi
|
|
|
173
140
|
/**
|
|
174
141
|
* Everything {@link ServerLayer} still needs from the platform: the three
|
|
175
142
|
* services `makeSilkRuntimeLayer` requires, plus `Stdio`, which
|
|
176
|
-
* `
|
|
143
|
+
* `McpStdio.layer` itself requires. `NodeServices.layer` supplies all
|
|
177
144
|
* four in `main.ts`; tests swap `Stdio` for `Stdio.layerTest`.
|
|
178
145
|
*
|
|
179
146
|
* @public
|
|
180
147
|
*/
|
|
181
148
|
type PlatformServices = FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner | Stdio.Stdio;
|
|
149
|
+
/**
|
|
150
|
+
* Options for {@link ServerLayer}.
|
|
151
|
+
*
|
|
152
|
+
* @public
|
|
153
|
+
*/
|
|
154
|
+
interface ServerOptions {
|
|
155
|
+
/**
|
|
156
|
+
* The carrier this server was installed through (for example
|
|
157
|
+
* `@savvy-web/silk`), rendered into `serverInfo.version` as
|
|
158
|
+
* `" via <name> <version>"`. Absent for a direct install.
|
|
159
|
+
*/
|
|
160
|
+
readonly distribution?: Distribution | undefined;
|
|
161
|
+
}
|
|
182
162
|
/**
|
|
183
163
|
* The whole server as one layer: the ten-tool toolkit, the silk-effects
|
|
184
|
-
* runtime discharging its dependencies, over `
|
|
164
|
+
* runtime discharging its dependencies, over `@effected/mcp`'s
|
|
165
|
+
* `McpStdio.layer`.
|
|
185
166
|
*
|
|
186
|
-
* `
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* failure there is an implementer-time defect, not a runtime condition.
|
|
167
|
+
* `McpStdio.layer` is `McpServer.layerStdio` with the kit's default
|
|
168
|
+
* `protocols` (the stateless `2026-07-28` adapter first, then the two newest
|
|
169
|
+
* stateful ones — see gotcha 2), `LogToStderr` merged into its output, a
|
|
170
|
+
* stdin guard answering a non-JSON line with `-32700`, and `Layer.orDie`.
|
|
191
171
|
*
|
|
192
172
|
* @public
|
|
193
173
|
*/
|
|
194
|
-
export declare const ServerLayer: (cwd: string) => Layer.Layer<never, never, PlatformServices>;
|
|
174
|
+
export declare const ServerLayer: (cwd: string, options?: ServerOptions) => Layer.Layer<never, never, PlatformServices>;
|
|
195
175
|
//#endregion
|
|
196
176
|
//#region src/tools/biome-check.d.ts
|
|
197
177
|
/**
|
|
@@ -741,5 +721,5 @@ export declare const ToolsLayer: (cwd: string) => Layer.Layer<Tool.HandlersFor<S
|
|
|
741
721
|
*/
|
|
742
722
|
export declare const CURRENT_MCP_VERSION: any;
|
|
743
723
|
//#endregion
|
|
744
|
-
export type { McpServices, PlatformServices, SilkTools };
|
|
724
|
+
export type { McpServices, PlatformServices, ServerOptions, SilkTools };
|
|
745
725
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { BiomeFailed, BiomeUnavailable, EngineError, InvalidArgument, McpToolError,
|
|
2
|
-
import { SilkMarkdown } from "./markdown.js";
|
|
1
|
+
import { BiomeFailed, BiomeUnavailable, EngineError, InvalidArgument, McpToolError, WorkspaceNotFound } from "./errors.js";
|
|
3
2
|
import { makeSilkRuntimeLayer } from "./runtime.js";
|
|
4
3
|
import { SilkToolkit, ToolsLayer } from "./toolkit.js";
|
|
5
4
|
import { CURRENT_MCP_VERSION } from "./version.js";
|
|
6
5
|
import { ServerLayer } from "./server.js";
|
|
7
6
|
|
|
8
|
-
export { BiomeFailed, BiomeUnavailable, CURRENT_MCP_VERSION, EngineError, InvalidArgument, McpToolError,
|
|
7
|
+
export { BiomeFailed, BiomeUnavailable, CURRENT_MCP_VERSION, EngineError, InvalidArgument, McpToolError, ServerLayer, SilkToolkit, ToolsLayer, WorkspaceNotFound, makeSilkRuntimeLayer };
|
package/main.d.ts
CHANGED
|
@@ -1,25 +1,30 @@
|
|
|
1
|
+
import { Distribution } from "@effected/engine";
|
|
1
2
|
//#region src/main.d.ts
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
* server layer launched over stdio.
|
|
4
|
+
* Options for {@link main}.
|
|
5
5
|
*
|
|
6
|
-
* @
|
|
7
|
-
* No static imports of the server graph — every module reachable from the
|
|
8
|
-
* MCP tool surface is imported dynamically, after the crash guards are
|
|
9
|
-
* registered, so an error during that import (or anything downstream) is
|
|
10
|
-
* caught by `uncaughtException`/`unhandledRejection` rather than crashing
|
|
11
|
-
* before a handler exists.
|
|
12
|
-
*
|
|
13
|
-
* @packageDocumentation
|
|
6
|
+
* @public
|
|
14
7
|
*/
|
|
8
|
+
export interface MainOptions {
|
|
9
|
+
/**
|
|
10
|
+
* The carrier this bin was installed through, for example
|
|
11
|
+
* `{ name: "@savvy-web/silk", version }`; rendered into the server's
|
|
12
|
+
* reported version. Absent for a direct install.
|
|
13
|
+
*/
|
|
14
|
+
readonly distribution?: Distribution | undefined;
|
|
15
|
+
}
|
|
15
16
|
/**
|
|
16
17
|
* Run the savvy MCP server over stdio. Owns the process.
|
|
17
18
|
*
|
|
18
19
|
* @remarks
|
|
19
|
-
*
|
|
20
|
+
* The project directory is the first positional argument, then
|
|
21
|
+
* `SAVVY_MCP_PROJECT_DIR`, then `CLAUDE_PROJECT_DIR`, then the working
|
|
22
|
+
* directory — an empty value or an unsubstituted `${VAR}` placeholder is
|
|
23
|
+
* skipped (`LaunchContext.projectDir`). NO static imports of the server
|
|
24
|
+
* graph — see the module remarks.
|
|
20
25
|
*
|
|
21
26
|
* @public
|
|
22
27
|
*/
|
|
23
|
-
export declare const main: () => Promise<void>;
|
|
28
|
+
export declare const main: (options?: MainOptions) => Promise<void>;
|
|
24
29
|
//#endregion
|
|
25
30
|
//# sourceMappingURL=main.d.ts.map
|
package/main.js
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
//#region src/main.ts
|
|
2
|
-
/**
|
|
3
|
-
* Owns the `savvy-mcp` process: crash guards, project-root resolution, and the
|
|
4
|
-
* server layer launched over stdio.
|
|
5
|
-
*
|
|
6
|
-
* @remarks
|
|
7
|
-
* No static imports of the server graph — every module reachable from the
|
|
8
|
-
* MCP tool surface is imported dynamically, after the crash guards are
|
|
9
|
-
* registered, so an error during that import (or anything downstream) is
|
|
10
|
-
* caught by `uncaughtException`/`unhandledRejection` rather than crashing
|
|
11
|
-
* before a handler exists.
|
|
12
|
-
*
|
|
13
|
-
* @packageDocumentation
|
|
14
|
-
*/
|
|
15
|
-
/* v8 ignore start -- process bootstrap; covered by the server-lifecycle e2e and the silk bins e2e */
|
|
16
2
|
const fatal = (label, error) => {
|
|
17
3
|
process.stderr.write(`savvy-mcp: ${label}: ${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
18
4
|
process.exit(1);
|
|
@@ -21,20 +7,29 @@ const fatal = (label, error) => {
|
|
|
21
7
|
* Run the savvy MCP server over stdio. Owns the process.
|
|
22
8
|
*
|
|
23
9
|
* @remarks
|
|
24
|
-
*
|
|
10
|
+
* The project directory is the first positional argument, then
|
|
11
|
+
* `SAVVY_MCP_PROJECT_DIR`, then `CLAUDE_PROJECT_DIR`, then the working
|
|
12
|
+
* directory — an empty value or an unsubstituted `${VAR}` placeholder is
|
|
13
|
+
* skipped (`LaunchContext.projectDir`). NO static imports of the server
|
|
14
|
+
* graph — see the module remarks.
|
|
25
15
|
*
|
|
26
16
|
* @public
|
|
27
17
|
*/
|
|
28
|
-
const main = async () => {
|
|
18
|
+
const main = async (options = {}) => {
|
|
29
19
|
process.on("uncaughtException", (e) => fatal("uncaught exception", e));
|
|
30
20
|
process.on("unhandledRejection", (r) => fatal("unhandled rejection", r));
|
|
31
21
|
const { NodeRuntime, NodeServices } = await import("@effect/platform-node");
|
|
32
|
-
const {
|
|
33
|
-
const {
|
|
22
|
+
const { Layer } = await import("effect");
|
|
23
|
+
const { LaunchContext } = await import("@effected/engine");
|
|
24
|
+
const { McpStdio } = await import("@effected/mcp");
|
|
34
25
|
const { ServerLayer } = await import("./server.js");
|
|
35
|
-
const cwd =
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
const cwd = LaunchContext.projectDir({
|
|
27
|
+
argv: process.argv.slice(2, 3),
|
|
28
|
+
env: process.env,
|
|
29
|
+
keys: ["SAVVY_MCP_PROJECT_DIR", "CLAUDE_PROJECT_DIR"],
|
|
30
|
+
cwd: process.cwd()
|
|
31
|
+
});
|
|
32
|
+
NodeRuntime.runMain(McpStdio.launch(ServerLayer(cwd, options).pipe(Layer.provide(NodeServices.layer))), { teardown: McpStdio.teardown });
|
|
38
33
|
};
|
|
39
34
|
/* v8 ignore stop */
|
|
40
35
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The savvy MCP server — Silk Suite tooling and library knowledge for coding agents",
|
|
6
6
|
"homepage": "https://github.com/savvy-web/systems/tree/main/packages/mcp",
|
|
@@ -38,9 +38,12 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@effect/platform-node": "4.0.0-rc.117",
|
|
40
40
|
"@effected/commands": "^0.9.0",
|
|
41
|
+
"@effected/engine": "^0.1.0",
|
|
41
42
|
"@effected/git": "^0.17.0",
|
|
42
|
-
"@effected/
|
|
43
|
-
"@
|
|
43
|
+
"@effected/mcp": "^0.1.1",
|
|
44
|
+
"@effected/templates": "^0.8.0",
|
|
45
|
+
"@effected/workspaces": "^0.26.0",
|
|
46
|
+
"@savvy-web/silk-effects": "9.1.3",
|
|
44
47
|
"effect": "4.0.0-rc.117"
|
|
45
48
|
}
|
|
46
49
|
}
|