@easynet/agent-tool 1.0.59 → 1.0.61
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/api/expose/index.d.ts +1 -1
- package/dist/api/expose/index.d.ts.map +1 -1
- package/dist/api/expose/mcp-build/build.d.ts +1 -3
- package/dist/api/expose/mcp-build/build.d.ts.map +1 -1
- package/dist/api/expose/mcp-build/index.d.ts +2 -2
- package/dist/api/expose/mcp-build/index.d.ts.map +1 -1
- package/dist/api/expose/mcp-build/run.d.ts +1 -3
- package/dist/api/expose/mcp-build/run.d.ts.map +1 -1
- package/dist/api/main.cjs +19 -15
- package/dist/api/main.js +8 -4
- package/dist/build.cjs +31 -0
- package/dist/build.cjs.map +1 -0
- package/dist/build.d.ts +13 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +6 -0
- package/dist/build.js.map +1 -0
- package/dist/chunk-45S2HPVU.js +463 -0
- package/dist/chunk-45S2HPVU.js.map +1 -0
- package/dist/{chunk-Y75CRPVF.js → chunk-5J27MF7S.js} +11 -12
- package/dist/chunk-5J27MF7S.js.map +1 -0
- package/dist/{chunk-JXYANBTH.cjs → chunk-HK4GTFTQ.cjs} +57 -1645
- package/dist/chunk-HK4GTFTQ.cjs.map +1 -0
- package/dist/chunk-JNIWNSCQ.cjs +494 -0
- package/dist/chunk-JNIWNSCQ.cjs.map +1 -0
- package/dist/{chunk-DPOLJN7F.cjs → chunk-NMZ4IMEW.cjs} +22 -25
- package/dist/chunk-NMZ4IMEW.cjs.map +1 -0
- package/dist/{chunk-A5C2MUNA.js → chunk-NVT4X4CB.js} +41 -1600
- package/dist/chunk-NVT4X4CB.js.map +1 -0
- package/dist/chunk-OG5ZSXQ5.cjs +1099 -0
- package/dist/chunk-OG5ZSXQ5.cjs.map +1 -0
- package/dist/{chunk-WQMHMPNC.cjs → chunk-PYCCJF7C.cjs} +2 -68
- package/dist/chunk-PYCCJF7C.cjs.map +1 -0
- package/dist/{chunk-IWM5B5DU.js → chunk-QPKBEU64.js} +4 -3
- package/dist/chunk-QPKBEU64.js.map +1 -0
- package/dist/chunk-QXQ4477T.js +49 -0
- package/dist/chunk-QXQ4477T.js.map +1 -0
- package/dist/chunk-RZTTO5MQ.js +65 -0
- package/dist/chunk-RZTTO5MQ.js.map +1 -0
- package/dist/{chunk-FCYBA7PR.js → chunk-WUMLZERG.js} +3 -62
- package/dist/chunk-WUMLZERG.js.map +1 -0
- package/dist/chunk-XPGHS4W7.cjs +73 -0
- package/dist/chunk-XPGHS4W7.cjs.map +1 -0
- package/dist/chunk-YRFUGA3C.js +1072 -0
- package/dist/chunk-YRFUGA3C.js.map +1 -0
- package/dist/chunk-ZDSZHEQU.cjs +52 -0
- package/dist/chunk-ZDSZHEQU.cjs.map +1 -0
- package/dist/{chunk-MUBZV65R.cjs → chunk-ZH5MH3AK.cjs} +16 -15
- package/dist/chunk-ZH5MH3AK.cjs.map +1 -0
- package/dist/core/runtime.cjs +6 -5
- package/dist/core/runtime.js +2 -1
- package/dist/extension.cjs +359 -0
- package/dist/extension.cjs.map +1 -0
- package/dist/extension.d.ts +6 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +341 -0
- package/dist/extension.js.map +1 -0
- package/dist/index.cjs +17 -609
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -520
- package/dist/index.js.map +1 -1
- package/dist/security.cjs +193 -0
- package/dist/security.cjs.map +1 -0
- package/dist/security.d.ts +6 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +182 -0
- package/dist/security.js.map +1 -0
- package/dist/utils/cli/index.cjs +25 -21
- package/dist/utils/cli/index.cjs.map +1 -1
- package/dist/utils/cli/index.js +13 -9
- package/dist/utils/cli/index.js.map +1 -1
- package/package.json +16 -2
- package/dist/chunk-A5C2MUNA.js.map +0 -1
- package/dist/chunk-DPOLJN7F.cjs.map +0 -1
- package/dist/chunk-FCYBA7PR.js.map +0 -1
- package/dist/chunk-IWM5B5DU.js.map +0 -1
- package/dist/chunk-JXYANBTH.cjs.map +0 -1
- package/dist/chunk-MUBZV65R.cjs.map +0 -1
- package/dist/chunk-WQMHMPNC.cjs.map +0 -1
- package/dist/chunk-Y75CRPVF.js.map +0 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var chunkWQMHMPNC_cjs = require('./chunk-WQMHMPNC.cjs');
|
|
4
|
-
var chunkQEJF3KDV_cjs = require('./chunk-QEJF3KDV.cjs');
|
|
5
3
|
var chunkUUNG3GL3_cjs = require('./chunk-UUNG3GL3.cjs');
|
|
4
|
+
var chunkOG5ZSXQ5_cjs = require('./chunk-OG5ZSXQ5.cjs');
|
|
5
|
+
var chunkZDSZHEQU_cjs = require('./chunk-ZDSZHEQU.cjs');
|
|
6
|
+
var chunkPYCCJF7C_cjs = require('./chunk-PYCCJF7C.cjs');
|
|
7
|
+
var chunkXPGHS4W7_cjs = require('./chunk-XPGHS4W7.cjs');
|
|
8
|
+
var chunkQEJF3KDV_cjs = require('./chunk-QEJF3KDV.cjs');
|
|
6
9
|
var fs = require('fs');
|
|
7
10
|
var path = require('path');
|
|
8
11
|
var agentCommon = require('@easynet/agent-common');
|
|
@@ -12,42 +15,17 @@ var cockatiel = require('cockatiel');
|
|
|
12
15
|
var eventemitter3 = require('eventemitter3');
|
|
13
16
|
var uuid = require('uuid');
|
|
14
17
|
var pTimeout = require('p-timeout');
|
|
15
|
-
var promises = require('fs/promises');
|
|
16
|
-
var ts2 = require('typescript');
|
|
17
18
|
var module$1 = require('module');
|
|
18
19
|
var url = require('url');
|
|
19
|
-
var yaml = require('js-yaml');
|
|
20
20
|
var npm = require('@easynet/agent-common/npm');
|
|
21
21
|
var http = require('http');
|
|
22
22
|
|
|
23
23
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
24
24
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
25
25
|
|
|
26
|
-
function _interopNamespace(e) {
|
|
27
|
-
if (e && e.__esModule) return e;
|
|
28
|
-
var n = Object.create(null);
|
|
29
|
-
if (e) {
|
|
30
|
-
Object.keys(e).forEach(function (k) {
|
|
31
|
-
if (k !== 'default') {
|
|
32
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
33
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
34
|
-
enumerable: true,
|
|
35
|
-
get: function () { return e[k]; }
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
n.default = e;
|
|
41
|
-
return Object.freeze(n);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
45
|
-
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
46
26
|
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
47
27
|
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
|
|
48
28
|
var pTimeout__default = /*#__PURE__*/_interopDefault(pTimeout);
|
|
49
|
-
var ts2__namespace = /*#__PURE__*/_interopNamespace(ts2);
|
|
50
|
-
var yaml__default = /*#__PURE__*/_interopDefault(yaml);
|
|
51
29
|
|
|
52
30
|
function loadToolConfig(toolYamlPath) {
|
|
53
31
|
const abs = path.resolve(toolYamlPath);
|
|
@@ -226,13 +204,13 @@ function expandToolDescriptorsToRegistryNames(descriptors, registryNames) {
|
|
|
226
204
|
out.push(s);
|
|
227
205
|
continue;
|
|
228
206
|
}
|
|
229
|
-
const
|
|
230
|
-
if (
|
|
231
|
-
const packagePrefix =
|
|
207
|
+
const path = parseToolPath(s);
|
|
208
|
+
if (path) {
|
|
209
|
+
const packagePrefix = path.protocol === "npm" ? npmDescriptorToPackagePrefix(s) : path.protocol === "file" ? fileDescriptorToPackagePrefix(s) : "";
|
|
232
210
|
const prefixWithDot = packagePrefix ? packagePrefix + "." : "";
|
|
233
211
|
if (prefixWithDot) {
|
|
234
|
-
if (
|
|
235
|
-
const suffix = "." +
|
|
212
|
+
if (path.toolName) {
|
|
213
|
+
const suffix = "." + path.toolName;
|
|
236
214
|
for (const r of registryNames) {
|
|
237
215
|
if (r.startsWith(prefixWithDot) && r.endsWith(suffix) && !seen.has(r)) {
|
|
238
216
|
seen.add(r);
|
|
@@ -261,9 +239,9 @@ function resolveToolDescriptor(descriptor) {
|
|
|
261
239
|
return s;
|
|
262
240
|
}
|
|
263
241
|
function fileDescriptorToPackagePrefix(descriptor) {
|
|
264
|
-
const
|
|
265
|
-
if (!
|
|
266
|
-
const pathPart = `${
|
|
242
|
+
const path = parseToolPath(descriptor.trim());
|
|
243
|
+
if (!path || path.protocol !== "file") return "";
|
|
244
|
+
const pathPart = `${path.scope}/${path.packageWithVersion}`;
|
|
267
245
|
const normalized = chunkQEJF3KDV_cjs.normalizeToolName(pathPart);
|
|
268
246
|
if (!normalized) return "";
|
|
269
247
|
return chunkQEJF3KDV_cjs.normalizeToolName("file." + normalized);
|
|
@@ -563,17 +541,17 @@ var PolicyEngine = class {
|
|
|
563
541
|
*/
|
|
564
542
|
extractStringValues(args, keyPatterns) {
|
|
565
543
|
const results = [];
|
|
566
|
-
const
|
|
544
|
+
const walk = (obj) => {
|
|
567
545
|
for (const [key, val] of Object.entries(obj)) {
|
|
568
546
|
const lowerKey = key.toLowerCase();
|
|
569
547
|
if (typeof val === "string" && keyPatterns.some((p) => lowerKey.includes(p))) {
|
|
570
548
|
results.push(val);
|
|
571
549
|
} else if (val && typeof val === "object" && !Array.isArray(val)) {
|
|
572
|
-
|
|
550
|
+
walk(val);
|
|
573
551
|
}
|
|
574
552
|
}
|
|
575
553
|
};
|
|
576
|
-
|
|
554
|
+
walk(args);
|
|
577
555
|
return results;
|
|
578
556
|
}
|
|
579
557
|
};
|
|
@@ -758,30 +736,30 @@ function summarizeValue(value, maxLen) {
|
|
|
758
736
|
}
|
|
759
737
|
function extractUrls(obj) {
|
|
760
738
|
const urls = [];
|
|
761
|
-
const
|
|
739
|
+
const walk = (val) => {
|
|
762
740
|
if (typeof val === "string" && /^https?:\/\//i.test(val)) {
|
|
763
741
|
urls.push(val);
|
|
764
742
|
} else if (val && typeof val === "object") {
|
|
765
743
|
for (const v of Object.values(val)) {
|
|
766
|
-
|
|
744
|
+
walk(v);
|
|
767
745
|
}
|
|
768
746
|
}
|
|
769
747
|
};
|
|
770
|
-
|
|
748
|
+
walk(obj);
|
|
771
749
|
return urls.slice(0, 10);
|
|
772
750
|
}
|
|
773
751
|
function extractFilePaths(obj) {
|
|
774
752
|
const paths = [];
|
|
775
|
-
const
|
|
753
|
+
const walk = (val) => {
|
|
776
754
|
if (typeof val === "string" && (val.startsWith("/") || val.startsWith("./")) && val.includes(".")) {
|
|
777
755
|
paths.push(val);
|
|
778
756
|
} else if (val && typeof val === "object") {
|
|
779
757
|
for (const v of Object.values(val)) {
|
|
780
|
-
|
|
758
|
+
walk(v);
|
|
781
759
|
}
|
|
782
760
|
}
|
|
783
761
|
};
|
|
784
|
-
|
|
762
|
+
walk(obj);
|
|
785
763
|
return paths.slice(0, 10);
|
|
786
764
|
}
|
|
787
765
|
var EventLog = class {
|
|
@@ -1191,7 +1169,7 @@ function resolveTool(toolName, registry) {
|
|
|
1191
1169
|
const key = chunkQEJF3KDV_cjs.normalizeToolName(toolName);
|
|
1192
1170
|
const spec = registry.get(key);
|
|
1193
1171
|
if (!spec) {
|
|
1194
|
-
throw
|
|
1172
|
+
throw chunkXPGHS4W7_cjs.createTaggedError(
|
|
1195
1173
|
"TOOL_NOT_FOUND",
|
|
1196
1174
|
`Tool not found: ${toolName}`,
|
|
1197
1175
|
{ availableTools: registry.snapshot().slice(0, 20).map((s) => s.name) }
|
|
@@ -1230,7 +1208,7 @@ function validateInput(spec, args, validator) {
|
|
|
1230
1208
|
if (error instanceof SchemaValidationError) {
|
|
1231
1209
|
const requiredKeys = getRequiredKeys(spec.inputSchema);
|
|
1232
1210
|
const passedKeys = args != null && typeof args === "object" && !Array.isArray(args) ? Object.keys(args) : [];
|
|
1233
|
-
throw
|
|
1211
|
+
throw chunkXPGHS4W7_cjs.createTaggedError("INPUT_SCHEMA_INVALID", error.message, {
|
|
1234
1212
|
errors: error.errors,
|
|
1235
1213
|
schema: spec.inputSchema,
|
|
1236
1214
|
requiredKeys: requiredKeys.length ? requiredKeys : void 0,
|
|
@@ -1303,7 +1281,7 @@ async function requireHumanApproval(spec, args, ctx, deps) {
|
|
|
1303
1281
|
sideEffect,
|
|
1304
1282
|
reason: err instanceof Error ? err.message : String(err)
|
|
1305
1283
|
});
|
|
1306
|
-
throw
|
|
1284
|
+
throw chunkXPGHS4W7_cjs.createTaggedError(
|
|
1307
1285
|
"HITL_DENIED",
|
|
1308
1286
|
`Human denied approval for ${spec.name} (${sideEffect})`,
|
|
1309
1287
|
{ reason: err instanceof Error ? err.message : String(err) }
|
|
@@ -1316,7 +1294,7 @@ async function requireHumanApproval(spec, args, ctx, deps) {
|
|
|
1316
1294
|
sideEffect,
|
|
1317
1295
|
reason: "User rejected"
|
|
1318
1296
|
});
|
|
1319
|
-
throw
|
|
1297
|
+
throw chunkXPGHS4W7_cjs.createTaggedError("HITL_DENIED", `Human denied approval for ${spec.name} (${sideEffect})`);
|
|
1320
1298
|
}
|
|
1321
1299
|
deps.eventLog.append({
|
|
1322
1300
|
...baseEvent,
|
|
@@ -1328,7 +1306,7 @@ async function requireHumanApproval(spec, args, ctx, deps) {
|
|
|
1328
1306
|
async function executeWithBudget(spec, args, ctx, spanId, deps) {
|
|
1329
1307
|
const adapter = deps.adaptersByToolName.get(spec.name) ?? deps.adapters.get(spec.kind);
|
|
1330
1308
|
if (!adapter) {
|
|
1331
|
-
throw
|
|
1309
|
+
throw chunkXPGHS4W7_cjs.createTaggedError(
|
|
1332
1310
|
"TOOL_NOT_FOUND",
|
|
1333
1311
|
`No adapter registered for kind: ${spec.kind}`
|
|
1334
1312
|
);
|
|
@@ -1356,7 +1334,7 @@ async function executeWithBudget(spec, args, ctx, spanId, deps) {
|
|
|
1356
1334
|
return result;
|
|
1357
1335
|
});
|
|
1358
1336
|
};
|
|
1359
|
-
const retryFn = () =>
|
|
1337
|
+
const retryFn = () => chunkXPGHS4W7_cjs.withRetry(executeFn, {
|
|
1360
1338
|
maxRetries,
|
|
1361
1339
|
onRetry: (error, attempt) => {
|
|
1362
1340
|
deps.metrics.recordRetry(spec.name);
|
|
@@ -1383,7 +1361,7 @@ async function executeWithBudget(spec, args, ctx, spanId, deps) {
|
|
|
1383
1361
|
});
|
|
1384
1362
|
} catch (error) {
|
|
1385
1363
|
if (error instanceof Error && error.message.includes("timed out")) {
|
|
1386
|
-
throw
|
|
1364
|
+
throw chunkXPGHS4W7_cjs.createTaggedError("TIMEOUT", error.message);
|
|
1387
1365
|
}
|
|
1388
1366
|
throw error;
|
|
1389
1367
|
}
|
|
@@ -1397,7 +1375,7 @@ function validateOutput(spec, result, validator) {
|
|
|
1397
1375
|
);
|
|
1398
1376
|
} catch (error) {
|
|
1399
1377
|
if (error instanceof SchemaValidationError) {
|
|
1400
|
-
throw
|
|
1378
|
+
throw chunkXPGHS4W7_cjs.createTaggedError("OUTPUT_SCHEMA_INVALID", error.message, {
|
|
1401
1379
|
errors: error.errors
|
|
1402
1380
|
});
|
|
1403
1381
|
}
|
|
@@ -1491,7 +1469,7 @@ var PTCRuntime = class {
|
|
|
1491
1469
|
logger;
|
|
1492
1470
|
constructor(options = {}) {
|
|
1493
1471
|
this.config = options.config ?? {};
|
|
1494
|
-
this.registry = options.registry ?? new
|
|
1472
|
+
this.registry = options.registry ?? new chunkPYCCJF7C_cjs.ToolRegistry();
|
|
1495
1473
|
this.validator = options.validator ?? new SchemaValidator();
|
|
1496
1474
|
this.policy = options.policy ?? new PolicyEngine(this.config.policy);
|
|
1497
1475
|
this.budget = options.budget ?? new BudgetManager(this.config.budget);
|
|
@@ -1601,7 +1579,7 @@ var PTCRuntime = class {
|
|
|
1601
1579
|
tracing: this.tracing
|
|
1602
1580
|
});
|
|
1603
1581
|
if (!this.budget.checkRateLimit(spec.name)) {
|
|
1604
|
-
throw
|
|
1582
|
+
throw chunkXPGHS4W7_cjs.createTaggedError(
|
|
1605
1583
|
"BUDGET_EXCEEDED",
|
|
1606
1584
|
`Rate limit exceeded for tool: ${spec.name}`
|
|
1607
1585
|
);
|
|
@@ -1624,7 +1602,7 @@ var PTCRuntime = class {
|
|
|
1624
1602
|
const toolError = asToolReturnedError(result);
|
|
1625
1603
|
if (toolError) {
|
|
1626
1604
|
const hint = buildInputSchemaHint(spec.inputSchema);
|
|
1627
|
-
throw
|
|
1605
|
+
throw chunkXPGHS4W7_cjs.createTaggedError("UPSTREAM_ERROR", toolError.message, {
|
|
1628
1606
|
...toolError.details && typeof toolError.details === "object" && !Array.isArray(toolError.details) ? toolError.details : {},
|
|
1629
1607
|
hint: hint ?? "Check the tool's input schema for required property names."
|
|
1630
1608
|
});
|
|
@@ -1748,1566 +1726,9 @@ function buildInputSchemaHint(inputSchema) {
|
|
|
1748
1726
|
if (names.length === 0) return null;
|
|
1749
1727
|
return `This tool expects input property ${names.length === 1 ? `'${names[0]}'` : `one of [${names.map((n) => `'${n}'`).join(", ")}]`}. Use the exact property names from the tool schema.`;
|
|
1750
1728
|
}
|
|
1751
|
-
var sandboxValidationEnabled = false;
|
|
1752
|
-
function setSandboxValidationEnabled(enabled) {
|
|
1753
|
-
sandboxValidationEnabled = enabled;
|
|
1754
|
-
}
|
|
1755
|
-
async function resolveSandboxedPath2(inputPath, sandboxRoot) {
|
|
1756
|
-
let normalizedRoot;
|
|
1757
|
-
try {
|
|
1758
|
-
normalizedRoot = await promises.realpath(path.resolve(sandboxRoot));
|
|
1759
|
-
} catch {
|
|
1760
|
-
normalizedRoot = path.normalize(path.resolve(sandboxRoot));
|
|
1761
|
-
}
|
|
1762
|
-
const resolved = path.resolve(normalizedRoot, inputPath);
|
|
1763
|
-
let real;
|
|
1764
|
-
try {
|
|
1765
|
-
await promises.access(resolved);
|
|
1766
|
-
real = await promises.realpath(resolved);
|
|
1767
|
-
} catch {
|
|
1768
|
-
const parentDir = path.dirname(resolved);
|
|
1769
|
-
let realParent;
|
|
1770
|
-
try {
|
|
1771
|
-
await promises.access(parentDir);
|
|
1772
|
-
realParent = await promises.realpath(parentDir);
|
|
1773
|
-
} catch {
|
|
1774
|
-
realParent = path.normalize(parentDir);
|
|
1775
|
-
}
|
|
1776
|
-
real = path.resolve(realParent, path.basename(resolved));
|
|
1777
|
-
}
|
|
1778
|
-
if (sandboxValidationEnabled && !isWithinRoot(real, normalizedRoot)) {
|
|
1779
|
-
throw chunkWQMHMPNC_cjs.createTaggedError(
|
|
1780
|
-
"PATH_OUTSIDE_SANDBOX",
|
|
1781
|
-
`Path "${inputPath}" resolves to "${real}" which is outside sandbox "${normalizedRoot}"`,
|
|
1782
|
-
{ inputPath, resolvedPath: real, sandboxRoot: normalizedRoot }
|
|
1783
|
-
);
|
|
1784
|
-
}
|
|
1785
|
-
return real;
|
|
1786
|
-
}
|
|
1787
|
-
function isWithinRoot(path7, root) {
|
|
1788
|
-
const normalizedPath = path.normalize(path7);
|
|
1789
|
-
const normalizedRoot = path.normalize(root);
|
|
1790
|
-
return normalizedPath === normalizedRoot || normalizedPath.startsWith(normalizedRoot + "/");
|
|
1791
|
-
}
|
|
1792
|
-
async function findDirsContainingFile(rootPath, fileName) {
|
|
1793
|
-
const found = [];
|
|
1794
|
-
await collectDirsWithFile(rootPath, fileName, found);
|
|
1795
|
-
return found;
|
|
1796
|
-
}
|
|
1797
|
-
async function collectDirsWithFile(dir, fileName, acc) {
|
|
1798
|
-
let entries;
|
|
1799
|
-
try {
|
|
1800
|
-
const e = await promises.readdir(dir, { withFileTypes: true });
|
|
1801
|
-
entries = e.map((x) => ({
|
|
1802
|
-
name: x.name,
|
|
1803
|
-
isDirectory: x.isDirectory(),
|
|
1804
|
-
isFile: x.isFile()
|
|
1805
|
-
}));
|
|
1806
|
-
} catch {
|
|
1807
|
-
return;
|
|
1808
|
-
}
|
|
1809
|
-
if (entries.some((x) => x.isFile && x.name === fileName)) acc.push(dir);
|
|
1810
|
-
for (const entry of entries) {
|
|
1811
|
-
if (!entry.isDirectory || entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
1812
|
-
await collectDirsWithFile(path.join(dir, entry.name), fileName, acc);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
function pathToToolName(sourcePath, programName) {
|
|
1816
|
-
const normalized = sourcePath.replace(/\\/g, "/").replace(/\.(ts|tsx|js|mjs|json)$/i, "");
|
|
1817
|
-
const segments = normalized.split("/").filter(Boolean);
|
|
1818
|
-
return segments.length === 0 ? programName : `${segments.join(".")}.${programName}`;
|
|
1819
|
-
}
|
|
1820
|
-
function buildOutputSchemaFromReturnType(node, typeChecker, onWarn) {
|
|
1821
|
-
const sig = typeChecker.getSignatureFromDeclaration(node);
|
|
1822
|
-
if (!sig) {
|
|
1823
|
-
onWarn?.("Could not get signature for return type, using object");
|
|
1824
|
-
return { type: "object", additionalProperties: true };
|
|
1825
|
-
}
|
|
1826
|
-
let returnType = typeChecker.getReturnTypeOfSignature(sig);
|
|
1827
|
-
if (returnType.getSymbol?.()?.getName() === "Promise") {
|
|
1828
|
-
const typeArgs = returnType.typeArguments;
|
|
1829
|
-
if (typeArgs?.[0]) returnType = typeArgs[0];
|
|
1830
|
-
}
|
|
1831
|
-
const schema = typeToJsonSchema(returnType, typeChecker, onWarn);
|
|
1832
|
-
const hasProps = typeof schema === "object" && schema.type === "object" && Object.keys(schema.properties ?? {}).length > 0;
|
|
1833
|
-
return hasProps ? schema : { type: "object", additionalProperties: true };
|
|
1834
|
-
}
|
|
1835
|
-
function buildInputSchemaFromParams(node, typeChecker, onWarn) {
|
|
1836
|
-
const properties = {};
|
|
1837
|
-
const required = [];
|
|
1838
|
-
if (!node.parameters.length) {
|
|
1839
|
-
return { schema: { type: "object", properties: {} }, required: [] };
|
|
1840
|
-
}
|
|
1841
|
-
for (const param of node.parameters) {
|
|
1842
|
-
const name = param.name.getText();
|
|
1843
|
-
if (name.startsWith("_") && name.length <= 2) continue;
|
|
1844
|
-
const sym = param.symbol;
|
|
1845
|
-
const paramType = sym ? typeChecker.getTypeOfSymbolAtLocation(sym, param) : typeChecker.getTypeAtLocation(param);
|
|
1846
|
-
const isOptional = !!param.questionToken || param.initializer !== void 0;
|
|
1847
|
-
const propSchema = typeToJsonSchema(paramType, typeChecker, onWarn);
|
|
1848
|
-
properties[name] = propSchema;
|
|
1849
|
-
if (!isOptional) required.push(name);
|
|
1850
|
-
}
|
|
1851
|
-
const paramNames = Object.keys(properties);
|
|
1852
|
-
if (paramNames.length === 1) {
|
|
1853
|
-
const soleName = paramNames[0];
|
|
1854
|
-
const inner = properties[soleName];
|
|
1855
|
-
if (inner && typeof inner === "object" && inner.type === "object" && inner.properties && typeof inner.properties === "object") {
|
|
1856
|
-
return {
|
|
1857
|
-
schema: {
|
|
1858
|
-
type: "object",
|
|
1859
|
-
properties: inner.properties,
|
|
1860
|
-
...Array.isArray(inner.required) && inner.required.length > 0 ? { required: inner.required } : {},
|
|
1861
|
-
...inner.additionalProperties !== void 0 ? { additionalProperties: inner.additionalProperties } : {}
|
|
1862
|
-
},
|
|
1863
|
-
required: inner.required ?? []
|
|
1864
|
-
};
|
|
1865
|
-
}
|
|
1866
|
-
}
|
|
1867
|
-
return {
|
|
1868
|
-
schema: {
|
|
1869
|
-
type: "object",
|
|
1870
|
-
properties,
|
|
1871
|
-
...required.length > 0 ? { required } : {}
|
|
1872
|
-
},
|
|
1873
|
-
required
|
|
1874
|
-
};
|
|
1875
|
-
}
|
|
1876
|
-
function typeToJsonSchema(type, typeChecker, onWarn) {
|
|
1877
|
-
const flags = type.flags;
|
|
1878
|
-
if (flags & ts2__namespace.TypeFlags.String) return { type: "string" };
|
|
1879
|
-
if (flags & ts2__namespace.TypeFlags.Number) return { type: "number" };
|
|
1880
|
-
if (flags & ts2__namespace.TypeFlags.Boolean) return { type: "boolean" };
|
|
1881
|
-
if (flags & ts2__namespace.TypeFlags.BooleanLiteral) return { type: "boolean" };
|
|
1882
|
-
if (flags & ts2__namespace.TypeFlags.Null) return { type: "null" };
|
|
1883
|
-
if (flags & ts2__namespace.TypeFlags.Undefined || flags & ts2__namespace.TypeFlags.Void) return {};
|
|
1884
|
-
if (flags & ts2__namespace.TypeFlags.Any || flags & ts2__namespace.TypeFlags.Unknown) {
|
|
1885
|
-
onWarn?.(`Unsupported type: any/unknown, using empty schema`);
|
|
1886
|
-
return {};
|
|
1887
|
-
}
|
|
1888
|
-
if (type.isUnion?.()) {
|
|
1889
|
-
const union = type;
|
|
1890
|
-
const types = union.types;
|
|
1891
|
-
const withoutUndef = types.filter(
|
|
1892
|
-
(t) => !(t.flags & ts2__namespace.TypeFlags.Undefined) && !(t.flags & ts2__namespace.TypeFlags.Void)
|
|
1893
|
-
);
|
|
1894
|
-
if (withoutUndef.length === 1) return typeToJsonSchema(withoutUndef[0], typeChecker, onWarn);
|
|
1895
|
-
if (withoutUndef.length === 0) return {};
|
|
1896
|
-
const stringEnumValues = [];
|
|
1897
|
-
let allStringLiterals = true;
|
|
1898
|
-
for (const t of withoutUndef) {
|
|
1899
|
-
if (t.flags & ts2__namespace.TypeFlags.StringLiteral) {
|
|
1900
|
-
const lit = t;
|
|
1901
|
-
if (typeof lit.value === "string") stringEnumValues.push(lit.value);
|
|
1902
|
-
} else {
|
|
1903
|
-
allStringLiterals = false;
|
|
1904
|
-
break;
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
if (allStringLiterals && stringEnumValues.length > 0) {
|
|
1908
|
-
return { type: "string", enum: [...new Set(stringEnumValues)] };
|
|
1909
|
-
}
|
|
1910
|
-
let allBooleanLiterals = true;
|
|
1911
|
-
for (const t of withoutUndef) {
|
|
1912
|
-
if (!(t.flags & ts2__namespace.TypeFlags.BooleanLiteral)) {
|
|
1913
|
-
allBooleanLiterals = false;
|
|
1914
|
-
break;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
if (allBooleanLiterals) return { type: "boolean" };
|
|
1918
|
-
}
|
|
1919
|
-
if (flags & ts2__namespace.TypeFlags.StringLiteral) {
|
|
1920
|
-
const lit = type;
|
|
1921
|
-
if (typeof lit.value === "string") {
|
|
1922
|
-
return { type: "string", enum: [lit.value] };
|
|
1923
|
-
}
|
|
1924
|
-
return { type: "string" };
|
|
1925
|
-
}
|
|
1926
|
-
if (typeChecker.isArrayType(type)) {
|
|
1927
|
-
const typeRef = type;
|
|
1928
|
-
const typeArgs = typeRef.typeArguments;
|
|
1929
|
-
const itemType = typeArgs?.[0];
|
|
1930
|
-
const items = itemType ? typeToJsonSchema(itemType, typeChecker, onWarn) : {};
|
|
1931
|
-
return { type: "array", items: Object.keys(items).length ? items : {} };
|
|
1932
|
-
}
|
|
1933
|
-
const str = typeChecker.typeToString(type);
|
|
1934
|
-
if (str === "string") return { type: "string" };
|
|
1935
|
-
if (str === "number") return { type: "number" };
|
|
1936
|
-
if (str === "boolean") return { type: "boolean" };
|
|
1937
|
-
if (str.endsWith("[]")) {
|
|
1938
|
-
const inner = str.slice(0, -2).trim();
|
|
1939
|
-
const itemType = inner === "string" ? { type: "string" } : inner === "number" ? { type: "number" } : {};
|
|
1940
|
-
return { type: "array", items: itemType };
|
|
1941
|
-
}
|
|
1942
|
-
if (type.getProperties && type.getProperties().length >= 0) {
|
|
1943
|
-
const props = type.getProperties();
|
|
1944
|
-
const properties = {};
|
|
1945
|
-
const required = [];
|
|
1946
|
-
for (const p of props) {
|
|
1947
|
-
const decl = p.valueDeclaration;
|
|
1948
|
-
const propType = decl ? typeChecker.getTypeAtLocation(decl) : typeChecker.getTypeOfSymbolAtLocation(p, p.valueDeclaration);
|
|
1949
|
-
const optional = decl && ts2__namespace.isPropertySignature(decl) ? !!decl.questionToken : false;
|
|
1950
|
-
properties[p.name] = typeToJsonSchema(propType, typeChecker, onWarn);
|
|
1951
|
-
if (!optional) required.push(p.name);
|
|
1952
|
-
}
|
|
1953
|
-
return { type: "object", properties, ...required.length ? { required } : {} };
|
|
1954
|
-
}
|
|
1955
|
-
onWarn?.(`Unsupported type: ${str}, using object`);
|
|
1956
|
-
return { type: "object" };
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
// src/tools/function/types.ts
|
|
1960
|
-
var FUNCTION_KIND = "function";
|
|
1961
|
-
|
|
1962
|
-
// src/tools/skill/types.ts
|
|
1963
|
-
var SKILL_KIND = "skill";
|
|
1964
|
-
var SKILL_DIR_NAME = "skill";
|
|
1965
|
-
|
|
1966
|
-
// src/tools/n8n/types.ts
|
|
1967
|
-
var N8N_KIND = "n8n";
|
|
1968
|
-
|
|
1969
|
-
// src/tools/mcp/mcpSpecToToolSpec.ts
|
|
1970
|
-
var DEFAULT_OUTPUT = { type: "object", additionalProperties: true };
|
|
1971
|
-
function mcpSpecToToolSpec(spec, projectPath) {
|
|
1972
|
-
const base = {
|
|
1973
|
-
name: spec.name,
|
|
1974
|
-
version: "1.0.0",
|
|
1975
|
-
kind: spec.kind,
|
|
1976
|
-
description: spec.description,
|
|
1977
|
-
inputSchema: spec.inputSchema ?? DEFAULT_OUTPUT,
|
|
1978
|
-
outputSchema: "outputSchema" in spec && spec.outputSchema ? spec.outputSchema : chunkQEJF3KDV_cjs.DEFAULT_OUTPUT_SCHEMA,
|
|
1979
|
-
capabilities: [],
|
|
1980
|
-
_meta: spec._meta,
|
|
1981
|
-
...spec.kind === N8N_KIND && "webhookUrl" in spec && spec.webhookUrl ? { endpoint: spec.webhookUrl } : {}
|
|
1982
|
-
};
|
|
1983
|
-
if (spec.kind === FUNCTION_KIND && "sourcePath" in spec && "exportName" in spec) {
|
|
1984
|
-
base._meta = {
|
|
1985
|
-
...base._meta,
|
|
1986
|
-
sourcePath: spec.sourcePath,
|
|
1987
|
-
exportName: spec.exportName,
|
|
1988
|
-
...projectPath && { projectPath }
|
|
1989
|
-
};
|
|
1990
|
-
}
|
|
1991
|
-
if (spec.kind === SKILL_KIND && "sourcePath" in spec && projectPath) {
|
|
1992
|
-
base._meta = { ...base._meta, sourcePath: spec.sourcePath, projectPath };
|
|
1993
|
-
}
|
|
1994
|
-
if (spec.kind === N8N_KIND && "sourcePath" in spec && projectPath) {
|
|
1995
|
-
base._meta = { ...base._meta, sourcePath: spec.sourcePath, projectPath };
|
|
1996
|
-
}
|
|
1997
|
-
return base;
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
// src/tools/function/scanner.ts
|
|
2001
|
-
var TOOL_TAG = "@tool";
|
|
2002
|
-
var EFFECT_VALUES = ["none", "local_write", "external_write", "destructive"];
|
|
2003
|
-
function scanForTools(options) {
|
|
2004
|
-
const projectPath = path__namespace.resolve(options.projectPath);
|
|
2005
|
-
const tsconfigPath = options.tsconfigPath ?? path__namespace.join(projectPath, "tsconfig.json");
|
|
2006
|
-
const include = options.include ?? ["**/*.ts"];
|
|
2007
|
-
const errors = [];
|
|
2008
|
-
const warnings = [];
|
|
2009
|
-
let config;
|
|
2010
|
-
let configPathResolved = path__namespace.resolve(projectPath, tsconfigPath);
|
|
2011
|
-
if (!fs__namespace.existsSync(configPathResolved)) {
|
|
2012
|
-
configPathResolved = path__namespace.join(projectPath, "tsconfig.json");
|
|
2013
|
-
}
|
|
2014
|
-
if (fs__namespace.existsSync(configPathResolved)) {
|
|
2015
|
-
const configFile = ts2__namespace.readConfigFile(configPathResolved, ts2__namespace.sys.readFile);
|
|
2016
|
-
if (configFile.error) {
|
|
2017
|
-
errors.push({ file: configPathResolved, message: String(configFile.error.messageText) });
|
|
2018
|
-
return { specs: [], errors, warnings };
|
|
2019
|
-
}
|
|
2020
|
-
const parsed = ts2__namespace.parseJsonConfigFileContent(
|
|
2021
|
-
configFile.config,
|
|
2022
|
-
ts2__namespace.sys,
|
|
2023
|
-
path__namespace.dirname(configPathResolved)
|
|
2024
|
-
);
|
|
2025
|
-
if (parsed.errors.length) {
|
|
2026
|
-
for (const e of parsed.errors) {
|
|
2027
|
-
errors.push({ file: e.file?.fileName ?? "tsconfig", message: String(e.messageText) });
|
|
2028
|
-
}
|
|
2029
|
-
return { specs: [], errors, warnings };
|
|
2030
|
-
}
|
|
2031
|
-
config = parsed;
|
|
2032
|
-
} else {
|
|
2033
|
-
config = {
|
|
2034
|
-
options: {
|
|
2035
|
-
target: ts2__namespace.ScriptTarget.ES2022,
|
|
2036
|
-
module: ts2__namespace.ModuleKind.ESNext,
|
|
2037
|
-
moduleResolution: ts2__namespace.ModuleResolutionKind.NodeNext,
|
|
2038
|
-
strict: true,
|
|
2039
|
-
skipLibCheck: true,
|
|
2040
|
-
noEmit: true
|
|
2041
|
-
},
|
|
2042
|
-
fileNames: resolveGlob(projectPath, include),
|
|
2043
|
-
errors: []
|
|
2044
|
-
};
|
|
2045
|
-
}
|
|
2046
|
-
const program = ts2__namespace.createProgram(config.fileNames, config.options);
|
|
2047
|
-
const typeChecker = program.getTypeChecker();
|
|
2048
|
-
const specs = [];
|
|
2049
|
-
for (const sourceFile of program.getSourceFiles()) {
|
|
2050
|
-
const fileName = sourceFile.fileName;
|
|
2051
|
-
if (fileName.includes("node_modules") || fileName.endsWith(".d.ts")) continue;
|
|
2052
|
-
if (!config.fileNames.some((f) => path__namespace.resolve(f) === path__namespace.resolve(fileName))) continue;
|
|
2053
|
-
ts2__namespace.forEachChild(sourceFile, (node) => {
|
|
2054
|
-
const decl = getExportedFunctionDeclaration(node);
|
|
2055
|
-
if (!decl) return;
|
|
2056
|
-
const func = decl.func;
|
|
2057
|
-
const name = decl.name;
|
|
2058
|
-
if (!name) return;
|
|
2059
|
-
const host = getJSDocHost(func);
|
|
2060
|
-
if (!hasToolTag(host)) return;
|
|
2061
|
-
const jsDoc = getJSDocComments(host);
|
|
2062
|
-
const description = getDescription(jsDoc);
|
|
2063
|
-
if (!description) {
|
|
2064
|
-
warnings.push({ file: fileName, message: `Tool ${name}: missing description, using humanized name` });
|
|
2065
|
-
}
|
|
2066
|
-
const sideEffect = getEffect(host);
|
|
2067
|
-
const onWarn = (msg) => warnings.push({ file: fileName, message: `${name}: ${msg}` });
|
|
2068
|
-
const { schema } = buildInputSchemaFromParams(func, typeChecker, onWarn);
|
|
2069
|
-
const inputSchema = Object.keys(schema.properties ?? {}).length > 0 ? schema : { type: "object", properties: {} };
|
|
2070
|
-
const outputSchema = buildOutputSchemaFromReturnType(func, typeChecker, onWarn);
|
|
2071
|
-
const sourcePath = path__namespace.relative(projectPath, fileName) || path__namespace.basename(fileName);
|
|
2072
|
-
const toolName = pathToToolName(sourcePath, name);
|
|
2073
|
-
specs.push({
|
|
2074
|
-
kind: FUNCTION_KIND,
|
|
2075
|
-
name: toolName,
|
|
2076
|
-
description: description || humanize(name),
|
|
2077
|
-
inputSchema,
|
|
2078
|
-
outputSchema,
|
|
2079
|
-
_meta: { hitl: { sideEffect } },
|
|
2080
|
-
sourcePath,
|
|
2081
|
-
exportName: name
|
|
2082
|
-
});
|
|
2083
|
-
});
|
|
2084
|
-
}
|
|
2085
|
-
return { specs, errors, warnings };
|
|
2086
|
-
}
|
|
2087
|
-
function resolveGlob(projectPath, patterns) {
|
|
2088
|
-
const result = [];
|
|
2089
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2090
|
-
const add = (f) => {
|
|
2091
|
-
const abs = path__namespace.resolve(f);
|
|
2092
|
-
if (f.endsWith(".ts") && !f.endsWith(".d.ts") && !seen.has(abs)) {
|
|
2093
|
-
seen.add(abs);
|
|
2094
|
-
result.push(abs);
|
|
2095
|
-
}
|
|
2096
|
-
};
|
|
2097
|
-
for (const p of patterns) {
|
|
2098
|
-
const full = path__namespace.join(projectPath, p);
|
|
2099
|
-
if (full.includes("*")) {
|
|
2100
|
-
const baseDir = full.replace(/\*\*\/.*$/, "").replace(/\*.*$/, "").replace(/\/?$/, "") || ".";
|
|
2101
|
-
const dir = path__namespace.resolve(projectPath, baseDir);
|
|
2102
|
-
if (fs__namespace.existsSync(dir)) walk(dir, add);
|
|
2103
|
-
} else {
|
|
2104
|
-
const resolved = path__namespace.resolve(projectPath, full);
|
|
2105
|
-
if (fs__namespace.existsSync(resolved)) {
|
|
2106
|
-
if (fs__namespace.statSync(resolved).isFile()) add(resolved);
|
|
2107
|
-
else walk(resolved, add);
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
if (result.length > 0) return result;
|
|
2112
|
-
const srcDir = path__namespace.join(projectPath, "src");
|
|
2113
|
-
if (fs__namespace.existsSync(srcDir)) return walkCollect(srcDir);
|
|
2114
|
-
return [];
|
|
2115
|
-
}
|
|
2116
|
-
function walkCollect(dir) {
|
|
2117
|
-
const out = [];
|
|
2118
|
-
walk(dir, (fullPath) => {
|
|
2119
|
-
if (fullPath.endsWith(".ts") && !fullPath.endsWith(".d.ts")) out.push(path__namespace.resolve(fullPath));
|
|
2120
|
-
});
|
|
2121
|
-
return out;
|
|
2122
|
-
}
|
|
2123
|
-
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "generated", "dist"]);
|
|
2124
|
-
function walk(dir, visit) {
|
|
2125
|
-
try {
|
|
2126
|
-
const entries = fs__namespace.readdirSync(dir, { withFileTypes: true });
|
|
2127
|
-
for (const e of entries) {
|
|
2128
|
-
const full = path__namespace.join(dir, e.name);
|
|
2129
|
-
if (e.isDirectory() && !SKIP_DIRS.has(e.name)) walk(full, visit);
|
|
2130
|
-
else if (e.isFile()) visit(full);
|
|
2131
|
-
}
|
|
2132
|
-
} catch {
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
function getExportedFunctionDeclaration(node, _sourceFile) {
|
|
2136
|
-
if (ts2__namespace.isFunctionDeclaration(node) && node.name) {
|
|
2137
|
-
const exported = (ts2__namespace.getModifiers(node) ?? []).some((m) => m.kind === ts2__namespace.SyntaxKind.ExportKeyword);
|
|
2138
|
-
if (exported) return { func: node, name: node.name.getText() };
|
|
2139
|
-
return null;
|
|
2140
|
-
}
|
|
2141
|
-
if (ts2__namespace.isVariableStatement(node)) {
|
|
2142
|
-
const exported = (ts2__namespace.getModifiers(node) ?? []).some((m) => m.kind === ts2__namespace.SyntaxKind.ExportKeyword);
|
|
2143
|
-
if (!exported) return null;
|
|
2144
|
-
for (const decl of node.declarationList.declarations) {
|
|
2145
|
-
let init = decl.initializer;
|
|
2146
|
-
while (init && (ts2__namespace.isParenthesizedExpression(init) || ts2__namespace.isAsExpression(init)))
|
|
2147
|
-
init = init.expression;
|
|
2148
|
-
if (init && ts2__namespace.isArrowFunction(init)) {
|
|
2149
|
-
const name = decl.name.getText();
|
|
2150
|
-
return { func: init, name };
|
|
2151
|
-
}
|
|
2152
|
-
if (init && ts2__namespace.isFunctionExpression(init)) {
|
|
2153
|
-
const name = decl.name.getText();
|
|
2154
|
-
return { func: init, name };
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
}
|
|
2158
|
-
return null;
|
|
2159
|
-
}
|
|
2160
|
-
function getJSDocHost(node) {
|
|
2161
|
-
const parent = node.parent;
|
|
2162
|
-
if (ts2__namespace.isVariableDeclaration(parent)) {
|
|
2163
|
-
const gp = parent.parent;
|
|
2164
|
-
if (ts2__namespace.isVariableDeclarationList(gp) && gp.parent && ts2__namespace.isVariableStatement(gp.parent)) return gp.parent;
|
|
2165
|
-
}
|
|
2166
|
-
return node;
|
|
2167
|
-
}
|
|
2168
|
-
function getJSDocComments(host) {
|
|
2169
|
-
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
2170
|
-
return all.filter((t) => ts2__namespace.isJSDoc(t));
|
|
2171
|
-
}
|
|
2172
|
-
function hasToolTag(host) {
|
|
2173
|
-
const tags = ts2__namespace.getJSDocTags(host);
|
|
2174
|
-
for (const tag of tags) {
|
|
2175
|
-
const name = tag.tagName?.getText() ?? "";
|
|
2176
|
-
if (name === "tool") return true;
|
|
2177
|
-
}
|
|
2178
|
-
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
2179
|
-
for (const t of all) {
|
|
2180
|
-
if (ts2__namespace.isJSDoc(t)) {
|
|
2181
|
-
const full = t.getFullText();
|
|
2182
|
-
if (full.includes(TOOL_TAG)) return true;
|
|
2183
|
-
}
|
|
2184
|
-
}
|
|
2185
|
-
return false;
|
|
2186
|
-
}
|
|
2187
|
-
function getDescription(jsDocs, fallbackName) {
|
|
2188
|
-
for (const doc of jsDocs) {
|
|
2189
|
-
const comment = doc.comment;
|
|
2190
|
-
if (typeof comment === "string") {
|
|
2191
|
-
const first = comment.split(/\n/)[0]?.trim() ?? "";
|
|
2192
|
-
if (first && !first.startsWith("@")) return first;
|
|
2193
|
-
}
|
|
2194
|
-
if (Array.isArray(comment)) {
|
|
2195
|
-
const first = comment[0];
|
|
2196
|
-
if (first && typeof first === "object" && "text" in first) {
|
|
2197
|
-
const t = first.text.trim();
|
|
2198
|
-
if (t && !t.startsWith("@")) return t;
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
const full = doc.getFullText();
|
|
2202
|
-
const match = full.match(/\*\s*@tool\s+(.+?)(?=\n|$|\*\/)/s);
|
|
2203
|
-
if (match?.[1]) return match[1].trim();
|
|
2204
|
-
}
|
|
2205
|
-
return "";
|
|
2206
|
-
}
|
|
2207
|
-
function getEffect(host) {
|
|
2208
|
-
const tags = ts2__namespace.getJSDocTags(host);
|
|
2209
|
-
for (const tag of tags) {
|
|
2210
|
-
const name = tag.tagName?.getText() ?? "";
|
|
2211
|
-
if (name === "effect") {
|
|
2212
|
-
const comment = tag.comment;
|
|
2213
|
-
const v = (typeof comment === "string" ? comment : "").trim().toLowerCase();
|
|
2214
|
-
if (EFFECT_VALUES.includes(v)) return v;
|
|
2215
|
-
}
|
|
2216
|
-
}
|
|
2217
|
-
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
2218
|
-
for (const t of all) {
|
|
2219
|
-
if (ts2__namespace.isJSDoc(t)) {
|
|
2220
|
-
const full = t.getFullText();
|
|
2221
|
-
const match = full.match(/\*\s*@effect\s+(\w+)/);
|
|
2222
|
-
if (match && EFFECT_VALUES.includes(match[1])) return match[1];
|
|
2223
|
-
}
|
|
2224
|
-
}
|
|
2225
|
-
return "none";
|
|
2226
|
-
}
|
|
2227
|
-
function humanize(name) {
|
|
2228
|
-
return name.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
|
|
2229
|
-
}
|
|
2230
|
-
function scan(projectPath, options = {}) {
|
|
2231
|
-
const root = path__namespace.resolve(projectPath);
|
|
2232
|
-
const result = scanForTools({
|
|
2233
|
-
projectPath: root,
|
|
2234
|
-
include: options.include ?? ["**/*.ts"],
|
|
2235
|
-
tsconfigPath: options.tsconfigPath
|
|
2236
|
-
});
|
|
2237
|
-
const specs = result.specs.map((s) => mcpSpecToToolSpec(s, root));
|
|
2238
|
-
return Promise.resolve({
|
|
2239
|
-
specs,
|
|
2240
|
-
errors: result.errors,
|
|
2241
|
-
warnings: result.warnings
|
|
2242
|
-
});
|
|
2243
|
-
}
|
|
2244
|
-
var DEFAULT_EXTENSIONS = [".js", ".mjs"];
|
|
2245
|
-
async function resolveEntryPoint(dirPath, baseName, extensions = DEFAULT_EXTENSIONS) {
|
|
2246
|
-
if (extensions.some((ext) => baseName.endsWith(ext))) {
|
|
2247
|
-
const fullPath = path.join(dirPath, baseName);
|
|
2248
|
-
await promises.stat(fullPath);
|
|
2249
|
-
return fullPath;
|
|
2250
|
-
}
|
|
2251
|
-
for (const ext of extensions) {
|
|
2252
|
-
const fullPath = path.join(dirPath, `${baseName}${ext}`);
|
|
2253
|
-
try {
|
|
2254
|
-
await promises.stat(fullPath);
|
|
2255
|
-
return fullPath;
|
|
2256
|
-
} catch {
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
throw new Error(
|
|
2260
|
-
`Could not find entry point in ${dirPath}. Tried: ${extensions.map((e) => baseName + e).join(", ")}`
|
|
2261
|
-
);
|
|
2262
|
-
}
|
|
2263
|
-
|
|
2264
|
-
// src/tools/skill/SkillManifest.ts
|
|
2265
|
-
var SkillManifestError = class extends Error {
|
|
2266
|
-
constructor(path7, field, message) {
|
|
2267
|
-
super(`SKILL.md error in ${path7}: ${message}`);
|
|
2268
|
-
this.path = path7;
|
|
2269
|
-
this.field = field;
|
|
2270
|
-
this.name = "SkillManifestError";
|
|
2271
|
-
}
|
|
2272
|
-
};
|
|
2273
|
-
var NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
2274
|
-
var NAME_MAX_LENGTH = 64;
|
|
2275
|
-
var DESCRIPTION_MAX_LENGTH = 1024;
|
|
2276
|
-
var COMPATIBILITY_MAX_LENGTH = 500;
|
|
2277
|
-
var RESERVED_WORDS = ["anthropic", "claude"];
|
|
2278
|
-
var XML_TAG_PATTERN = /<\/?[a-zA-Z][^>]*>/;
|
|
2279
|
-
function validateFrontmatter(fm, filePath) {
|
|
2280
|
-
if (!fm.name || typeof fm.name !== "string") {
|
|
2281
|
-
throw new SkillManifestError(filePath, "name", "name is required");
|
|
2282
|
-
}
|
|
2283
|
-
if (fm.name.length > NAME_MAX_LENGTH) {
|
|
2284
|
-
throw new SkillManifestError(
|
|
2285
|
-
filePath,
|
|
2286
|
-
"name",
|
|
2287
|
-
`name must be at most ${NAME_MAX_LENGTH} characters (got ${fm.name.length})`
|
|
2288
|
-
);
|
|
2289
|
-
}
|
|
2290
|
-
if (!NAME_PATTERN.test(fm.name)) {
|
|
2291
|
-
throw new SkillManifestError(
|
|
2292
|
-
filePath,
|
|
2293
|
-
"name",
|
|
2294
|
-
"name must contain only lowercase letters, numbers, and hyphens"
|
|
2295
|
-
);
|
|
2296
|
-
}
|
|
2297
|
-
if (fm.name.startsWith("-") || fm.name.endsWith("-")) {
|
|
2298
|
-
throw new SkillManifestError(
|
|
2299
|
-
filePath,
|
|
2300
|
-
"name",
|
|
2301
|
-
"name must not start or end with a hyphen"
|
|
2302
|
-
);
|
|
2303
|
-
}
|
|
2304
|
-
if (fm.name.includes("--")) {
|
|
2305
|
-
throw new SkillManifestError(
|
|
2306
|
-
filePath,
|
|
2307
|
-
"name",
|
|
2308
|
-
"name must not contain consecutive hyphens"
|
|
2309
|
-
);
|
|
2310
|
-
}
|
|
2311
|
-
if (XML_TAG_PATTERN.test(fm.name)) {
|
|
2312
|
-
throw new SkillManifestError(filePath, "name", "name cannot contain XML tags");
|
|
2313
|
-
}
|
|
2314
|
-
for (const reserved of RESERVED_WORDS) {
|
|
2315
|
-
if (fm.name.includes(reserved)) {
|
|
2316
|
-
throw new SkillManifestError(
|
|
2317
|
-
filePath,
|
|
2318
|
-
"name",
|
|
2319
|
-
`name cannot contain reserved word "${reserved}"`
|
|
2320
|
-
);
|
|
2321
|
-
}
|
|
2322
|
-
}
|
|
2323
|
-
if (!fm.description || typeof fm.description !== "string") {
|
|
2324
|
-
throw new SkillManifestError(
|
|
2325
|
-
filePath,
|
|
2326
|
-
"description",
|
|
2327
|
-
"description is required and must be non-empty"
|
|
2328
|
-
);
|
|
2329
|
-
}
|
|
2330
|
-
if (fm.description.length > DESCRIPTION_MAX_LENGTH) {
|
|
2331
|
-
throw new SkillManifestError(
|
|
2332
|
-
filePath,
|
|
2333
|
-
"description",
|
|
2334
|
-
`description must be at most ${DESCRIPTION_MAX_LENGTH} characters (got ${fm.description.length})`
|
|
2335
|
-
);
|
|
2336
|
-
}
|
|
2337
|
-
if (XML_TAG_PATTERN.test(fm.description)) {
|
|
2338
|
-
throw new SkillManifestError(
|
|
2339
|
-
filePath,
|
|
2340
|
-
"description",
|
|
2341
|
-
"description cannot contain XML tags"
|
|
2342
|
-
);
|
|
2343
|
-
}
|
|
2344
|
-
if (fm.compatibility != null && typeof fm.compatibility === "string") {
|
|
2345
|
-
if (fm.compatibility.length > COMPATIBILITY_MAX_LENGTH) {
|
|
2346
|
-
throw new SkillManifestError(
|
|
2347
|
-
filePath,
|
|
2348
|
-
"compatibility",
|
|
2349
|
-
`compatibility must be at most ${COMPATIBILITY_MAX_LENGTH} characters (got ${fm.compatibility.length})`
|
|
2350
|
-
);
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
|
|
2355
|
-
// src/tools/skill/SkillMdParser.ts
|
|
2356
|
-
var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2357
|
-
".py",
|
|
2358
|
-
".js",
|
|
2359
|
-
".mjs",
|
|
2360
|
-
".ts",
|
|
2361
|
-
".sh",
|
|
2362
|
-
".bash",
|
|
2363
|
-
".rb",
|
|
2364
|
-
".go"
|
|
2365
|
-
]);
|
|
2366
|
-
var INSTRUCTION_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
2367
|
-
var EXCLUDED_FILES = /* @__PURE__ */ new Set(["SKILL.md", "tool.json"]);
|
|
2368
|
-
function parseSkillMd(content, filePath) {
|
|
2369
|
-
const trimmed = content.trimStart();
|
|
2370
|
-
if (!trimmed.startsWith("---")) {
|
|
2371
|
-
throw new SkillManifestError(
|
|
2372
|
-
filePath,
|
|
2373
|
-
"frontmatter",
|
|
2374
|
-
"SKILL.md must start with YAML frontmatter (---)"
|
|
2375
|
-
);
|
|
2376
|
-
}
|
|
2377
|
-
const endIndex = trimmed.indexOf("\n---", 3);
|
|
2378
|
-
if (endIndex === -1) {
|
|
2379
|
-
throw new SkillManifestError(
|
|
2380
|
-
filePath,
|
|
2381
|
-
"frontmatter",
|
|
2382
|
-
"SKILL.md frontmatter is not closed (missing closing ---)"
|
|
2383
|
-
);
|
|
2384
|
-
}
|
|
2385
|
-
const yamlBlock = trimmed.slice(4, endIndex).trim();
|
|
2386
|
-
const body = trimmed.slice(endIndex + 4).trim();
|
|
2387
|
-
let raw;
|
|
2388
|
-
try {
|
|
2389
|
-
const parsed = yaml__default.default.load(yamlBlock);
|
|
2390
|
-
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
2391
|
-
throw new SkillManifestError(
|
|
2392
|
-
filePath,
|
|
2393
|
-
"frontmatter",
|
|
2394
|
-
"YAML frontmatter must be an object (key: value)"
|
|
2395
|
-
);
|
|
2396
|
-
}
|
|
2397
|
-
raw = parsed;
|
|
2398
|
-
} catch (err) {
|
|
2399
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2400
|
-
throw new SkillManifestError(
|
|
2401
|
-
filePath,
|
|
2402
|
-
"frontmatter",
|
|
2403
|
-
`Invalid YAML frontmatter: ${message}`
|
|
2404
|
-
);
|
|
2405
|
-
}
|
|
2406
|
-
const name = stringField(raw, "name", filePath);
|
|
2407
|
-
const description = stringField(raw, "description", filePath);
|
|
2408
|
-
if (!name || !description) {
|
|
2409
|
-
throw new SkillManifestError(
|
|
2410
|
-
filePath,
|
|
2411
|
-
"frontmatter",
|
|
2412
|
-
!name ? "name is required" : "description is required"
|
|
2413
|
-
);
|
|
2414
|
-
}
|
|
2415
|
-
const license = stringField(raw, "license");
|
|
2416
|
-
const compatibility = stringField(raw, "compatibility");
|
|
2417
|
-
const allowedTools = stringField(raw, "allowed-tools");
|
|
2418
|
-
const metadata = normalizeMetadata(raw.metadata);
|
|
2419
|
-
const frontmatter = {
|
|
2420
|
-
name,
|
|
2421
|
-
description,
|
|
2422
|
-
...license && { license },
|
|
2423
|
-
...compatibility && { compatibility },
|
|
2424
|
-
...allowedTools && { allowedTools },
|
|
2425
|
-
...metadata && Object.keys(metadata).length > 0 && { metadata }
|
|
2426
|
-
};
|
|
2427
|
-
validateFrontmatter(frontmatter, filePath);
|
|
2428
|
-
return { frontmatter, instructions: body };
|
|
2429
|
-
}
|
|
2430
|
-
function stringField(raw, key, filePath) {
|
|
2431
|
-
const v = raw[key];
|
|
2432
|
-
if (v == null) return "";
|
|
2433
|
-
if (typeof v === "string") return v;
|
|
2434
|
-
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
2435
|
-
if (Array.isArray(v)) {
|
|
2436
|
-
return v.map((x) => typeof x === "string" ? x : String(x)).join("\n");
|
|
2437
|
-
}
|
|
2438
|
-
if (filePath) {
|
|
2439
|
-
throw new SkillManifestError(
|
|
2440
|
-
filePath,
|
|
2441
|
-
"frontmatter",
|
|
2442
|
-
`Frontmatter field "${key}" must be a string, number, boolean, or array`
|
|
2443
|
-
);
|
|
2444
|
-
}
|
|
2445
|
-
return String(v);
|
|
2446
|
-
}
|
|
2447
|
-
function normalizeMetadata(val) {
|
|
2448
|
-
if (val == null) return void 0;
|
|
2449
|
-
if (typeof val === "object" && !Array.isArray(val)) {
|
|
2450
|
-
const out = {};
|
|
2451
|
-
for (const [k, v] of Object.entries(val)) {
|
|
2452
|
-
if (typeof k === "string" && v !== void 0 && v !== null) {
|
|
2453
|
-
out[k] = typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
2454
|
-
}
|
|
2455
|
-
}
|
|
2456
|
-
return Object.keys(out).length ? out : void 0;
|
|
2457
|
-
}
|
|
2458
|
-
if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
|
|
2459
|
-
return { value: String(val) };
|
|
2460
|
-
}
|
|
2461
|
-
return void 0;
|
|
2462
|
-
}
|
|
2463
|
-
async function scanSkillResources(dirPath) {
|
|
2464
|
-
const resources = [];
|
|
2465
|
-
await scanDir(dirPath, dirPath, resources);
|
|
2466
|
-
return resources;
|
|
2467
|
-
}
|
|
2468
|
-
async function scanDir(basePath, currentPath, resources) {
|
|
2469
|
-
let entries;
|
|
2470
|
-
try {
|
|
2471
|
-
entries = await promises.readdir(currentPath, { withFileTypes: true });
|
|
2472
|
-
} catch {
|
|
2473
|
-
return;
|
|
2474
|
-
}
|
|
2475
|
-
for (const entry of entries) {
|
|
2476
|
-
const fullPath = path.join(currentPath, entry.name);
|
|
2477
|
-
if (entry.isDirectory()) {
|
|
2478
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
2479
|
-
continue;
|
|
2480
|
-
}
|
|
2481
|
-
await scanDir(basePath, fullPath, resources);
|
|
2482
|
-
} else if (entry.isFile()) {
|
|
2483
|
-
if (EXCLUDED_FILES.has(entry.name)) {
|
|
2484
|
-
continue;
|
|
2485
|
-
}
|
|
2486
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
2487
|
-
const relPath = path.relative(basePath, fullPath);
|
|
2488
|
-
resources.push({
|
|
2489
|
-
relativePath: relPath,
|
|
2490
|
-
absolutePath: fullPath,
|
|
2491
|
-
extension: ext,
|
|
2492
|
-
type: inferResourceType(ext)
|
|
2493
|
-
});
|
|
2494
|
-
}
|
|
2495
|
-
}
|
|
2496
|
-
}
|
|
2497
|
-
function inferResourceType(ext) {
|
|
2498
|
-
if (CODE_EXTENSIONS.has(ext)) return "code";
|
|
2499
|
-
if (INSTRUCTION_EXTENSIONS.has(ext)) return "instructions";
|
|
2500
|
-
return "data";
|
|
2501
|
-
}
|
|
2502
|
-
async function loadSkillDefinition(dirPath) {
|
|
2503
|
-
const skillMdPath = path.join(dirPath, "SKILL.md");
|
|
2504
|
-
let content;
|
|
2505
|
-
try {
|
|
2506
|
-
content = await promises.readFile(skillMdPath, "utf-8");
|
|
2507
|
-
} catch (err) {
|
|
2508
|
-
throw new SkillManifestError(
|
|
2509
|
-
skillMdPath,
|
|
2510
|
-
"file",
|
|
2511
|
-
`Cannot read SKILL.md: ${err.message}`
|
|
2512
|
-
);
|
|
2513
|
-
}
|
|
2514
|
-
const { frontmatter, instructions } = parseSkillMd(content, skillMdPath);
|
|
2515
|
-
const resources = await scanSkillResources(dirPath);
|
|
2516
|
-
return {
|
|
2517
|
-
frontmatter,
|
|
2518
|
-
instructions,
|
|
2519
|
-
resources,
|
|
2520
|
-
dirPath,
|
|
2521
|
-
skillMdPath
|
|
2522
|
-
};
|
|
2523
|
-
}
|
|
2524
|
-
|
|
2525
|
-
// src/tools/skill/scanSkill.ts
|
|
2526
|
-
var defaultInputSchema = { type: "object", properties: {}, additionalProperties: true };
|
|
2527
|
-
async function scanForSkill(projectPath) {
|
|
2528
|
-
const projectRoot = path__namespace.resolve(projectPath);
|
|
2529
|
-
const dirs = await findDirsContainingFile(projectRoot, "SKILL.md");
|
|
2530
|
-
const skills = [];
|
|
2531
|
-
const errors = [];
|
|
2532
|
-
for (const dirPath of dirs) {
|
|
2533
|
-
const relativePath = path__namespace.relative(projectRoot, dirPath) || path__namespace.basename(dirPath);
|
|
2534
|
-
try {
|
|
2535
|
-
const skillDef = await loadSkillDefinition(dirPath);
|
|
2536
|
-
const name = pathToToolName(relativePath, skillDef.frontmatter.name);
|
|
2537
|
-
skills.push({
|
|
2538
|
-
kind: SKILL_KIND,
|
|
2539
|
-
name,
|
|
2540
|
-
description: skillDef.frontmatter.description,
|
|
2541
|
-
inputSchema: defaultInputSchema,
|
|
2542
|
-
_meta: { hitl: { sideEffect: "none" } },
|
|
2543
|
-
sourcePath: relativePath.replace(/\\/g, "/")
|
|
2544
|
-
});
|
|
2545
|
-
} catch (err) {
|
|
2546
|
-
errors.push({ dir: relativePath, message: err instanceof Error ? err.message : String(err) });
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
return { skills, errors };
|
|
2550
|
-
}
|
|
2551
|
-
async function scan2(projectPath, _options = {}) {
|
|
2552
|
-
const root = path__namespace.resolve(projectPath);
|
|
2553
|
-
const result = await scanForSkill(root);
|
|
2554
|
-
const specs = result.skills.map((s) => mcpSpecToToolSpec(s, root));
|
|
2555
|
-
return {
|
|
2556
|
-
specs,
|
|
2557
|
-
errors: result.errors.map((e) => ({ file: e.dir, message: e.message }))
|
|
2558
|
-
};
|
|
2559
|
-
}
|
|
2560
|
-
async function readWorkflowMeta(dirPath, workflowFileName = "workflow.json") {
|
|
2561
|
-
const workflowPath = path.join(dirPath, workflowFileName);
|
|
2562
|
-
let raw;
|
|
2563
|
-
try {
|
|
2564
|
-
raw = await promises.readFile(workflowPath, "utf-8");
|
|
2565
|
-
} catch (err) {
|
|
2566
|
-
throw new DiscoveryError(
|
|
2567
|
-
dirPath,
|
|
2568
|
-
"load",
|
|
2569
|
-
`Failed to read workflow: ${workflowPath}`,
|
|
2570
|
-
err
|
|
2571
|
-
);
|
|
2572
|
-
}
|
|
2573
|
-
let workflowDef;
|
|
2574
|
-
try {
|
|
2575
|
-
workflowDef = JSON.parse(raw);
|
|
2576
|
-
} catch (err) {
|
|
2577
|
-
throw new DiscoveryError(
|
|
2578
|
-
dirPath,
|
|
2579
|
-
"load",
|
|
2580
|
-
`Invalid JSON in ${workflowPath}`,
|
|
2581
|
-
err
|
|
2582
|
-
);
|
|
2583
|
-
}
|
|
2584
|
-
if (!workflowDef.nodes || !Array.isArray(workflowDef.nodes)) {
|
|
2585
|
-
throw new DiscoveryError(
|
|
2586
|
-
dirPath,
|
|
2587
|
-
"validate",
|
|
2588
|
-
`workflow.json must have a "nodes" array`
|
|
2589
|
-
);
|
|
2590
|
-
}
|
|
2591
|
-
const meta = workflowDef.meta;
|
|
2592
|
-
const name = workflowDef.name || meta?.name || path.basename(dirPath);
|
|
2593
|
-
const description = workflowDef.description || meta?.description || `n8n workflow: ${name}`;
|
|
2594
|
-
let webhookUrl;
|
|
2595
|
-
const nodes = workflowDef.nodes;
|
|
2596
|
-
if (Array.isArray(nodes)) {
|
|
2597
|
-
const webhookNode = nodes.find(
|
|
2598
|
-
(n) => n.type === "n8n-nodes-base.webhook" || n.type?.includes("webhook")
|
|
2599
|
-
);
|
|
2600
|
-
if (webhookNode?.parameters && typeof webhookNode.parameters === "object") {
|
|
2601
|
-
const params = webhookNode.parameters;
|
|
2602
|
-
const pathVal = params.path ?? params.webhookPath;
|
|
2603
|
-
if (typeof pathVal === "string" && pathVal.startsWith("http")) {
|
|
2604
|
-
webhookUrl = pathVal;
|
|
2605
|
-
}
|
|
2606
|
-
}
|
|
2607
|
-
}
|
|
2608
|
-
return { name, description, webhookUrl, workflowDef };
|
|
2609
|
-
}
|
|
2610
|
-
async function loadN8nTool(dirPath, manifest) {
|
|
2611
|
-
const { workflowDef } = await readWorkflowMeta(
|
|
2612
|
-
dirPath,
|
|
2613
|
-
manifest.entryPoint ?? "workflow.json"
|
|
2614
|
-
);
|
|
2615
|
-
return { manifest, dirPath, workflowDef };
|
|
2616
|
-
}
|
|
2617
|
-
|
|
2618
|
-
// src/tools/n8n/scanN8n.ts
|
|
2619
|
-
var defaultInputSchema2 = { type: "object", properties: {}, additionalProperties: true };
|
|
2620
|
-
async function scanForN8n(projectPath) {
|
|
2621
|
-
const projectRoot = path__namespace.resolve(projectPath);
|
|
2622
|
-
const dirs = await findDirsContainingFile(projectRoot, "workflow.json");
|
|
2623
|
-
const n8n = [];
|
|
2624
|
-
const errors = [];
|
|
2625
|
-
for (const dirPath of dirs) {
|
|
2626
|
-
const relativePath = path__namespace.relative(projectRoot, dirPath) || path__namespace.basename(dirPath);
|
|
2627
|
-
try {
|
|
2628
|
-
const { name: wfName, description: wfDesc, webhookUrl } = await readWorkflowMeta(dirPath);
|
|
2629
|
-
const toolName = pathToToolName(relativePath, wfName);
|
|
2630
|
-
n8n.push({
|
|
2631
|
-
kind: N8N_KIND,
|
|
2632
|
-
name: toolName,
|
|
2633
|
-
description: wfDesc,
|
|
2634
|
-
inputSchema: defaultInputSchema2,
|
|
2635
|
-
_meta: { hitl: { sideEffect: "external_write" } },
|
|
2636
|
-
sourcePath: relativePath.replace(/\\/g, "/"),
|
|
2637
|
-
webhookUrl
|
|
2638
|
-
});
|
|
2639
|
-
} catch (err) {
|
|
2640
|
-
errors.push({ dir: relativePath, message: err instanceof Error ? err.message : String(err) });
|
|
2641
|
-
}
|
|
2642
|
-
}
|
|
2643
|
-
return { n8n, errors };
|
|
2644
|
-
}
|
|
2645
|
-
async function scan3(projectPath, _options = {}) {
|
|
2646
|
-
const root = path__namespace.resolve(projectPath);
|
|
2647
|
-
const result = await scanForN8n(root);
|
|
2648
|
-
const specs = result.n8n.map((s) => mcpSpecToToolSpec(s, root));
|
|
2649
|
-
return {
|
|
2650
|
-
specs,
|
|
2651
|
-
errors: result.errors.map((e) => ({ file: e.dir, message: e.message }))
|
|
2652
|
-
};
|
|
2653
|
-
}
|
|
2654
|
-
|
|
2655
|
-
// src/tools/mcp/types.ts
|
|
2656
|
-
var MCP_KIND = "mcp";
|
|
2657
|
-
|
|
2658
|
-
// src/tools/mcp/scanner.ts
|
|
2659
|
-
async function scan4(projectPath, options = {}) {
|
|
2660
|
-
const root = path__namespace.resolve(projectPath);
|
|
2661
|
-
const namespace = options.namespace ?? "dir";
|
|
2662
|
-
const errors = [];
|
|
2663
|
-
const scanner = new DirectoryScanner({
|
|
2664
|
-
roots: [root],
|
|
2665
|
-
namespace,
|
|
2666
|
-
extensions: options.extensions,
|
|
2667
|
-
onError: (dir, err) => {
|
|
2668
|
-
errors.push({ file: dir, message: err.message });
|
|
2669
|
-
options.onError?.(dir, err);
|
|
2670
|
-
}
|
|
2671
|
-
});
|
|
2672
|
-
let specs;
|
|
2673
|
-
try {
|
|
2674
|
-
specs = await scanner.scan();
|
|
2675
|
-
} catch (err) {
|
|
2676
|
-
errors.push({
|
|
2677
|
-
file: root,
|
|
2678
|
-
message: err instanceof Error ? err.message : String(err)
|
|
2679
|
-
});
|
|
2680
|
-
return { specs: [], errors };
|
|
2681
|
-
}
|
|
2682
|
-
const filtered = specs.filter((s) => s.kind === MCP_KIND);
|
|
2683
|
-
return { specs: filtered, errors };
|
|
2684
|
-
}
|
|
2685
|
-
|
|
2686
|
-
// src/tools/langchain/types.ts
|
|
2687
|
-
var LANGCHAIN_KIND = "langchain";
|
|
2688
|
-
var LANGCHAIN_DIR_NAME = "langchain";
|
|
2689
|
-
|
|
2690
|
-
// src/tools/langchain/scanner.ts
|
|
2691
|
-
async function scan5(projectPath, options = {}) {
|
|
2692
|
-
const root = path__namespace.resolve(projectPath);
|
|
2693
|
-
const namespace = options.namespace ?? "dir";
|
|
2694
|
-
const errors = [];
|
|
2695
|
-
const scanner = new DirectoryScanner({
|
|
2696
|
-
roots: [root],
|
|
2697
|
-
namespace,
|
|
2698
|
-
extensions: options.extensions,
|
|
2699
|
-
onError: (dir, err) => {
|
|
2700
|
-
errors.push({ file: dir, message: err.message });
|
|
2701
|
-
options.onError?.(dir, err);
|
|
2702
|
-
}
|
|
2703
|
-
});
|
|
2704
|
-
let specs;
|
|
2705
|
-
try {
|
|
2706
|
-
specs = await scanner.scan();
|
|
2707
|
-
} catch (err) {
|
|
2708
|
-
errors.push({
|
|
2709
|
-
file: root,
|
|
2710
|
-
message: err instanceof Error ? err.message : String(err)
|
|
2711
|
-
});
|
|
2712
|
-
return { specs: [], errors };
|
|
2713
|
-
}
|
|
2714
|
-
const filtered = specs.filter((s) => s.kind === LANGCHAIN_KIND);
|
|
2715
|
-
return { specs: filtered, errors };
|
|
2716
|
-
}
|
|
2717
|
-
async function loadLangChainTool(dirPath, manifest, extensions) {
|
|
2718
|
-
let entryFile;
|
|
2719
|
-
try {
|
|
2720
|
-
entryFile = await resolveEntryPoint(
|
|
2721
|
-
dirPath,
|
|
2722
|
-
manifest.entryPoint ?? "index",
|
|
2723
|
-
extensions
|
|
2724
|
-
);
|
|
2725
|
-
} catch (err) {
|
|
2726
|
-
throw new DiscoveryError(
|
|
2727
|
-
dirPath,
|
|
2728
|
-
"load",
|
|
2729
|
-
`Cannot find LangChain entry point`,
|
|
2730
|
-
err
|
|
2731
|
-
);
|
|
2732
|
-
}
|
|
2733
|
-
let mod;
|
|
2734
|
-
try {
|
|
2735
|
-
mod = await import(url.pathToFileURL(entryFile).href);
|
|
2736
|
-
} catch (err) {
|
|
2737
|
-
throw new DiscoveryError(
|
|
2738
|
-
dirPath,
|
|
2739
|
-
"load",
|
|
2740
|
-
`Failed to import ${entryFile}`,
|
|
2741
|
-
err
|
|
2742
|
-
);
|
|
2743
|
-
}
|
|
2744
|
-
const tool = mod.default ?? mod.tool ?? mod;
|
|
2745
|
-
if (!tool || typeof tool.invoke !== "function") {
|
|
2746
|
-
throw new DiscoveryError(
|
|
2747
|
-
dirPath,
|
|
2748
|
-
"validate",
|
|
2749
|
-
`Entry point must export an object with invoke() method (LangChainToolLike)`
|
|
2750
|
-
);
|
|
2751
|
-
}
|
|
2752
|
-
return { manifest, dirPath, impl: tool };
|
|
2753
|
-
}
|
|
2754
|
-
var DEFAULT_EXTENSIONS2 = [".js", ".mjs"];
|
|
2755
|
-
async function listSkillProgramFiles(dirPath, extensions = DEFAULT_EXTENSIONS2) {
|
|
2756
|
-
let entries;
|
|
2757
|
-
try {
|
|
2758
|
-
const dirEntries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
2759
|
-
entries = dirEntries.map((entry) => ({
|
|
2760
|
-
name: entry.name,
|
|
2761
|
-
isFile: entry.isFile()
|
|
2762
|
-
}));
|
|
2763
|
-
} catch {
|
|
2764
|
-
return [];
|
|
2765
|
-
}
|
|
2766
|
-
return entries.filter((e) => e.isFile).map((e) => e.name).filter((name) => {
|
|
2767
|
-
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
2768
|
-
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
2769
|
-
return extensions.some((ext) => name.endsWith(ext));
|
|
2770
|
-
}).sort((a, b) => {
|
|
2771
|
-
if (a === "handler.js" || a === "index.js") return -1;
|
|
2772
|
-
if (b === "handler.js" || b === "index.js") return 1;
|
|
2773
|
-
return a.localeCompare(b);
|
|
2774
|
-
});
|
|
2775
|
-
}
|
|
2776
|
-
function isLangChainLikeTool(val) {
|
|
2777
|
-
return val != null && typeof val === "object" && "invoke" in val && typeof val.invoke === "function";
|
|
2778
|
-
}
|
|
2779
|
-
function isConstructable(val) {
|
|
2780
|
-
return typeof val === "function" && typeof val.prototype === "object";
|
|
2781
|
-
}
|
|
2782
|
-
async function loadOneSkillProgram(dirPath, manifest, entryFile, skillDef, programKey, extensions) {
|
|
2783
|
-
let impl;
|
|
2784
|
-
try {
|
|
2785
|
-
const fullPath = await resolveEntryPoint(dirPath, entryFile, extensions ?? [".js", ".mjs"]);
|
|
2786
|
-
const mod = await import(url.pathToFileURL(fullPath).href);
|
|
2787
|
-
const fn = mod.default ?? mod.handler ?? mod.Tool;
|
|
2788
|
-
if (isLangChainLikeTool(fn)) {
|
|
2789
|
-
impl = fn;
|
|
2790
|
-
} else if (isConstructable(fn)) {
|
|
2791
|
-
const instance = new fn();
|
|
2792
|
-
if (isLangChainLikeTool(instance)) impl = instance;
|
|
2793
|
-
} else if (typeof fn === "function") {
|
|
2794
|
-
impl = fn;
|
|
2795
|
-
}
|
|
2796
|
-
} catch {
|
|
2797
|
-
}
|
|
2798
|
-
return {
|
|
2799
|
-
manifest,
|
|
2800
|
-
dirPath,
|
|
2801
|
-
impl,
|
|
2802
|
-
skillDefinition: skillDef,
|
|
2803
|
-
programKey
|
|
2804
|
-
};
|
|
2805
|
-
}
|
|
2806
|
-
async function loadSkillTools(dirPath, manifest, extensions) {
|
|
2807
|
-
let skillDef;
|
|
2808
|
-
try {
|
|
2809
|
-
skillDef = await loadSkillDefinition(dirPath);
|
|
2810
|
-
} catch (err) {
|
|
2811
|
-
throw new DiscoveryError(
|
|
2812
|
-
dirPath,
|
|
2813
|
-
"load",
|
|
2814
|
-
`Failed to parse SKILL.md: ${err.message}`,
|
|
2815
|
-
err
|
|
2816
|
-
);
|
|
2817
|
-
}
|
|
2818
|
-
const programs = manifest.programs;
|
|
2819
|
-
if (programs && typeof programs === "object" && Object.keys(programs).length > 0) {
|
|
2820
|
-
const result = [];
|
|
2821
|
-
for (const [programKey, entryFile2] of Object.entries(programs)) {
|
|
2822
|
-
const loaded2 = await loadOneSkillProgram(
|
|
2823
|
-
dirPath,
|
|
2824
|
-
manifest,
|
|
2825
|
-
entryFile2,
|
|
2826
|
-
skillDef,
|
|
2827
|
-
programKey,
|
|
2828
|
-
extensions
|
|
2829
|
-
);
|
|
2830
|
-
result.push(loaded2);
|
|
2831
|
-
}
|
|
2832
|
-
return result;
|
|
2833
|
-
}
|
|
2834
|
-
const exts = extensions ?? DEFAULT_EXTENSIONS2;
|
|
2835
|
-
const files = await listSkillProgramFiles(dirPath, exts);
|
|
2836
|
-
if (files.length >= 2) {
|
|
2837
|
-
const result = [];
|
|
2838
|
-
for (let i = 0; i < files.length; i++) {
|
|
2839
|
-
const file = files[i];
|
|
2840
|
-
const programKey = i === 0 ? "default" : file.replace(/\.[^.]+$/, "");
|
|
2841
|
-
const loaded2 = await loadOneSkillProgram(
|
|
2842
|
-
dirPath,
|
|
2843
|
-
manifest,
|
|
2844
|
-
file,
|
|
2845
|
-
skillDef,
|
|
2846
|
-
programKey,
|
|
2847
|
-
extensions
|
|
2848
|
-
);
|
|
2849
|
-
result.push(loaded2);
|
|
2850
|
-
}
|
|
2851
|
-
return result;
|
|
2852
|
-
}
|
|
2853
|
-
const entryFile = manifest.entryPoint ?? files[0] ?? "handler";
|
|
2854
|
-
const loaded = await loadOneSkillProgram(
|
|
2855
|
-
dirPath,
|
|
2856
|
-
manifest,
|
|
2857
|
-
entryFile,
|
|
2858
|
-
skillDef,
|
|
2859
|
-
void 0,
|
|
2860
|
-
extensions
|
|
2861
|
-
);
|
|
2862
|
-
return [loaded];
|
|
2863
|
-
}
|
|
2864
|
-
async function listLangchainEntryFiles(dirPath, extensions) {
|
|
2865
|
-
let entries;
|
|
2866
|
-
try {
|
|
2867
|
-
const dirEntries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
2868
|
-
entries = dirEntries.map((entry) => ({
|
|
2869
|
-
name: entry.name,
|
|
2870
|
-
isFile: entry.isFile()
|
|
2871
|
-
}));
|
|
2872
|
-
} catch {
|
|
2873
|
-
return [];
|
|
2874
|
-
}
|
|
2875
|
-
return entries.filter((e) => e.isFile).map((e) => e.name).filter((name) => {
|
|
2876
|
-
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
2877
|
-
if (name.endsWith(".d.ts")) return false;
|
|
2878
|
-
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
2879
|
-
return extensions.some((ext) => name.endsWith(ext));
|
|
2880
|
-
});
|
|
2881
|
-
}
|
|
2882
|
-
async function loadLangChainToolsFromDir(dirPath, dirName, manifest, strict, namespace, extensions, langchainDirName, toSpec, onError) {
|
|
2883
|
-
const entryFiles = await listLangchainEntryFiles(dirPath, extensions);
|
|
2884
|
-
if (entryFiles.length === 0) {
|
|
2885
|
-
if (strict) {
|
|
2886
|
-
throw new DiscoveryError(dirPath, "load", "No LangChain entry files found");
|
|
2887
|
-
}
|
|
2888
|
-
return [];
|
|
2889
|
-
}
|
|
2890
|
-
const specs = [];
|
|
2891
|
-
const useDirNameForSingle = dirName !== langchainDirName;
|
|
2892
|
-
for (const entryFile of entryFiles) {
|
|
2893
|
-
const fileManifest = { ...manifest, entryPoint: entryFile };
|
|
2894
|
-
try {
|
|
2895
|
-
const loaded = await loadLangChainTool(dirPath, fileManifest, extensions);
|
|
2896
|
-
const fileBase = path.basename(entryFile).replace(/\.[^.]+$/, "");
|
|
2897
|
-
const nameHint = entryFiles.length === 1 && useDirNameForSingle ? dirName : fileBase;
|
|
2898
|
-
specs.push(toSpec(loaded, nameHint, dirPath, namespace));
|
|
2899
|
-
} catch (error) {
|
|
2900
|
-
const err = error;
|
|
2901
|
-
if (err instanceof DiscoveryError && err.phase === "validate") {
|
|
2902
|
-
if (strict) throw err;
|
|
2903
|
-
continue;
|
|
2904
|
-
}
|
|
2905
|
-
onError?.(path.join(dirPath, entryFile), err);
|
|
2906
|
-
if (strict) throw err;
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
return specs;
|
|
2910
|
-
}
|
|
2911
|
-
function isCursorFormat(obj) {
|
|
2912
|
-
return typeof obj === "object" && obj !== null && "mcpServers" in obj && typeof obj.mcpServers === "object" && obj.mcpServers !== null;
|
|
2913
|
-
}
|
|
2914
|
-
function extractMCPConfig(parsed, toolName) {
|
|
2915
|
-
if (isCursorFormat(parsed)) {
|
|
2916
|
-
const servers = parsed.mcpServers;
|
|
2917
|
-
const keys = Object.keys(servers);
|
|
2918
|
-
if (keys.length === 0) {
|
|
2919
|
-
return {};
|
|
2920
|
-
}
|
|
2921
|
-
const name = toolName && keys.includes(toolName) ? toolName : keys[0];
|
|
2922
|
-
return servers[name];
|
|
2923
|
-
}
|
|
2924
|
-
return parsed;
|
|
2925
|
-
}
|
|
2926
|
-
async function loadMCPTool(dirPath, manifest) {
|
|
2927
|
-
const mcpPath = path.join(dirPath, manifest.entryPoint ?? "mcp.json");
|
|
2928
|
-
let raw;
|
|
2929
|
-
try {
|
|
2930
|
-
raw = await promises.readFile(mcpPath, "utf-8");
|
|
2931
|
-
} catch (err) {
|
|
2932
|
-
throw new DiscoveryError(
|
|
2933
|
-
dirPath,
|
|
2934
|
-
"load",
|
|
2935
|
-
`Failed to read MCP config: ${mcpPath}`,
|
|
2936
|
-
err
|
|
2937
|
-
);
|
|
2938
|
-
}
|
|
2939
|
-
let parsed;
|
|
2940
|
-
try {
|
|
2941
|
-
parsed = JSON.parse(raw);
|
|
2942
|
-
} catch (err) {
|
|
2943
|
-
throw new DiscoveryError(
|
|
2944
|
-
dirPath,
|
|
2945
|
-
"load",
|
|
2946
|
-
`Invalid JSON in ${mcpPath}`,
|
|
2947
|
-
err
|
|
2948
|
-
);
|
|
2949
|
-
}
|
|
2950
|
-
const baseName = manifest.name?.split("/").pop();
|
|
2951
|
-
const config = extractMCPConfig(parsed, baseName);
|
|
2952
|
-
if (!config.command && !config.url) {
|
|
2953
|
-
throw new DiscoveryError(
|
|
2954
|
-
dirPath,
|
|
2955
|
-
"validate",
|
|
2956
|
-
`mcp.json must have either "command" or "url" field`
|
|
2957
|
-
);
|
|
2958
|
-
}
|
|
2959
|
-
return { manifest, dirPath, mcpConfig: config };
|
|
2960
|
-
}
|
|
2961
|
-
|
|
2962
|
-
// src/tools/mcp/directoryApply.ts
|
|
2963
|
-
function applyLoadedToSpec(spec, loaded, _manifest, _defaultDirName, _namespace) {
|
|
2964
|
-
if (loaded.mcpConfig?.url) spec.endpoint = loaded.mcpConfig.url;
|
|
2965
|
-
spec.impl = loaded.mcpConfig;
|
|
2966
|
-
}
|
|
2967
|
-
var directoryMarker = {
|
|
2968
|
-
kind: "mcp",
|
|
2969
|
-
markerFile: "mcp.json",
|
|
2970
|
-
defaultEntryPoint: "mcp.json"
|
|
2971
|
-
};
|
|
2972
|
-
|
|
2973
|
-
// src/tools/langchain/directoryApply.ts
|
|
2974
|
-
function applyLoadedToSpec2(spec, loaded, manifest, _defaultDirName, namespace) {
|
|
2975
|
-
spec.impl = loaded.impl;
|
|
2976
|
-
if (!manifest.name && loaded.impl) {
|
|
2977
|
-
const toolName = loaded.impl.name;
|
|
2978
|
-
if (toolName) spec.name = `${namespace}/${toolName}`;
|
|
2979
|
-
}
|
|
2980
|
-
if (!manifest.description && loaded.impl) {
|
|
2981
|
-
const d = loaded.impl.description;
|
|
2982
|
-
if (d) spec.description = d;
|
|
2983
|
-
}
|
|
2984
|
-
if (!manifest.inputSchema && loaded.impl) {
|
|
2985
|
-
const schema = loaded.impl.schema;
|
|
2986
|
-
if (schema) spec.inputSchema = schema;
|
|
2987
|
-
}
|
|
2988
|
-
}
|
|
2989
|
-
|
|
2990
|
-
// src/tools/skill/directoryApply.ts
|
|
2991
|
-
function applyLoadedToSpec3(spec, loaded, manifest, defaultDirName, namespace) {
|
|
2992
|
-
const skillDef = loaded.skillDefinition;
|
|
2993
|
-
if (skillDef) {
|
|
2994
|
-
spec.name = manifest.name ?? skillDef.frontmatter.name;
|
|
2995
|
-
spec.description = skillDef.frontmatter.description;
|
|
2996
|
-
if (loaded.programKey === "default") {
|
|
2997
|
-
spec.name = `${namespace}/${defaultDirName}`;
|
|
2998
|
-
} else if (loaded.programKey) {
|
|
2999
|
-
spec.name = `${namespace}/${defaultDirName}/${loaded.programKey}`;
|
|
3000
|
-
}
|
|
3001
|
-
const impl = loaded.impl;
|
|
3002
|
-
if (impl && typeof impl === "object" && typeof impl.invoke === "function") {
|
|
3003
|
-
if (impl.description != null && impl.description !== "")
|
|
3004
|
-
spec.description = impl.description;
|
|
3005
|
-
if (impl.schema != null && typeof impl.schema === "object")
|
|
3006
|
-
spec.inputSchema = impl.schema;
|
|
3007
|
-
}
|
|
3008
|
-
spec.impl = { ...skillDef, handler: loaded.impl };
|
|
3009
|
-
} else {
|
|
3010
|
-
spec.impl = loaded.impl;
|
|
3011
|
-
}
|
|
3012
|
-
}
|
|
3013
|
-
var directoryMarker2 = {
|
|
3014
|
-
kind: "skill",
|
|
3015
|
-
markerFile: "SKILL.md",
|
|
3016
|
-
defaultEntryPoint: "handler"
|
|
3017
|
-
};
|
|
3018
|
-
|
|
3019
|
-
// src/tools/n8n/directoryApply.ts
|
|
3020
|
-
function applyLoadedToSpec4(spec, loaded, manifest, _defaultDirName, _namespace) {
|
|
3021
|
-
const workflow = loaded.workflowDef;
|
|
3022
|
-
if (workflow?.id) spec.resourceId = String(workflow.id);
|
|
3023
|
-
if (!manifest.description && workflow) {
|
|
3024
|
-
const d = workflow.description ?? workflow.meta?.description ?? (typeof workflow.name === "string" ? workflow.name : void 0);
|
|
3025
|
-
if (d) spec.description = d;
|
|
3026
|
-
}
|
|
3027
|
-
spec.impl = loaded.workflowDef;
|
|
3028
|
-
}
|
|
3029
|
-
var directoryMarker3 = {
|
|
3030
|
-
kind: "n8n",
|
|
3031
|
-
markerFile: "workflow.json",
|
|
3032
|
-
defaultEntryPoint: "workflow.json"
|
|
3033
|
-
};
|
|
3034
|
-
|
|
3035
|
-
// src/tools/discoveryFactory.ts
|
|
3036
|
-
var DiscoveryError = class extends Error {
|
|
3037
|
-
toolDir;
|
|
3038
|
-
phase;
|
|
3039
|
-
cause;
|
|
3040
|
-
constructor(toolDir, phase, message, cause) {
|
|
3041
|
-
super(`[${phase}] ${toolDir}: ${message}`);
|
|
3042
|
-
this.name = "DiscoveryError";
|
|
3043
|
-
this.toolDir = toolDir;
|
|
3044
|
-
this.phase = phase;
|
|
3045
|
-
this.cause = cause;
|
|
3046
|
-
}
|
|
3047
|
-
};
|
|
3048
|
-
var DIRECTORY_KINDS = ["mcp", "langchain", "skill", "n8n"];
|
|
3049
|
-
var DIRECTORY_DISCOVERABLE_KINDS = DIRECTORY_KINDS;
|
|
3050
|
-
var DIRECTORY_KIND_MARKERS = [
|
|
3051
|
-
directoryMarker2,
|
|
3052
|
-
directoryMarker3,
|
|
3053
|
-
directoryMarker
|
|
3054
|
-
];
|
|
3055
|
-
var DIRECTORY_LOADERS = {
|
|
3056
|
-
mcp: async (dirPath, manifest) => [await loadMCPTool(dirPath, manifest)],
|
|
3057
|
-
langchain: async (dirPath, manifest, ext) => [await loadLangChainTool(dirPath, manifest, ext)],
|
|
3058
|
-
skill: (dirPath, manifest, ext) => loadSkillTools(dirPath, manifest, ext),
|
|
3059
|
-
n8n: async (dirPath, manifest) => [await loadN8nTool(dirPath, manifest)]
|
|
3060
|
-
};
|
|
3061
|
-
function getDirectoryLoader(kind) {
|
|
3062
|
-
const loader = DIRECTORY_LOADERS[kind];
|
|
3063
|
-
if (!loader) {
|
|
3064
|
-
throw new DiscoveryError("", "manifest", `Unknown directory tool kind: "${kind}"`);
|
|
3065
|
-
}
|
|
3066
|
-
return loader;
|
|
3067
|
-
}
|
|
3068
|
-
function applyDirectoryLoadedToSpec(spec, loaded, manifest, defaultDirName, namespace) {
|
|
3069
|
-
switch (manifest.kind) {
|
|
3070
|
-
case "mcp":
|
|
3071
|
-
return applyLoadedToSpec(spec, loaded);
|
|
3072
|
-
case "langchain":
|
|
3073
|
-
return applyLoadedToSpec2(spec, loaded, manifest, defaultDirName, namespace);
|
|
3074
|
-
case "skill":
|
|
3075
|
-
return applyLoadedToSpec3(spec, loaded, manifest, defaultDirName, namespace);
|
|
3076
|
-
case "n8n":
|
|
3077
|
-
return applyLoadedToSpec4(spec, loaded, manifest);
|
|
3078
|
-
}
|
|
3079
|
-
}
|
|
3080
|
-
async function discoverTools(type, projectPath, options = {}) {
|
|
3081
|
-
const root = path__namespace.resolve(projectPath);
|
|
3082
|
-
switch (type) {
|
|
3083
|
-
case "function":
|
|
3084
|
-
return scan(root, options);
|
|
3085
|
-
case "skill":
|
|
3086
|
-
return scan2(root, options);
|
|
3087
|
-
case "n8n":
|
|
3088
|
-
return scan3(root, options);
|
|
3089
|
-
case "mcp":
|
|
3090
|
-
return scan4(root, options);
|
|
3091
|
-
case "langchain":
|
|
3092
|
-
return scan5(root, options);
|
|
3093
|
-
default: {
|
|
3094
|
-
const _ = type;
|
|
3095
|
-
return _;
|
|
3096
|
-
}
|
|
3097
|
-
}
|
|
3098
|
-
}
|
|
3099
|
-
var DEFAULT_EXTENSIONS3 = [".js", ".mjs"];
|
|
3100
|
-
var DirectoryScanner = class {
|
|
3101
|
-
roots;
|
|
3102
|
-
extensions;
|
|
3103
|
-
onError;
|
|
3104
|
-
constructor(options) {
|
|
3105
|
-
const defaultNamespace = options.namespace ?? "dir";
|
|
3106
|
-
this.roots = options.roots.map((root) => {
|
|
3107
|
-
if (typeof root === "string") {
|
|
3108
|
-
return { path: root, namespace: defaultNamespace };
|
|
3109
|
-
}
|
|
3110
|
-
return {
|
|
3111
|
-
path: root.path,
|
|
3112
|
-
namespace: root.namespace ?? defaultNamespace
|
|
3113
|
-
};
|
|
3114
|
-
});
|
|
3115
|
-
this.extensions = options.extensions ?? DEFAULT_EXTENSIONS3;
|
|
3116
|
-
this.onError = options.onError;
|
|
3117
|
-
}
|
|
3118
|
-
async scan() {
|
|
3119
|
-
const specs = [];
|
|
3120
|
-
for (const root of this.roots) {
|
|
3121
|
-
const rootSpecs = await this.scanRoot(root.path, root.namespace);
|
|
3122
|
-
specs.push(...rootSpecs);
|
|
3123
|
-
}
|
|
3124
|
-
return specs;
|
|
3125
|
-
}
|
|
3126
|
-
async scanRoot(rootPath, namespace) {
|
|
3127
|
-
return this.scanRecursive(rootPath, namespace);
|
|
3128
|
-
}
|
|
3129
|
-
async scanRecursive(dirPath, namespace) {
|
|
3130
|
-
const specs = [];
|
|
3131
|
-
let dirEntries;
|
|
3132
|
-
try {
|
|
3133
|
-
const entries = await promises.readdir(dirPath, { withFileTypes: true });
|
|
3134
|
-
dirEntries = entries.map((entry) => ({
|
|
3135
|
-
name: entry.name,
|
|
3136
|
-
isDirectory: entry.isDirectory()
|
|
3137
|
-
}));
|
|
3138
|
-
} catch (error) {
|
|
3139
|
-
this.onError?.(dirPath, error);
|
|
3140
|
-
return specs;
|
|
3141
|
-
}
|
|
3142
|
-
const dirName = path.basename(dirPath);
|
|
3143
|
-
try {
|
|
3144
|
-
const loadedSpecs = await this.loadToolDir(dirPath, dirName, namespace);
|
|
3145
|
-
if (loadedSpecs.length > 0) specs.push(...loadedSpecs);
|
|
3146
|
-
} catch (error) {
|
|
3147
|
-
this.onError?.(dirPath, error);
|
|
3148
|
-
}
|
|
3149
|
-
for (const entry of dirEntries) {
|
|
3150
|
-
if (!entry.isDirectory) continue;
|
|
3151
|
-
const childPath = path.join(dirPath, entry.name);
|
|
3152
|
-
try {
|
|
3153
|
-
const childSpecs = await this.scanRecursive(childPath, namespace);
|
|
3154
|
-
specs.push(...childSpecs);
|
|
3155
|
-
} catch (error) {
|
|
3156
|
-
this.onError?.(childPath, error);
|
|
3157
|
-
}
|
|
3158
|
-
}
|
|
3159
|
-
return specs;
|
|
3160
|
-
}
|
|
3161
|
-
async loadToolDir(dirPath, dirName, namespace) {
|
|
3162
|
-
const manifestPath = path.join(dirPath, "tool.json");
|
|
3163
|
-
let manifestRaw;
|
|
3164
|
-
try {
|
|
3165
|
-
manifestRaw = await promises.readFile(manifestPath, "utf-8");
|
|
3166
|
-
} catch {
|
|
3167
|
-
const inferred = await this.inferManifest(dirPath, dirName);
|
|
3168
|
-
if (!inferred) return [];
|
|
3169
|
-
if (inferred.kind === "langchain") {
|
|
3170
|
-
if (inferred.entryPoint) {
|
|
3171
|
-
const loaded3 = await loadLangChainTool(dirPath, inferred, this.extensions);
|
|
3172
|
-
return [this.toToolSpec(loaded3, dirName, dirPath, namespace)];
|
|
3173
|
-
}
|
|
3174
|
-
return loadLangChainToolsFromDir(
|
|
3175
|
-
dirPath,
|
|
3176
|
-
dirName,
|
|
3177
|
-
inferred,
|
|
3178
|
-
false,
|
|
3179
|
-
namespace,
|
|
3180
|
-
this.extensions,
|
|
3181
|
-
LANGCHAIN_DIR_NAME,
|
|
3182
|
-
(loaded3, nameHint, dp, ns) => this.toToolSpec(loaded3, nameHint, dp, ns),
|
|
3183
|
-
this.onError
|
|
3184
|
-
);
|
|
3185
|
-
}
|
|
3186
|
-
if (inferred.kind === "skill") {
|
|
3187
|
-
const loadedList = await loadSkillTools(dirPath, inferred, this.extensions);
|
|
3188
|
-
return loadedList.map(
|
|
3189
|
-
(loaded3) => this.toToolSpec(loaded3, dirName, dirPath, namespace)
|
|
3190
|
-
);
|
|
3191
|
-
}
|
|
3192
|
-
const loaded2 = await this.loadByKind(dirPath, inferred);
|
|
3193
|
-
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
3194
|
-
}
|
|
3195
|
-
let manifest;
|
|
3196
|
-
try {
|
|
3197
|
-
manifest = JSON.parse(manifestRaw);
|
|
3198
|
-
} catch (err) {
|
|
3199
|
-
throw new DiscoveryError(dirPath, "manifest", "Invalid JSON in tool.json", err);
|
|
3200
|
-
}
|
|
3201
|
-
if (!manifest.kind) {
|
|
3202
|
-
throw new DiscoveryError(dirPath, "manifest", `tool.json must have a "kind" field`);
|
|
3203
|
-
}
|
|
3204
|
-
if (manifest.enabled === false) return [];
|
|
3205
|
-
if (manifest.kind === "langchain") {
|
|
3206
|
-
if (manifest.entryPoint) {
|
|
3207
|
-
const loaded2 = await loadLangChainTool(dirPath, manifest, this.extensions);
|
|
3208
|
-
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
3209
|
-
}
|
|
3210
|
-
return loadLangChainToolsFromDir(
|
|
3211
|
-
dirPath,
|
|
3212
|
-
dirName,
|
|
3213
|
-
manifest,
|
|
3214
|
-
true,
|
|
3215
|
-
namespace,
|
|
3216
|
-
this.extensions,
|
|
3217
|
-
LANGCHAIN_DIR_NAME,
|
|
3218
|
-
(loaded2, nameHint, dp, ns) => this.toToolSpec(loaded2, nameHint, dp, ns),
|
|
3219
|
-
this.onError
|
|
3220
|
-
);
|
|
3221
|
-
}
|
|
3222
|
-
if (manifest.kind === "skill") {
|
|
3223
|
-
const loadedList = await loadSkillTools(dirPath, manifest, this.extensions);
|
|
3224
|
-
return loadedList.map(
|
|
3225
|
-
(loaded2) => this.toToolSpec(loaded2, dirName, dirPath, namespace)
|
|
3226
|
-
);
|
|
3227
|
-
}
|
|
3228
|
-
const loaded = await this.loadByKind(dirPath, manifest);
|
|
3229
|
-
return [this.toToolSpec(loaded, dirName, dirPath, namespace)];
|
|
3230
|
-
}
|
|
3231
|
-
async inferManifest(dirPath, dirName) {
|
|
3232
|
-
const kinds = [];
|
|
3233
|
-
for (const m of DIRECTORY_KIND_MARKERS) {
|
|
3234
|
-
if (await this.fileExists(path.join(dirPath, m.markerFile))) kinds.push(m.kind);
|
|
3235
|
-
}
|
|
3236
|
-
const isLangchainDir = dirName === LANGCHAIN_DIR_NAME;
|
|
3237
|
-
const hasLangchain = isLangchainDir ? (await listLangchainEntryFiles(dirPath, this.extensions)).length > 0 : dirName !== SKILL_DIR_NAME && await this.hasEntryPoint(dirPath, "index");
|
|
3238
|
-
if (hasLangchain) kinds.push("langchain");
|
|
3239
|
-
if (kinds.length === 0) return null;
|
|
3240
|
-
if (kinds.length > 1) {
|
|
3241
|
-
throw new DiscoveryError(
|
|
3242
|
-
dirPath,
|
|
3243
|
-
"manifest",
|
|
3244
|
-
`Ambiguous tool kind (found ${kinds.join(", ")}). Add tool.json to disambiguate.`
|
|
3245
|
-
);
|
|
3246
|
-
}
|
|
3247
|
-
const kind = kinds[0];
|
|
3248
|
-
const manifest = { kind };
|
|
3249
|
-
const marker = DIRECTORY_KIND_MARKERS.find((m) => m.kind === kind);
|
|
3250
|
-
if (marker) {
|
|
3251
|
-
manifest.entryPoint = marker.defaultEntryPoint;
|
|
3252
|
-
}
|
|
3253
|
-
if (kind === "langchain" && !isLangchainDir) manifest.entryPoint = "index";
|
|
3254
|
-
return manifest;
|
|
3255
|
-
}
|
|
3256
|
-
async fileExists(path7) {
|
|
3257
|
-
try {
|
|
3258
|
-
await promises.access(path7);
|
|
3259
|
-
return true;
|
|
3260
|
-
} catch {
|
|
3261
|
-
return false;
|
|
3262
|
-
}
|
|
3263
|
-
}
|
|
3264
|
-
async hasEntryPoint(dirPath, baseName) {
|
|
3265
|
-
try {
|
|
3266
|
-
await resolveEntryPoint(dirPath, baseName, this.extensions);
|
|
3267
|
-
return true;
|
|
3268
|
-
} catch {
|
|
3269
|
-
return false;
|
|
3270
|
-
}
|
|
3271
|
-
}
|
|
3272
|
-
async loadByKind(dirPath, manifest) {
|
|
3273
|
-
const kind = manifest.kind;
|
|
3274
|
-
const loader = getDirectoryLoader(kind);
|
|
3275
|
-
const result = await loader(dirPath, manifest, this.extensions);
|
|
3276
|
-
const list = Array.isArray(result) ? result : [result];
|
|
3277
|
-
if (list.length === 0) {
|
|
3278
|
-
throw new DiscoveryError(dirPath, "load", "No tools loaded", new Error("empty"));
|
|
3279
|
-
}
|
|
3280
|
-
return list[0];
|
|
3281
|
-
}
|
|
3282
|
-
toToolSpec(loaded, dirName, dirPath, namespace) {
|
|
3283
|
-
const { manifest } = loaded;
|
|
3284
|
-
const kindDirNames = new Set(DIRECTORY_DISCOVERABLE_KINDS);
|
|
3285
|
-
const parentName = path.basename(path.join(dirPath, ".."));
|
|
3286
|
-
const isKindDir = kindDirNames.has(dirName);
|
|
3287
|
-
const defaultDirName = isKindDir ? parentName : dirName;
|
|
3288
|
-
const inferredName = isKindDir ? `${namespace}/${defaultDirName}-${dirName}` : `${namespace}/${defaultDirName}`;
|
|
3289
|
-
const name = manifest.name ?? inferredName;
|
|
3290
|
-
const spec = this.buildBaseSpec(manifest, name, dirName);
|
|
3291
|
-
applyDirectoryLoadedToSpec(spec, loaded, manifest, defaultDirName, namespace);
|
|
3292
|
-
return spec;
|
|
3293
|
-
}
|
|
3294
|
-
buildBaseSpec(manifest, name, dirName) {
|
|
3295
|
-
return {
|
|
3296
|
-
name,
|
|
3297
|
-
version: manifest.version ?? "1.0.0",
|
|
3298
|
-
kind: manifest.kind,
|
|
3299
|
-
description: manifest.description ?? `${manifest.kind} tool: ${dirName}`,
|
|
3300
|
-
tags: manifest.tags,
|
|
3301
|
-
inputSchema: manifest.inputSchema ?? { type: "object", additionalProperties: true },
|
|
3302
|
-
outputSchema: manifest.outputSchema ?? { type: "object", additionalProperties: true },
|
|
3303
|
-
capabilities: manifest.capabilities ?? [],
|
|
3304
|
-
costHints: manifest.costHints
|
|
3305
|
-
};
|
|
3306
|
-
}
|
|
3307
|
-
};
|
|
3308
1729
|
|
|
3309
1730
|
// src/api/runtimeFromConfig.ts
|
|
3310
|
-
var requireFromPackage = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-
|
|
1731
|
+
var requireFromPackage = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-HK4GTFTQ.cjs', document.baseURI).href)));
|
|
3311
1732
|
function getProjectRequire() {
|
|
3312
1733
|
const cwd = process.cwd();
|
|
3313
1734
|
if (fs.existsSync(path.join(cwd, "package.json"))) return module$1.createRequire(path.join(cwd, "package.json"));
|
|
@@ -3501,11 +1922,11 @@ function parseNpmDescriptor(entry) {
|
|
|
3501
1922
|
}
|
|
3502
1923
|
function loadExtensionFromFileDescriptorSync(descriptor, configFilePath, stepLog) {
|
|
3503
1924
|
const entryStr = descriptor.trim();
|
|
3504
|
-
const
|
|
3505
|
-
if (!
|
|
1925
|
+
const path$1 = parseToolPath(entryStr);
|
|
1926
|
+
if (!path$1 || path$1.protocol !== "file") return null;
|
|
3506
1927
|
const localPath = path.isAbsolute(configFilePath) ? configFilePath : path.resolve(process.cwd(), configFilePath);
|
|
3507
1928
|
const configDir = path.dirname(localPath);
|
|
3508
|
-
const pathPart = `${
|
|
1929
|
+
const pathPart = `${path$1.scope}/${path$1.packageWithVersion}`;
|
|
3509
1930
|
const resolvedPath = path.resolve(configDir, pathPart);
|
|
3510
1931
|
if (!fs.existsSync(resolvedPath) || !fs.statSync(resolvedPath).isDirectory()) return null;
|
|
3511
1932
|
try {
|
|
@@ -3653,7 +2074,7 @@ async function loadLocalDirectoryForFileDescriptor(descriptor, configFilePath, s
|
|
|
3653
2074
|
if (!resolvedPath || !fs.existsSync(resolvedPath) || !fs.statSync(resolvedPath).isDirectory()) return null;
|
|
3654
2075
|
if (fs.existsSync(path.join(resolvedPath, "package.json"))) return null;
|
|
3655
2076
|
const scanErrors = [];
|
|
3656
|
-
const scanner = new DirectoryScanner({
|
|
2077
|
+
const scanner = new chunkOG5ZSXQ5_cjs.DirectoryScanner({
|
|
3657
2078
|
roots: [{ path: resolvedPath, namespace: "local" }],
|
|
3658
2079
|
onError: (toolDir, error) => scanErrors.push(`${toolDir}: ${error.message}`)
|
|
3659
2080
|
});
|
|
@@ -3697,9 +2118,9 @@ async function loadAllExtensionsFromToolYamlAsync(configFilePath, stepLog) {
|
|
|
3697
2118
|
return loaded;
|
|
3698
2119
|
}
|
|
3699
2120
|
function createRuntimeFromConfigSync(options = {}) {
|
|
3700
|
-
const registry = new
|
|
2121
|
+
const registry = new chunkPYCCJF7C_cjs.ToolRegistry();
|
|
3701
2122
|
const stepLog = options.stepLog;
|
|
3702
|
-
setSandboxValidationEnabled(options.coreTools?.enableSandboxValidation === true);
|
|
2123
|
+
chunkZDSZHEQU_cjs.setSandboxValidationEnabled(options.coreTools?.enableSandboxValidation === true);
|
|
3703
2124
|
if (options.coreTools !== void 0) {
|
|
3704
2125
|
if (options.configFilePath) {
|
|
3705
2126
|
const all = loadAllExtensionsFromToolYamlSync(options.configFilePath, stepLog);
|
|
@@ -3741,12 +2162,12 @@ function createRuntimeFromConfigSync(options = {}) {
|
|
|
3741
2162
|
return { runtime, registry };
|
|
3742
2163
|
}
|
|
3743
2164
|
async function createRuntimeFromConfig(options = {}) {
|
|
3744
|
-
setSandboxValidationEnabled(options.coreTools?.enableSandboxValidation === true);
|
|
2165
|
+
chunkZDSZHEQU_cjs.setSandboxValidationEnabled(options.coreTools?.enableSandboxValidation === true);
|
|
3745
2166
|
if (options.coreTools !== void 0 && options.configFilePath) {
|
|
3746
2167
|
const all = await loadAllExtensionsFromToolYamlAsync(options.configFilePath, options.stepLog);
|
|
3747
2168
|
if (all.length > 0) {
|
|
3748
2169
|
if (options.stepLog) options.stepLog(`Registered ${all.length} extension(s) from tool.yaml`);
|
|
3749
|
-
const registry = new
|
|
2170
|
+
const registry = new chunkPYCCJF7C_cjs.ToolRegistry();
|
|
3750
2171
|
const runtime = new PTCRuntime({ registry });
|
|
3751
2172
|
for (const ext of all) {
|
|
3752
2173
|
const before = new Set(registry.snapshot().map((s) => s.name));
|
|
@@ -3972,18 +2393,18 @@ var BodyParseError = class extends Error {
|
|
|
3972
2393
|
}
|
|
3973
2394
|
};
|
|
3974
2395
|
function parseBody(req) {
|
|
3975
|
-
return new Promise((
|
|
2396
|
+
return new Promise((resolve3, reject) => {
|
|
3976
2397
|
const chunks = [];
|
|
3977
2398
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
3978
2399
|
req.on("end", () => {
|
|
3979
2400
|
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
3980
2401
|
if (!raw.trim()) {
|
|
3981
|
-
|
|
2402
|
+
resolve3({});
|
|
3982
2403
|
return;
|
|
3983
2404
|
}
|
|
3984
2405
|
const parsed = safeParseToolArgs(raw);
|
|
3985
2406
|
if (parsed.ok) {
|
|
3986
|
-
|
|
2407
|
+
resolve3(parsed.value);
|
|
3987
2408
|
return;
|
|
3988
2409
|
}
|
|
3989
2410
|
reject(new BodyParseError("Invalid JSON body", parsed.hint));
|
|
@@ -4031,8 +2452,8 @@ function createOpenAPIHttpServer(runtime, options = {}) {
|
|
|
4031
2452
|
const ctxFactory = options.execContextFactory ?? (() => ({ ...DEFAULT_CTX }));
|
|
4032
2453
|
const server = http.createServer(async (req, res) => {
|
|
4033
2454
|
const url = req.url ?? "/";
|
|
4034
|
-
const
|
|
4035
|
-
const norm = basePath ?
|
|
2455
|
+
const path = url.split("?")[0] ?? "/";
|
|
2456
|
+
const norm = basePath ? path === basePath ? "" : path.replace(basePath, "") || "/" : path;
|
|
4036
2457
|
try {
|
|
4037
2458
|
if (req.method === "GET" && (norm === "/" || norm === "/swagger")) {
|
|
4038
2459
|
const specPath = basePath ? `${basePath}/openapi.json` : "/openapi.json";
|
|
@@ -4141,13 +2562,13 @@ function createOpenAPIHttpServer(runtime, options = {}) {
|
|
|
4141
2562
|
return server;
|
|
4142
2563
|
}
|
|
4143
2564
|
function listenOpenAPIHttpServer(server, options = {}) {
|
|
4144
|
-
return new Promise((
|
|
2565
|
+
return new Promise((resolve3, reject) => {
|
|
4145
2566
|
const port = options.port ?? 0;
|
|
4146
2567
|
const host = options.host ?? "localhost";
|
|
4147
2568
|
server.listen(port, host, () => {
|
|
4148
2569
|
const addr = server.address();
|
|
4149
2570
|
const actualPort = typeof addr === "object" && addr?.port != null ? addr.port : port;
|
|
4150
|
-
|
|
2571
|
+
resolve3({ port: actualPort, host });
|
|
4151
2572
|
});
|
|
4152
2573
|
server.on("error", reject);
|
|
4153
2574
|
});
|
|
@@ -4205,7 +2626,7 @@ async function createMcpServerWithTools(runtime, options) {
|
|
|
4205
2626
|
async (args) => {
|
|
4206
2627
|
const ctx = ctxFactory();
|
|
4207
2628
|
const result = await runtime.invoke(
|
|
4208
|
-
{ tool: spec.name, args: args ?? {}, purpose: MCP_KIND },
|
|
2629
|
+
{ tool: spec.name, args: args ?? {}, purpose: chunkOG5ZSXQ5_cjs.MCP_KIND },
|
|
4209
2630
|
ctx
|
|
4210
2631
|
);
|
|
4211
2632
|
if (result.ok) {
|
|
@@ -4269,24 +2690,24 @@ function createMCPStreamableHttpHandler(runtimeOrConfig, options = {}) {
|
|
|
4269
2690
|
})();
|
|
4270
2691
|
}
|
|
4271
2692
|
async function createMCPServerStreamableHttp(runtimeOrConfig, options = {}) {
|
|
4272
|
-
const
|
|
2693
|
+
const path = options.path ?? "/mcp";
|
|
4273
2694
|
const host = options.host ?? "127.0.0.1";
|
|
4274
2695
|
const port = options.port ?? 3e3;
|
|
4275
2696
|
const { createMcpExpressApp } = await import('@modelcontextprotocol/sdk/server/express.js');
|
|
4276
2697
|
const handler = "invoke" in runtimeOrConfig && typeof runtimeOrConfig.invoke === "function" ? createMCPStreamableHttpHandler(runtimeOrConfig, options) : await createMCPStreamableHttpHandler(runtimeOrConfig, options);
|
|
4277
2698
|
const app = createMcpExpressApp({ host });
|
|
4278
|
-
app.post(
|
|
2699
|
+
app.post(path, handler);
|
|
4279
2700
|
return {
|
|
4280
2701
|
app,
|
|
4281
|
-
path
|
|
2702
|
+
path,
|
|
4282
2703
|
async listen(listenPort, listenHost) {
|
|
4283
2704
|
const p = listenPort ?? port;
|
|
4284
2705
|
const h = listenHost ?? host;
|
|
4285
|
-
return new Promise((
|
|
2706
|
+
return new Promise((resolve3, reject) => {
|
|
4286
2707
|
const server = app.listen(p, h, () => {
|
|
4287
2708
|
const addr = server.address();
|
|
4288
2709
|
const actualPort = typeof addr === "object" && addr !== null && "port" in addr ? addr.port : p;
|
|
4289
|
-
|
|
2710
|
+
resolve3({ url: `http://${h}:${actualPort}${path}`, port: actualPort });
|
|
4290
2711
|
});
|
|
4291
2712
|
});
|
|
4292
2713
|
}
|
|
@@ -4298,18 +2719,13 @@ async function runMCPServerOverStdio(runtime, options = {}) {
|
|
|
4298
2719
|
return result;
|
|
4299
2720
|
}
|
|
4300
2721
|
|
|
4301
|
-
exports.FUNCTION_KIND = FUNCTION_KIND;
|
|
4302
|
-
exports.LANGCHAIN_KIND = LANGCHAIN_KIND;
|
|
4303
|
-
exports.N8N_KIND = N8N_KIND;
|
|
4304
2722
|
exports.PTCRuntime = PTCRuntime;
|
|
4305
|
-
exports.SKILL_KIND = SKILL_KIND;
|
|
4306
2723
|
exports.createHttpService = createHttpService;
|
|
4307
2724
|
exports.createMCPServer = createMCPServer;
|
|
4308
2725
|
exports.createMCPServerStreamableHttp = createMCPServerStreamableHttp;
|
|
4309
2726
|
exports.createMCPStreamableHttpHandler = createMCPStreamableHttpHandler;
|
|
4310
2727
|
exports.createRuntimeFromConfig = createRuntimeFromConfig;
|
|
4311
2728
|
exports.createRuntimeFromConfigSync = createRuntimeFromConfigSync;
|
|
4312
|
-
exports.discoverTools = discoverTools;
|
|
4313
2729
|
exports.expandToolDescriptorsToRegistryNames = expandToolDescriptorsToRegistryNames;
|
|
4314
2730
|
exports.fileDescriptorToPackagePrefix = fileDescriptorToPackagePrefix;
|
|
4315
2731
|
exports.findAndLoadToolConfig = findAndLoadToolConfig;
|
|
@@ -4318,11 +2734,7 @@ exports.isBarePackageDescriptor = isBarePackageDescriptor;
|
|
|
4318
2734
|
exports.loadToolConfig = loadToolConfig;
|
|
4319
2735
|
exports.npmDescriptorToPackagePrefixWithVersion = npmDescriptorToPackagePrefixWithVersion;
|
|
4320
2736
|
exports.resolveSandboxedPath = resolveSandboxedPath;
|
|
4321
|
-
exports.resolveSandboxedPath2 = resolveSandboxedPath2;
|
|
4322
2737
|
exports.resolveToolDescriptor = resolveToolDescriptor;
|
|
4323
2738
|
exports.runMCPServerOverStdio = runMCPServerOverStdio;
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
exports.setSandboxValidationEnabled = setSandboxValidationEnabled;
|
|
4327
|
-
//# sourceMappingURL=chunk-JXYANBTH.cjs.map
|
|
4328
|
-
//# sourceMappingURL=chunk-JXYANBTH.cjs.map
|
|
2739
|
+
//# sourceMappingURL=chunk-HK4GTFTQ.cjs.map
|
|
2740
|
+
//# sourceMappingURL=chunk-HK4GTFTQ.cjs.map
|