toolcraft 0.0.17 → 0.0.18
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/dist/cli.d.ts +2 -0
- package/dist/cli.js +833 -124
- package/dist/error-report.d.ts +39 -0
- package/dist/error-report.js +330 -0
- package/dist/human-in-loop/approval-tasks.js +11 -8
- package/dist/human-in-loop/approvals-commands.js +21 -20
- package/dist/human-in-loop/default-provider.js +5 -3
- package/dist/human-in-loop/runner.js +45 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +55 -35
- package/dist/json-schema-converter.d.ts +1 -0
- package/dist/json-schema-converter.js +102 -52
- package/dist/mcp-proxy.d.ts +1 -0
- package/dist/mcp-proxy.js +13 -6
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.js +131 -55
- package/dist/sdk.d.ts +4 -2
- package/dist/sdk.js +132 -48
- package/dist/source-snippet.d.ts +8 -0
- package/dist/source-snippet.js +42 -0
- package/dist/stack-trim.d.ts +4 -0
- package/dist/stack-trim.js +70 -0
- package/dist/suggest.d.ts +4 -0
- package/dist/suggest.js +46 -0
- package/dist/user-error.d.ts +3 -0
- package/dist/user-error.js +7 -1
- package/dist/validation-errors.d.ts +5 -0
- package/dist/validation-errors.js +18 -0
- package/node_modules/@poe-code/design-system/dist/components/help-formatter-plain.d.ts +1 -0
- package/node_modules/@poe-code/design-system/dist/components/help-formatter-plain.js +1 -1
- package/node_modules/@poe-code/design-system/dist/components/text.d.ts +1 -0
- package/node_modules/@poe-code/design-system/dist/components/text.js +8 -0
- package/node_modules/@poe-code/design-system/dist/dashboard/buffer.js +8 -1
- package/node_modules/@poe-code/design-system/dist/dashboard/keymap.d.ts +5 -0
- package/node_modules/@poe-code/design-system/dist/dashboard/keymap.js +146 -12
- package/node_modules/@poe-code/design-system/dist/dashboard/terminal.js +31 -0
- package/node_modules/@poe-code/design-system/dist/dashboard/types.d.ts +1 -0
- package/node_modules/@poe-code/design-system/dist/explorer/actions.d.ts +16 -0
- package/node_modules/@poe-code/design-system/dist/explorer/actions.js +39 -0
- package/node_modules/@poe-code/design-system/dist/explorer/demo.d.ts +13 -0
- package/node_modules/@poe-code/design-system/dist/explorer/demo.js +297 -0
- package/node_modules/@poe-code/design-system/dist/explorer/events.d.ts +61 -0
- package/node_modules/@poe-code/design-system/dist/explorer/events.js +1 -0
- package/node_modules/@poe-code/design-system/dist/explorer/filter.d.ts +10 -0
- package/node_modules/@poe-code/design-system/dist/explorer/filter.js +95 -0
- package/node_modules/@poe-code/design-system/dist/explorer/index.d.ts +8 -0
- package/node_modules/@poe-code/design-system/dist/explorer/index.js +8 -0
- package/node_modules/@poe-code/design-system/dist/explorer/jobs.d.ts +7 -0
- package/node_modules/@poe-code/design-system/dist/explorer/jobs.js +59 -0
- package/node_modules/@poe-code/design-system/dist/explorer/keymap.d.ts +21 -0
- package/node_modules/@poe-code/design-system/dist/explorer/keymap.js +363 -0
- package/node_modules/@poe-code/design-system/dist/explorer/layout.d.ts +20 -0
- package/node_modules/@poe-code/design-system/dist/explorer/layout.js +73 -0
- package/node_modules/@poe-code/design-system/dist/explorer/reducer.d.ts +9 -0
- package/node_modules/@poe-code/design-system/dist/explorer/reducer.js +704 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/detail.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/detail.js +96 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/footer.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/footer.js +49 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/header.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/header.js +56 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/index.d.ts +8 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/index.js +61 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/list.d.ts +4 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/list.js +106 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/modal.d.ts +3 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/modal.js +91 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/test-fixtures.d.ts +8 -0
- package/node_modules/@poe-code/design-system/dist/explorer/render/test-fixtures.js +156 -0
- package/node_modules/@poe-code/design-system/dist/explorer/runtime.d.ts +2 -0
- package/node_modules/@poe-code/design-system/dist/explorer/runtime.js +282 -0
- package/node_modules/@poe-code/design-system/dist/explorer/runtime.test-helpers.d.ts +50 -0
- package/node_modules/@poe-code/design-system/dist/explorer/runtime.test-helpers.js +101 -0
- package/node_modules/@poe-code/design-system/dist/explorer/state.d.ts +130 -0
- package/node_modules/@poe-code/design-system/dist/explorer/state.js +87 -0
- package/node_modules/@poe-code/design-system/dist/explorer/theme.d.ts +27 -0
- package/node_modules/@poe-code/design-system/dist/explorer/theme.js +97 -0
- package/node_modules/@poe-code/design-system/dist/index.d.ts +3 -0
- package/node_modules/@poe-code/design-system/dist/index.js +3 -0
- package/node_modules/@poe-code/design-system/package.json +1 -0
- package/package.json +6 -2
package/dist/mcp.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type SDKTransport, type Server as TinyServer } from "tiny-stdio-mcp-server";
|
|
2
2
|
import type { Group } from "./index.js";
|
|
3
|
+
import { type ErrorReportsOption } from "./error-report.js";
|
|
3
4
|
import { type HumanInLoopRuntimeOptions } from "./human-in-loop/index.js";
|
|
4
5
|
type Casing = "snake" | "camel";
|
|
5
6
|
type CmdkitServer = Omit<TinyServer, "connect"> & {
|
|
@@ -27,6 +28,7 @@ export interface RunMCPOptions<TServices extends object = Record<string, unknown
|
|
|
27
28
|
*/
|
|
28
29
|
omitRootToolNamePrefix?: boolean;
|
|
29
30
|
services?: TServices;
|
|
31
|
+
errorReports?: ErrorReportsOption;
|
|
30
32
|
/**
|
|
31
33
|
* Controls MCP input-schema key casing and accepted argument-key casing.
|
|
32
34
|
*
|
package/dist/mcp.js
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
import { access, readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import { createServer, JSON_RPC_ERROR_CODES, ToolError
|
|
2
|
+
import { createServer, JSON_RPC_ERROR_CODES, ToolError } from "tiny-stdio-mcp-server";
|
|
3
3
|
import { toJsonSchema } from "toolcraft-schema";
|
|
4
|
-
import { UserError, assertCommandRequirements, resolveCommandSecrets } from "./index.js";
|
|
4
|
+
import { ToolcraftBugError, UserError, assertCommandRequirements, resolveCommandSecrets } from "./index.js";
|
|
5
|
+
import { writeErrorReport } from "./error-report.js";
|
|
5
6
|
import { mergeApprovalsGroup } from "./human-in-loop/approvals-commands.js";
|
|
6
|
-
import { ApprovalDeclinedError, invokeWithHumanInLoop
|
|
7
|
+
import { ApprovalDeclinedError, invokeWithHumanInLoop } from "./human-in-loop/index.js";
|
|
7
8
|
import { hasMcpProxyGroups, resolveMcpProxies } from "./mcp-proxy.js";
|
|
8
9
|
import { getExpectedNumberDescription, isValidNumberSchemaValue } from "./number-schema.js";
|
|
9
10
|
import { findEntrypointPackageMetadata } from "./package-metadata.js";
|
|
10
11
|
import { filterSchemaForScope } from "./schema-scope.js";
|
|
11
|
-
|
|
12
|
+
import { enableSourceMaps } from "./stack-trim.js";
|
|
13
|
+
import { suggest } from "./suggest.js";
|
|
14
|
+
import { throwValidationErrors } from "./validation-errors.js";
|
|
15
|
+
const RESERVED_SERVICE_NAMES = new Set([
|
|
16
|
+
"params",
|
|
17
|
+
"secrets",
|
|
18
|
+
"fetch",
|
|
19
|
+
"fs",
|
|
20
|
+
"env",
|
|
21
|
+
"progress",
|
|
22
|
+
"runtimeOptions",
|
|
23
|
+
"root"
|
|
24
|
+
]);
|
|
25
|
+
const RESERVED_SERVICE_NAMES_MESSAGE = "Available reserved names: params, secrets, fetch, fs, env, progress, runtimeOptions, root.";
|
|
12
26
|
function normalizeRoots(roots) {
|
|
13
27
|
if (!Array.isArray(roots)) {
|
|
14
28
|
return roots;
|
|
@@ -18,7 +32,7 @@ function normalizeRoots(roots) {
|
|
|
18
32
|
name: "",
|
|
19
33
|
aliases: [],
|
|
20
34
|
secrets: {},
|
|
21
|
-
children: roots
|
|
35
|
+
children: roots
|
|
22
36
|
};
|
|
23
37
|
}
|
|
24
38
|
function splitWords(value) {
|
|
@@ -39,7 +53,9 @@ function splitWords(value) {
|
|
|
39
53
|
const isUppercase = char !== lower && char === upper;
|
|
40
54
|
const previous = value[index - 1];
|
|
41
55
|
const next = value[index + 1];
|
|
42
|
-
const previousIsLowercase = previous !== undefined &&
|
|
56
|
+
const previousIsLowercase = previous !== undefined &&
|
|
57
|
+
previous === previous.toLowerCase() &&
|
|
58
|
+
previous !== previous.toUpperCase();
|
|
43
59
|
const nextIsLowercase = next !== undefined && next === next.toLowerCase() && next !== next.toUpperCase();
|
|
44
60
|
if (isUppercase && current.length > 0 && (previousIsLowercase || nextIsLowercase)) {
|
|
45
61
|
words.push(current.toLowerCase());
|
|
@@ -59,7 +75,7 @@ function formatSegment(segment, casing) {
|
|
|
59
75
|
return words.join("_");
|
|
60
76
|
}
|
|
61
77
|
return words
|
|
62
|
-
.map((word, index) => index === 0 ? word : `${word[0]?.toUpperCase() ?? ""}${word.slice(1)}`)
|
|
78
|
+
.map((word, index) => (index === 0 ? word : `${word[0]?.toUpperCase() ?? ""}${word.slice(1)}`))
|
|
63
79
|
.join("");
|
|
64
80
|
}
|
|
65
81
|
function unwrapOptional(schema) {
|
|
@@ -88,42 +104,45 @@ function createFs() {
|
|
|
88
104
|
catch {
|
|
89
105
|
return false;
|
|
90
106
|
}
|
|
91
|
-
}
|
|
107
|
+
}
|
|
92
108
|
};
|
|
93
109
|
}
|
|
94
110
|
function createEnv(values = process.env) {
|
|
95
111
|
return {
|
|
96
112
|
get(key) {
|
|
97
113
|
return values[key];
|
|
98
|
-
}
|
|
114
|
+
}
|
|
99
115
|
};
|
|
100
116
|
}
|
|
101
117
|
function validateServices(services) {
|
|
102
118
|
for (const name of Object.keys(services)) {
|
|
103
119
|
if (RESERVED_SERVICE_NAMES.has(name)) {
|
|
104
|
-
throw new Error(`Service name "${name}" is reserved. Choose a different name
|
|
120
|
+
throw new Error(`Service name "${name}" is reserved. Choose a different name. ${RESERVED_SERVICE_NAMES_MESSAGE}`);
|
|
105
121
|
}
|
|
106
122
|
}
|
|
107
123
|
}
|
|
124
|
+
function formatAvailableList(values) {
|
|
125
|
+
return `Available: ${[...values].sort().join(", ")}.`;
|
|
126
|
+
}
|
|
108
127
|
function applySchemaCasing(schema, casing) {
|
|
109
128
|
if (schema.type !== "object" || schema.properties === undefined) {
|
|
110
129
|
if (schema.type === "array" && schema.items !== undefined) {
|
|
111
130
|
return {
|
|
112
131
|
...schema,
|
|
113
|
-
items: applySchemaCasing(schema.items, casing)
|
|
132
|
+
items: applySchemaCasing(schema.items, casing)
|
|
114
133
|
};
|
|
115
134
|
}
|
|
116
135
|
return schema;
|
|
117
136
|
}
|
|
118
137
|
const properties = Object.fromEntries(Object.entries(schema.properties).map(([key, value]) => [
|
|
119
138
|
formatSegment(key, casing),
|
|
120
|
-
applySchemaCasing(value, casing)
|
|
139
|
+
applySchemaCasing(value, casing)
|
|
121
140
|
]));
|
|
122
141
|
const required = schema.required?.map((key) => formatSegment(key, casing));
|
|
123
142
|
return {
|
|
124
143
|
...schema,
|
|
125
144
|
properties,
|
|
126
|
-
...(required === undefined ? {} : { required })
|
|
145
|
+
...(required === undefined ? {} : { required })
|
|
127
146
|
};
|
|
128
147
|
}
|
|
129
148
|
function collectParamSummaries(schema, casing, path = [], inheritedOptional = false) {
|
|
@@ -175,14 +194,14 @@ function enumerateTools(root, casing, allowlist, omitRootToolNamePrefix) {
|
|
|
175
194
|
return;
|
|
176
195
|
}
|
|
177
196
|
if (params === undefined || params.kind !== "object") {
|
|
178
|
-
throw new
|
|
197
|
+
throw new ToolcraftBugError(`command "${name}" must define an object params schema for MCP.`);
|
|
179
198
|
}
|
|
180
199
|
tools.push({
|
|
181
200
|
command: node,
|
|
182
201
|
commandPath: [...commandPath, node.name].join("."),
|
|
183
202
|
name,
|
|
184
203
|
description: buildToolDescription(node.description, params, casing),
|
|
185
|
-
inputSchema: applySchemaCasing(toJsonSchema(params), casing)
|
|
204
|
+
inputSchema: applySchemaCasing(toJsonSchema(params), casing)
|
|
186
205
|
});
|
|
187
206
|
return;
|
|
188
207
|
}
|
|
@@ -212,13 +231,13 @@ function renderPendingApproval(pending) {
|
|
|
212
231
|
content: [
|
|
213
232
|
{
|
|
214
233
|
type: "text",
|
|
215
|
-
text: `Queued for human approval (id: ${pending.approvalId}). Track with \`toolcraft approvals show ${pending.approvalId}
|
|
234
|
+
text: `Queued for human approval (id: ${pending.approvalId}). Track with \`toolcraft approvals show ${pending.approvalId}\`.`
|
|
216
235
|
},
|
|
217
236
|
{
|
|
218
237
|
type: "text",
|
|
219
|
-
text: JSON.stringify(pending)
|
|
220
|
-
}
|
|
221
|
-
]
|
|
238
|
+
text: JSON.stringify(pending)
|
|
239
|
+
}
|
|
240
|
+
]
|
|
222
241
|
};
|
|
223
242
|
}
|
|
224
243
|
function renderDeclinedApproval(error) {
|
|
@@ -227,26 +246,45 @@ function renderDeclinedApproval(error) {
|
|
|
227
246
|
content: [
|
|
228
247
|
{
|
|
229
248
|
type: "text",
|
|
230
|
-
text: error.reason === undefined ? "Declined." : `Declined: ${error.reason}
|
|
249
|
+
text: error.reason === undefined ? "Declined." : `Declined: ${error.reason}`
|
|
231
250
|
},
|
|
232
251
|
{
|
|
233
252
|
type: "text",
|
|
234
253
|
text: JSON.stringify({
|
|
235
254
|
outcome: "declined",
|
|
236
255
|
reason: error.reason,
|
|
237
|
-
commandPath: error.commandPath
|
|
238
|
-
})
|
|
239
|
-
}
|
|
240
|
-
]
|
|
256
|
+
commandPath: error.commandPath
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
]
|
|
241
260
|
};
|
|
242
261
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return value
|
|
262
|
+
function formatEnumError(value, schema, label) {
|
|
263
|
+
const suggestionLine = typeof value === "string"
|
|
264
|
+
? formatEnumSuggestionLine(value, schema.values.map((candidate) => String(candidate)))
|
|
265
|
+
: " ";
|
|
266
|
+
return `Invalid value for "${label}".${suggestionLine}Expected one of: ${schema.values.map((candidate) => String(candidate)).join(", ")}, got ${describeReceived(value)}.`;
|
|
248
267
|
}
|
|
249
|
-
function
|
|
268
|
+
function formatEnumSuggestionLine(value, values) {
|
|
269
|
+
const suggestions = suggest(value, values);
|
|
270
|
+
return suggestions.length > 0 ? ` Did you mean: ${suggestions.join(", ")}?\n` : " ";
|
|
271
|
+
}
|
|
272
|
+
function describeReceived(value) {
|
|
273
|
+
if (value === null)
|
|
274
|
+
return "null";
|
|
275
|
+
if (value === undefined)
|
|
276
|
+
return "missing";
|
|
277
|
+
if (Array.isArray(value))
|
|
278
|
+
return `array(${value.length})`;
|
|
279
|
+
if (typeof value === "object")
|
|
280
|
+
return "object";
|
|
281
|
+
if (typeof value === "string") {
|
|
282
|
+
const s = value.length > 40 ? `${value.slice(0, 40)}…` : value;
|
|
283
|
+
return `${JSON.stringify(s)}`;
|
|
284
|
+
}
|
|
285
|
+
return JSON.stringify(value);
|
|
286
|
+
}
|
|
287
|
+
function validateSchemaValue(schema, value, casing, label, errors) {
|
|
250
288
|
const unwrappedSchema = unwrapOptional(schema);
|
|
251
289
|
if (value === null && unwrappedSchema.nullable === true) {
|
|
252
290
|
return null;
|
|
@@ -254,33 +292,53 @@ function validateSchemaValue(schema, value, casing, label) {
|
|
|
254
292
|
switch (unwrappedSchema.kind) {
|
|
255
293
|
case "string":
|
|
256
294
|
if (typeof value !== "string") {
|
|
257
|
-
|
|
295
|
+
errors.push({
|
|
296
|
+
path: label,
|
|
297
|
+
message: `Invalid value for "${label}". Expected a string, got ${describeReceived(value)}.`
|
|
298
|
+
});
|
|
258
299
|
}
|
|
259
300
|
return value;
|
|
260
301
|
case "number":
|
|
261
302
|
if (!isValidNumberSchemaValue(value, unwrappedSchema)) {
|
|
262
|
-
|
|
303
|
+
errors.push({
|
|
304
|
+
path: label,
|
|
305
|
+
message: `Invalid value for "${label}". Expected ${getExpectedNumberDescription(unwrappedSchema)}, got ${describeReceived(value)}.`
|
|
306
|
+
});
|
|
263
307
|
}
|
|
264
308
|
return value;
|
|
265
309
|
case "boolean":
|
|
266
310
|
if (typeof value !== "boolean") {
|
|
267
|
-
|
|
311
|
+
errors.push({
|
|
312
|
+
path: label,
|
|
313
|
+
message: `Invalid value for "${label}". Expected a boolean, got ${describeReceived(value)}.`
|
|
314
|
+
});
|
|
268
315
|
}
|
|
269
316
|
return value;
|
|
270
317
|
case "enum":
|
|
271
|
-
|
|
318
|
+
if (!unwrappedSchema.values.includes(value)) {
|
|
319
|
+
errors.push({ path: label, message: formatEnumError(value, unwrappedSchema, label) });
|
|
320
|
+
}
|
|
321
|
+
return value;
|
|
272
322
|
case "array":
|
|
273
323
|
if (!Array.isArray(value)) {
|
|
274
|
-
|
|
324
|
+
errors.push({
|
|
325
|
+
path: label,
|
|
326
|
+
message: `Invalid value for "${label}". Expected an array, got ${describeReceived(value)}.`
|
|
327
|
+
});
|
|
328
|
+
return value;
|
|
275
329
|
}
|
|
276
|
-
return value.map((item, index) => validateSchemaValue(unwrappedSchema.item, item, casing, `${label}[${index}]
|
|
330
|
+
return value.map((item, index) => validateSchemaValue(unwrappedSchema.item, item, casing, `${label}[${index}]`, errors));
|
|
277
331
|
case "object":
|
|
278
|
-
return validateObjectSchema(unwrappedSchema, value, casing, label);
|
|
332
|
+
return validateObjectSchema(unwrappedSchema, value, casing, label, errors);
|
|
279
333
|
}
|
|
280
334
|
}
|
|
281
|
-
function validateObjectSchema(schema, value, casing, label) {
|
|
335
|
+
function validateObjectSchema(schema, value, casing, label, errors) {
|
|
282
336
|
if (!isPlainObject(value)) {
|
|
283
|
-
|
|
337
|
+
errors.push({
|
|
338
|
+
path: label,
|
|
339
|
+
message: `Invalid value for "${label}". Expected an object, got ${describeReceived(value)}.`
|
|
340
|
+
});
|
|
341
|
+
return {};
|
|
284
342
|
}
|
|
285
343
|
const result = {};
|
|
286
344
|
const expectedKeys = new Map();
|
|
@@ -290,7 +348,10 @@ function validateObjectSchema(schema, value, casing, label) {
|
|
|
290
348
|
for (const key of Object.keys(value)) {
|
|
291
349
|
if (!expectedKeys.has(key)) {
|
|
292
350
|
const fieldLabel = label.length === 0 ? key : `${label}.${key}`;
|
|
293
|
-
|
|
351
|
+
errors.push({
|
|
352
|
+
path: fieldLabel,
|
|
353
|
+
message: `Unexpected parameter "${fieldLabel}". ${formatAvailableList([...expectedKeys.keys()].map((expectedKey) => label.length === 0 ? expectedKey : `${label}.${expectedKey}`))}`
|
|
354
|
+
});
|
|
294
355
|
}
|
|
295
356
|
}
|
|
296
357
|
for (const [inputKey, [outputKey, rawChildSchema]] of expectedKeys.entries()) {
|
|
@@ -305,14 +366,18 @@ function validateObjectSchema(schema, value, casing, label) {
|
|
|
305
366
|
if (isOptional(rawChildSchema)) {
|
|
306
367
|
continue;
|
|
307
368
|
}
|
|
308
|
-
|
|
369
|
+
errors.push({ path: fieldLabel, message: `Missing required parameter "${fieldLabel}".` });
|
|
370
|
+
continue;
|
|
309
371
|
}
|
|
310
|
-
result[outputKey] = validateSchemaValue(rawChildSchema, value[inputKey], casing, fieldLabel);
|
|
372
|
+
result[outputKey] = validateSchemaValue(rawChildSchema, value[inputKey], casing, fieldLabel, errors);
|
|
311
373
|
}
|
|
312
374
|
return result;
|
|
313
375
|
}
|
|
314
376
|
function validateToolArguments(schema, argumentsValue, casing) {
|
|
315
|
-
|
|
377
|
+
const errors = [];
|
|
378
|
+
const result = validateObjectSchema(schema, argumentsValue ?? {}, casing, "", errors);
|
|
379
|
+
throwValidationErrors(errors);
|
|
380
|
+
return result;
|
|
316
381
|
}
|
|
317
382
|
function isContentBlock(value) {
|
|
318
383
|
if (!isPlainObject(value) || typeof value.type !== "string") {
|
|
@@ -330,9 +395,7 @@ function toToolContent(result) {
|
|
|
330
395
|
if (Array.isArray(result)) {
|
|
331
396
|
return result.flatMap((item) => toToolContent(item));
|
|
332
397
|
}
|
|
333
|
-
if (typeof result === "string" ||
|
|
334
|
-
typeof result === "number" ||
|
|
335
|
-
typeof result === "boolean") {
|
|
398
|
+
if (typeof result === "string" || typeof result === "number" || typeof result === "boolean") {
|
|
336
399
|
return [{ type: "text", text: String(result) }];
|
|
337
400
|
}
|
|
338
401
|
if (result === null) {
|
|
@@ -362,7 +425,7 @@ function createResolvedMCPServer(root, options) {
|
|
|
362
425
|
const servicesWithBuiltIns = {
|
|
363
426
|
...services,
|
|
364
427
|
runtimeOptions,
|
|
365
|
-
root
|
|
428
|
+
root
|
|
366
429
|
};
|
|
367
430
|
validateServices(services);
|
|
368
431
|
const tools = enumerateTools(root, casing, options.tools, options.omitRootToolNamePrefix ?? false);
|
|
@@ -370,8 +433,10 @@ function createResolvedMCPServer(root, options) {
|
|
|
370
433
|
const server = createServer({ name: options.name, version });
|
|
371
434
|
for (const tool of tools) {
|
|
372
435
|
server.tool(tool.name, tool.description, tool.inputSchema, async (argumentsValue) => {
|
|
436
|
+
let params;
|
|
437
|
+
let secrets;
|
|
373
438
|
try {
|
|
374
|
-
|
|
439
|
+
secrets = resolveCommandSecrets(tool.command);
|
|
375
440
|
const baseContext = {
|
|
376
441
|
...servicesWithBuiltIns,
|
|
377
442
|
secrets,
|
|
@@ -380,13 +445,13 @@ function createResolvedMCPServer(root, options) {
|
|
|
380
445
|
env: createEnv(),
|
|
381
446
|
progress() {
|
|
382
447
|
return undefined;
|
|
383
|
-
}
|
|
448
|
+
}
|
|
384
449
|
};
|
|
385
450
|
await assertCommandRequirements(tool.command, { ...baseContext, params: undefined });
|
|
386
|
-
|
|
451
|
+
params = validateToolArguments(tool.command.params, argumentsValue, casing);
|
|
387
452
|
const result = await invokeWithHumanInLoop(tool.command, {
|
|
388
453
|
...baseContext,
|
|
389
|
-
params
|
|
454
|
+
params
|
|
390
455
|
}, runtimeOptions, tool.commandPath);
|
|
391
456
|
if (isHumanInLoopPending(result)) {
|
|
392
457
|
return renderPendingApproval(result);
|
|
@@ -397,6 +462,16 @@ function createResolvedMCPServer(root, options) {
|
|
|
397
462
|
if (error instanceof ApprovalDeclinedError) {
|
|
398
463
|
return renderDeclinedApproval(error);
|
|
399
464
|
}
|
|
465
|
+
await writeErrorReport({
|
|
466
|
+
command: tool.command,
|
|
467
|
+
commandPath: tool.commandPath,
|
|
468
|
+
env: process.env,
|
|
469
|
+
error,
|
|
470
|
+
errorReports: options.errorReports,
|
|
471
|
+
params,
|
|
472
|
+
projectRoot: options.projectRoot,
|
|
473
|
+
secrets
|
|
474
|
+
});
|
|
400
475
|
throw toToolError(error);
|
|
401
476
|
}
|
|
402
477
|
});
|
|
@@ -405,13 +480,13 @@ function createResolvedMCPServer(root, options) {
|
|
|
405
480
|
...server,
|
|
406
481
|
connect(transport) {
|
|
407
482
|
return server.connectSDK(transport);
|
|
408
|
-
}
|
|
483
|
+
}
|
|
409
484
|
};
|
|
410
485
|
}
|
|
411
486
|
function resolveMCPVersion(version) {
|
|
412
487
|
const resolvedVersion = version ?? findEntrypointPackageMetadata(process.argv[1])?.version;
|
|
413
488
|
if (resolvedVersion === undefined) {
|
|
414
|
-
throw new Error(
|
|
489
|
+
throw new Error('MCP server version is required. Pass version: "x.y.z" to createMCPServer / runMCP, or run toolcraft from a project whose package.json defines "version".');
|
|
415
490
|
}
|
|
416
491
|
return resolvedVersion;
|
|
417
492
|
}
|
|
@@ -430,14 +505,14 @@ function createDeferredMCPServer(root, options) {
|
|
|
430
505
|
},
|
|
431
506
|
connect(transport) {
|
|
432
507
|
return resolveServer().then((server) => server.connect(transport));
|
|
433
|
-
}
|
|
508
|
+
}
|
|
434
509
|
}, {
|
|
435
510
|
get(target, property, receiver) {
|
|
436
511
|
if (property === "then") {
|
|
437
512
|
return resolveServer().then.bind(resolveServer());
|
|
438
513
|
}
|
|
439
514
|
return Reflect.get(target, property, receiver);
|
|
440
|
-
}
|
|
515
|
+
}
|
|
441
516
|
});
|
|
442
517
|
}
|
|
443
518
|
export function createMCPServer(roots, options) {
|
|
@@ -448,6 +523,7 @@ export function createMCPServer(roots, options) {
|
|
|
448
523
|
return createDeferredMCPServer(root, options);
|
|
449
524
|
}
|
|
450
525
|
export async function runMCP(roots, options) {
|
|
526
|
+
enableSourceMaps();
|
|
451
527
|
const root = mergeApprovalsGroup(normalizeRoots(roots));
|
|
452
528
|
await resolveMcpProxies(root, { projectRoot: options.projectRoot });
|
|
453
529
|
const server = createResolvedMCPServer(root, options);
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ObjectSchema, Static } from "toolcraft-schema";
|
|
2
2
|
import type { Group, Scope } from "./index.js";
|
|
3
|
+
import { type ErrorReportsOption } from "./error-report.js";
|
|
3
4
|
import type { HumanInLoopPending, HumanInLoopRuntimeOptions } from "./human-in-loop/index.js";
|
|
4
5
|
type ScopeInput = readonly Scope[] | undefined;
|
|
5
6
|
type HumanInLoopMode = "sync" | "async";
|
|
@@ -12,8 +13,8 @@ type IncludesSDK<TScope> = TScope extends readonly Scope[] ? "sdk" extends TScop
|
|
|
12
13
|
type EffectiveCommandHumanInLoopMode<TOwnHumanInLoopMode extends HumanInLoopModeInput, TInheritedHumanInLoopMode extends HumanInLoopMode | undefined> = TOwnHumanInLoopMode extends HumanInLoopMode ? TOwnHumanInLoopMode : TOwnHumanInLoopMode extends null ? undefined : TInheritedHumanInLoopMode;
|
|
13
14
|
type EffectiveGroupHumanInLoopMode<TOwnHumanInLoopMode extends HumanInLoopModeInput, TInheritedHumanInLoopMode extends HumanInLoopMode | undefined> = TOwnHumanInLoopMode extends HumanInLoopMode ? TOwnHumanInLoopMode : TOwnHumanInLoopMode extends null ? undefined : TInheritedHumanInLoopMode;
|
|
14
15
|
type Separator = "-" | "_" | " " | ".";
|
|
15
|
-
type IsUppercase<TValue extends string> = TValue extends Uppercase<TValue> ? TValue extends Lowercase<TValue> ? false : true : false;
|
|
16
|
-
type IsLowercase<TValue extends string> = TValue extends Lowercase<TValue> ? TValue extends Uppercase<TValue> ? false : true : false;
|
|
16
|
+
type IsUppercase<TValue extends string> = TValue extends Uppercase<TValue> ? (TValue extends Lowercase<TValue> ? false : true) : false;
|
|
17
|
+
type IsLowercase<TValue extends string> = TValue extends Lowercase<TValue> ? (TValue extends Uppercase<TValue> ? false : true) : false;
|
|
17
18
|
type LastCharacter<TValue extends string> = TValue extends `${infer THead}${infer TTail}` ? TTail extends "" ? THead : LastCharacter<TTail> : never;
|
|
18
19
|
type PushCurrentWord<TCurrent extends string, TWords extends readonly string[]> = TCurrent extends "" ? TWords : [...TWords, Lowercase<TCurrent>];
|
|
19
20
|
type SplitCamelWords<TValue extends string, TCurrent extends string = "", TWords extends readonly string[] = []> = TValue extends `${infer TChar}${infer TRest}` ? TChar extends Separator ? SplitCamelWords<TRest, "", PushCurrentWord<TCurrent, TWords>> : IsUppercase<TChar> extends true ? TCurrent extends "" ? SplitCamelWords<TRest, TChar, TWords> : TRest extends `${infer TNext}${string}` ? IsLowercase<LastCharacter<TCurrent>> extends true ? SplitCamelWords<TRest, TChar, PushCurrentWord<TCurrent, TWords>> : IsLowercase<TNext> extends true ? SplitCamelWords<TRest, TChar, PushCurrentWord<TCurrent, TWords>> : SplitCamelWords<TRest, `${TCurrent}${TChar}`, TWords> : SplitCamelWords<TRest, `${TCurrent}${TChar}`, TWords> : SplitCamelWords<TRest, `${TCurrent}${TChar}`, TWords> : PushCurrentWord<TCurrent, TWords>;
|
|
@@ -64,6 +65,7 @@ export interface CreateSDKOptions<TServices extends object = Record<string, unkn
|
|
|
64
65
|
casing?: "camel";
|
|
65
66
|
humanInLoop?: HumanInLoopRuntimeOptions;
|
|
66
67
|
projectRoot?: string;
|
|
68
|
+
errorReports?: ErrorReportsOption;
|
|
67
69
|
}
|
|
68
70
|
export declare function createSDK<TRootInfo, TServices extends object = Record<string, unknown>>(root: Group<any> & {
|
|
69
71
|
readonly __agentKitGroupTypeInfo: TRootInfo;
|