@easynet/agent-tool 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -0
- package/dist/chunk-3YLVPZRJ.cjs +32 -0
- package/dist/chunk-3YLVPZRJ.cjs.map +1 -0
- package/dist/chunk-AXUNV4MK.js +28 -0
- package/dist/chunk-AXUNV4MK.js.map +1 -0
- package/dist/chunk-BM4EVYI5.js +1069 -0
- package/dist/chunk-BM4EVYI5.js.map +1 -0
- package/dist/chunk-P3UEAZHK.cjs +171 -0
- package/dist/chunk-P3UEAZHK.cjs.map +1 -0
- package/dist/chunk-RPAMQCFH.js +167 -0
- package/dist/chunk-RPAMQCFH.js.map +1 -0
- package/dist/chunk-Z7TGIG77.cjs +1108 -0
- package/dist/chunk-Z7TGIG77.cjs.map +1 -0
- package/dist/cli.cjs +154 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +147 -0
- package/dist/cli.js.map +1 -0
- package/dist/codegen/build.d.ts +23 -0
- package/dist/codegen/build.d.ts.map +1 -0
- package/dist/codegen/generator.d.ts +15 -0
- package/dist/codegen/generator.d.ts.map +1 -0
- package/dist/codegen/index.d.ts +21 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/init.d.ts +17 -0
- package/dist/codegen/init.d.ts.map +1 -0
- package/dist/codegen/run.d.ts +19 -0
- package/dist/codegen/run.d.ts.map +1 -0
- package/dist/codegen/scan/scanN8n.d.ts +17 -0
- package/dist/codegen/scan/scanN8n.d.ts.map +1 -0
- package/dist/codegen/scan/scanSkill.d.ts +17 -0
- package/dist/codegen/scan/scanSkill.d.ts.map +1 -0
- package/dist/codegen/scan/scanTools.d.ts +31 -0
- package/dist/codegen/scan/scanTools.d.ts.map +1 -0
- package/dist/codegen/scan/scanner.d.ts +26 -0
- package/dist/codegen/scan/scanner.d.ts.map +1 -0
- package/dist/codegen/scan/schemaFromTs.d.ts +16 -0
- package/dist/codegen/scan/schemaFromTs.d.ts.map +1 -0
- package/dist/codegen/types.d.ts +81 -0
- package/dist/codegen/types.d.ts.map +1 -0
- package/dist/core.cjs +20 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -0
- package/dist/discovery/MCPProcessManager.d.ts +57 -0
- package/dist/discovery/MCPProcessManager.d.ts.map +1 -0
- package/dist/discovery/errors.d.ts +13 -0
- package/dist/discovery/errors.d.ts.map +1 -0
- package/dist/discovery/load/LangChainLoader.d.ts +7 -0
- package/dist/discovery/load/LangChainLoader.d.ts.map +1 -0
- package/dist/discovery/load/MCPLoader.d.ts +8 -0
- package/dist/discovery/load/MCPLoader.d.ts.map +1 -0
- package/dist/discovery/load/N8nLoader.d.ts +25 -0
- package/dist/discovery/load/N8nLoader.d.ts.map +1 -0
- package/dist/discovery/load/SkillLoader.d.ts +20 -0
- package/dist/discovery/load/SkillLoader.d.ts.map +1 -0
- package/dist/discovery/load/SkillManifest.d.ts +79 -0
- package/dist/discovery/load/SkillManifest.d.ts.map +1 -0
- package/dist/discovery/load/SkillMdParser.d.ts +31 -0
- package/dist/discovery/load/SkillMdParser.d.ts.map +1 -0
- package/dist/discovery/load/index.d.ts +6 -0
- package/dist/discovery/load/index.d.ts.map +1 -0
- package/dist/discovery/load/resolveEntry.d.ts +7 -0
- package/dist/discovery/load/resolveEntry.d.ts.map +1 -0
- package/dist/discovery/scan/DirectoryScanner.d.ts +37 -0
- package/dist/discovery/scan/DirectoryScanner.d.ts.map +1 -0
- package/dist/discovery/scan/scanUtil.d.ts +16 -0
- package/dist/discovery/scan/scanUtil.d.ts.map +1 -0
- package/dist/discovery/types.d.ts +99 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/index.cjs +3014 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2778 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/AgentLLMAdapter.d.ts +27 -0
- package/dist/llm/AgentLLMAdapter.d.ts.map +1 -0
- package/dist/llm/LangChainToolsHub.d.ts +31 -0
- package/dist/llm/LangChainToolsHub.d.ts.map +1 -0
- package/dist/llm/OpenAICompatibleClient.d.ts +64 -0
- package/dist/llm/OpenAICompatibleClient.d.ts.map +1 -0
- package/dist/llm/ReActAgent.d.ts +35 -0
- package/dist/llm/ReActAgent.d.ts.map +1 -0
- package/dist/llm-export.cjs +20 -0
- package/dist/llm-export.cjs.map +1 -0
- package/dist/llm-export.d.ts +9 -0
- package/dist/llm-export.d.ts.map +1 -0
- package/dist/llm-export.js +3 -0
- package/dist/llm-export.js.map +1 -0
- package/dist/mcp/MCPClientAdapter.d.ts +34 -0
- package/dist/mcp/MCPClientAdapter.d.ts.map +1 -0
- package/dist/mcp/connectMCP.d.ts +47 -0
- package/dist/mcp/connectMCP.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +10 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/registerMCPTools.d.ts +24 -0
- package/dist/mcp/registerMCPTools.d.ts.map +1 -0
- package/dist/observability/EventLog.d.ts +60 -0
- package/dist/observability/EventLog.d.ts.map +1 -0
- package/dist/observability/Logger.d.ts +33 -0
- package/dist/observability/Logger.d.ts.map +1 -0
- package/dist/observability/Metrics.d.ts +70 -0
- package/dist/observability/Metrics.d.ts.map +1 -0
- package/dist/observability/Tracing.d.ts +69 -0
- package/dist/observability/Tracing.d.ts.map +1 -0
- package/dist/registry/ToolRegistry.d.ts +68 -0
- package/dist/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/report/AgentReportGenerator.d.ts +53 -0
- package/dist/report/AgentReportGenerator.d.ts.map +1 -0
- package/dist/report/agent-report-template.html +362 -0
- package/dist/report/index.d.ts +3 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/types.d.ts +101 -0
- package/dist/report/types.d.ts.map +1 -0
- package/dist/runAgent.d.ts +37 -0
- package/dist/runAgent.d.ts.map +1 -0
- package/dist/runtime/Budget.d.ts +63 -0
- package/dist/runtime/Budget.d.ts.map +1 -0
- package/dist/runtime/Evidence.d.ts +19 -0
- package/dist/runtime/Evidence.d.ts.map +1 -0
- package/dist/runtime/PTCRuntime.d.ts +115 -0
- package/dist/runtime/PTCRuntime.d.ts.map +1 -0
- package/dist/runtime/PTCRuntimeObservability.d.ts +26 -0
- package/dist/runtime/PTCRuntimeObservability.d.ts.map +1 -0
- package/dist/runtime/PTCRuntimePipeline.d.ts +62 -0
- package/dist/runtime/PTCRuntimePipeline.d.ts.map +1 -0
- package/dist/runtime/PolicyEngine.d.ts +67 -0
- package/dist/runtime/PolicyEngine.d.ts.map +1 -0
- package/dist/runtime/Retry.d.ts +33 -0
- package/dist/runtime/Retry.d.ts.map +1 -0
- package/dist/runtime/SchemaValidator.d.ts +42 -0
- package/dist/runtime/SchemaValidator.d.ts.map +1 -0
- package/dist/templates/mcp-server.js +48 -0
- package/dist/templates/n8n-invoker.js +11 -0
- package/dist/templates/skill-invoker.js +11 -0
- package/dist/templates/tool-index.js +9 -0
- package/dist/toolDescriptor.d.ts +38 -0
- package/dist/toolDescriptor.d.ts.map +1 -0
- package/dist/types/Events.d.ts +99 -0
- package/dist/types/Events.d.ts.map +1 -0
- package/dist/types/ToolIntent.d.ts +40 -0
- package/dist/types/ToolIntent.d.ts.map +1 -0
- package/dist/types/ToolResult.d.ts +30 -0
- package/dist/types/ToolResult.d.ts.map +1 -0
- package/dist/types/ToolSpec.d.ts +99 -0
- package/dist/types/ToolSpec.d.ts.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/extensions/examples/README.md +40 -0
- package/extensions/examples/scripts/agent-tool-react-stock.mjs +30 -0
- package/extensions/examples/tools/instruction-only/skill/SKILL.md +26 -0
- package/extensions/examples/tools/web-search/mcp/mcp.json +8 -0
- package/package.json +122 -0
|
@@ -0,0 +1,1108 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs3 = require('fs/promises');
|
|
4
|
+
var path5 = require('path');
|
|
5
|
+
var fs2 = require('fs');
|
|
6
|
+
var ts2 = require('typescript');
|
|
7
|
+
var yaml = require('js-yaml');
|
|
8
|
+
var url = require('url');
|
|
9
|
+
var child_process = require('child_process');
|
|
10
|
+
|
|
11
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
|
|
14
|
+
function _interopNamespace(e) {
|
|
15
|
+
if (e && e.__esModule) return e;
|
|
16
|
+
var n = Object.create(null);
|
|
17
|
+
if (e) {
|
|
18
|
+
Object.keys(e).forEach(function (k) {
|
|
19
|
+
if (k !== 'default') {
|
|
20
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
21
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () { return e[k]; }
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
n.default = e;
|
|
29
|
+
return Object.freeze(n);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
|
|
33
|
+
var path5__namespace = /*#__PURE__*/_interopNamespace(path5);
|
|
34
|
+
var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
|
|
35
|
+
var ts2__namespace = /*#__PURE__*/_interopNamespace(ts2);
|
|
36
|
+
var yaml__default = /*#__PURE__*/_interopDefault(yaml);
|
|
37
|
+
|
|
38
|
+
// src/codegen/init.ts
|
|
39
|
+
var TEMPLATES = {
|
|
40
|
+
"package.json": `{
|
|
41
|
+
"name": "my-mcp-tools",
|
|
42
|
+
"version": "1.0.0",
|
|
43
|
+
"private": true,
|
|
44
|
+
"type": "module",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "node build.mjs",
|
|
47
|
+
"start": "node start.mjs"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@easynet/agent-tool": "latest"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`,
|
|
54
|
+
"build.mjs": `import { buildMcpPackage } from "@easynet/agent-tool";
|
|
55
|
+
|
|
56
|
+
const result = await buildMcpPackage({ outDir: "dist" });
|
|
57
|
+
console.log("Built", result.toolCount, "tool(s) ->", result.outDir);
|
|
58
|
+
`,
|
|
59
|
+
"start.mjs": `import { runMcpServer } from "@easynet/agent-tool";
|
|
60
|
+
|
|
61
|
+
const { process: child } = await runMcpServer({ path: "./dist" });
|
|
62
|
+
child.stdin?.pipe(process.stdin);
|
|
63
|
+
child.stdout?.pipe(process.stdout);
|
|
64
|
+
child.stderr?.pipe(process.stderr);
|
|
65
|
+
process.stdin?.ref();
|
|
66
|
+
child.on("close", (code) => process.exit(code ?? 0));
|
|
67
|
+
`,
|
|
68
|
+
"tsconfig.json": `{
|
|
69
|
+
"compilerOptions": {
|
|
70
|
+
"target": "ES2022",
|
|
71
|
+
"module": "ESNext",
|
|
72
|
+
"strict": true,
|
|
73
|
+
"skipLibCheck": true,
|
|
74
|
+
"noEmit": true
|
|
75
|
+
},
|
|
76
|
+
"include": ["src/**/*.ts"]
|
|
77
|
+
}
|
|
78
|
+
`,
|
|
79
|
+
"src/tools/example.ts": `/**
|
|
80
|
+
* Add two numbers.
|
|
81
|
+
* @tool
|
|
82
|
+
*/
|
|
83
|
+
export async function add(a: number, b: number): Promise<number> {
|
|
84
|
+
return a + b;
|
|
85
|
+
}
|
|
86
|
+
`,
|
|
87
|
+
"skills/hello-skill/SKILL.md": `---
|
|
88
|
+
name: hello-skill
|
|
89
|
+
description: Say hello with a name.
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
# Hello Skill
|
|
93
|
+
|
|
94
|
+
Returns a greeting for the given name.
|
|
95
|
+
`,
|
|
96
|
+
"skills/hello-skill/handler.js": `export default async function handler(args, ctx) {
|
|
97
|
+
const name = args?.name ?? "World";
|
|
98
|
+
return { message: \`Hello, \${name}!\` };
|
|
99
|
+
}
|
|
100
|
+
`,
|
|
101
|
+
"README.md": `# MCP Tool Project
|
|
102
|
+
|
|
103
|
+
Scaffolded by \`agent-tool init\`. Workflow:
|
|
104
|
+
|
|
105
|
+
1. **init** \u2014 create project template (you are here)
|
|
106
|
+
2. **npm install** \u2014 install dependencies
|
|
107
|
+
3. **npm run build** \u2014 generate MCP package under \`dist/\`
|
|
108
|
+
4. **npm start** \u2014 start the MCP server for testing
|
|
109
|
+
|
|
110
|
+
## Quick start
|
|
111
|
+
|
|
112
|
+
\`\`\`bash
|
|
113
|
+
npm install
|
|
114
|
+
npm run build
|
|
115
|
+
npm start
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
Edit \`src/tools/*.ts\` (add \`@tool\` JSDoc) and/or \`skills/*/SKILL.md\`, then \`npm run build\` again.
|
|
119
|
+
`
|
|
120
|
+
};
|
|
121
|
+
async function initProject(options = {}) {
|
|
122
|
+
const targetPath = path5__namespace.resolve(options.targetPath ?? process.cwd());
|
|
123
|
+
const filesCreated = [];
|
|
124
|
+
await fs3__namespace.mkdir(targetPath, { recursive: true });
|
|
125
|
+
for (const [relPath, content] of Object.entries(TEMPLATES)) {
|
|
126
|
+
const fullPath = path5__namespace.join(targetPath, relPath);
|
|
127
|
+
await fs3__namespace.mkdir(path5__namespace.dirname(fullPath), { recursive: true });
|
|
128
|
+
try {
|
|
129
|
+
await fs3__namespace.access(fullPath);
|
|
130
|
+
if (relPath === "package.json") continue;
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
await fs3__namespace.writeFile(fullPath, content, "utf8");
|
|
134
|
+
filesCreated.push(relPath);
|
|
135
|
+
}
|
|
136
|
+
return { targetPath, filesCreated };
|
|
137
|
+
}
|
|
138
|
+
async function findDirsContainingFile(rootPath, fileName) {
|
|
139
|
+
const found = [];
|
|
140
|
+
await collectDirsWithFile(rootPath, fileName, found);
|
|
141
|
+
return found;
|
|
142
|
+
}
|
|
143
|
+
async function collectDirsWithFile(dir, fileName, found) {
|
|
144
|
+
let entries;
|
|
145
|
+
try {
|
|
146
|
+
const e = await fs3.readdir(dir, { withFileTypes: true });
|
|
147
|
+
entries = e.map((x) => ({
|
|
148
|
+
name: x.name,
|
|
149
|
+
isDirectory: x.isDirectory(),
|
|
150
|
+
isFile: x.isFile()
|
|
151
|
+
}));
|
|
152
|
+
} catch {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
if (entries.some((x) => x.isFile && x.name === fileName)) {
|
|
156
|
+
found.push(dir);
|
|
157
|
+
}
|
|
158
|
+
for (const entry of entries) {
|
|
159
|
+
if (!entry.isDirectory || entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
await collectDirsWithFile(path5.join(dir, entry.name), fileName, found);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function pathToToolName(sourcePath, programName) {
|
|
166
|
+
const normalized = sourcePath.replace(/\\/g, "/").replace(/\.(ts|tsx|js|mjs|json)$/i, "");
|
|
167
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
168
|
+
if (segments.length === 0) return programName;
|
|
169
|
+
const pathPart = segments.join(".");
|
|
170
|
+
return `${pathPart}.${programName}`;
|
|
171
|
+
}
|
|
172
|
+
function buildOutputSchemaFromReturnType(node, typeChecker, onWarn) {
|
|
173
|
+
const sig = typeChecker.getSignatureFromDeclaration(node);
|
|
174
|
+
if (!sig) {
|
|
175
|
+
onWarn?.("Could not get signature for return type, using object");
|
|
176
|
+
return { type: "object", additionalProperties: true };
|
|
177
|
+
}
|
|
178
|
+
let returnType = typeChecker.getReturnTypeOfSignature(sig);
|
|
179
|
+
if (returnType.getSymbol?.()?.getName() === "Promise") {
|
|
180
|
+
const typeArgs = returnType.typeArguments;
|
|
181
|
+
if (typeArgs?.[0]) returnType = typeArgs[0];
|
|
182
|
+
}
|
|
183
|
+
const schema = typeToJsonSchema(returnType, typeChecker, onWarn);
|
|
184
|
+
const hasProps = typeof schema === "object" && schema.type === "object" && Object.keys(schema.properties ?? {}).length > 0;
|
|
185
|
+
return hasProps ? schema : { type: "object", additionalProperties: true };
|
|
186
|
+
}
|
|
187
|
+
function buildInputSchemaFromParams(node, typeChecker, onWarn) {
|
|
188
|
+
const properties = {};
|
|
189
|
+
const required = [];
|
|
190
|
+
if (!node.parameters.length) {
|
|
191
|
+
return { schema: { type: "object", properties: {} }, required: [] };
|
|
192
|
+
}
|
|
193
|
+
for (const param of node.parameters) {
|
|
194
|
+
const name = param.name.getText();
|
|
195
|
+
if (name.startsWith("_") && name.length <= 2) continue;
|
|
196
|
+
const sym = param.symbol;
|
|
197
|
+
const paramType = sym ? typeChecker.getTypeOfSymbolAtLocation(sym, param) : typeChecker.getTypeAtLocation(param);
|
|
198
|
+
const isOptional = !!param.questionToken || param.initializer !== void 0;
|
|
199
|
+
const propSchema = typeToJsonSchema(paramType, typeChecker, onWarn);
|
|
200
|
+
properties[name] = propSchema;
|
|
201
|
+
if (!isOptional) required.push(name);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
schema: {
|
|
205
|
+
type: "object",
|
|
206
|
+
properties,
|
|
207
|
+
...required.length > 0 ? { required } : {}
|
|
208
|
+
},
|
|
209
|
+
required
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function typeToJsonSchema(type, typeChecker, onWarn) {
|
|
213
|
+
const flags = type.flags;
|
|
214
|
+
if (flags & ts2__namespace.TypeFlags.String) return { type: "string" };
|
|
215
|
+
if (flags & ts2__namespace.TypeFlags.Number) return { type: "number" };
|
|
216
|
+
if (flags & ts2__namespace.TypeFlags.Boolean) return { type: "boolean" };
|
|
217
|
+
if (flags & ts2__namespace.TypeFlags.Null) return { type: "null" };
|
|
218
|
+
if (flags & ts2__namespace.TypeFlags.Undefined || flags & ts2__namespace.TypeFlags.Void) return {};
|
|
219
|
+
if (flags & ts2__namespace.TypeFlags.Any || flags & ts2__namespace.TypeFlags.Unknown) {
|
|
220
|
+
onWarn?.(`Unsupported type: any/unknown, using empty schema`);
|
|
221
|
+
return {};
|
|
222
|
+
}
|
|
223
|
+
if (type.isUnion?.()) {
|
|
224
|
+
const union = type;
|
|
225
|
+
const types = union.types;
|
|
226
|
+
const withoutUndef = types.filter(
|
|
227
|
+
(t) => !(t.flags & ts2__namespace.TypeFlags.Undefined) && !(t.flags & ts2__namespace.TypeFlags.Void)
|
|
228
|
+
);
|
|
229
|
+
if (withoutUndef.length === 1) return typeToJsonSchema(withoutUndef[0], typeChecker, onWarn);
|
|
230
|
+
if (withoutUndef.length === 0) return {};
|
|
231
|
+
}
|
|
232
|
+
if (typeChecker.isArrayType(type)) {
|
|
233
|
+
const typeRef = type;
|
|
234
|
+
const typeArgs = typeRef.typeArguments;
|
|
235
|
+
const itemType = typeArgs?.[0];
|
|
236
|
+
const items = itemType ? typeToJsonSchema(itemType, typeChecker, onWarn) : {};
|
|
237
|
+
return { type: "array", items: Object.keys(items).length ? items : {} };
|
|
238
|
+
}
|
|
239
|
+
const str = typeChecker.typeToString(type);
|
|
240
|
+
if (str === "string") return { type: "string" };
|
|
241
|
+
if (str === "number") return { type: "number" };
|
|
242
|
+
if (str === "boolean") return { type: "boolean" };
|
|
243
|
+
if (str.endsWith("[]")) {
|
|
244
|
+
const inner = str.slice(0, -2).trim();
|
|
245
|
+
const itemType = inner === "string" ? { type: "string" } : inner === "number" ? { type: "number" } : {};
|
|
246
|
+
return { type: "array", items: itemType };
|
|
247
|
+
}
|
|
248
|
+
if (type.getProperties && type.getProperties().length >= 0) {
|
|
249
|
+
const props = type.getProperties();
|
|
250
|
+
const properties = {};
|
|
251
|
+
const required = [];
|
|
252
|
+
for (const p of props) {
|
|
253
|
+
const decl = p.valueDeclaration;
|
|
254
|
+
const propType = decl ? typeChecker.getTypeAtLocation(decl) : typeChecker.getTypeOfSymbolAtLocation(p, p.valueDeclaration);
|
|
255
|
+
const optional = decl && ts2__namespace.isPropertySignature(decl) ? !!decl.questionToken : false;
|
|
256
|
+
properties[p.name] = typeToJsonSchema(propType, typeChecker, onWarn);
|
|
257
|
+
if (!optional) required.push(p.name);
|
|
258
|
+
}
|
|
259
|
+
return { type: "object", properties, ...required.length ? { required } : {} };
|
|
260
|
+
}
|
|
261
|
+
onWarn?.(`Unsupported type: ${str}, using object`);
|
|
262
|
+
return { type: "object" };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/codegen/scan/scanner.ts
|
|
266
|
+
var TOOL_TAG = "@tool";
|
|
267
|
+
var EFFECT_VALUES = ["none", "local_write", "external_write", "destructive"];
|
|
268
|
+
function scanForTools(options) {
|
|
269
|
+
const projectPath = path5__namespace.resolve(options.projectPath);
|
|
270
|
+
const tsconfigPath = options.tsconfigPath ?? path5__namespace.join(projectPath, "tsconfig.json");
|
|
271
|
+
const include = options.include ?? ["**/*.ts"];
|
|
272
|
+
const errors = [];
|
|
273
|
+
const warnings = [];
|
|
274
|
+
let config;
|
|
275
|
+
let configPathResolved = path5__namespace.resolve(projectPath, tsconfigPath);
|
|
276
|
+
if (!fs2__namespace.existsSync(configPathResolved)) {
|
|
277
|
+
configPathResolved = path5__namespace.join(projectPath, "tsconfig.json");
|
|
278
|
+
}
|
|
279
|
+
if (fs2__namespace.existsSync(configPathResolved)) {
|
|
280
|
+
const configFile = ts2__namespace.readConfigFile(configPathResolved, ts2__namespace.sys.readFile);
|
|
281
|
+
if (configFile.error) {
|
|
282
|
+
errors.push({ file: configPathResolved, message: String(configFile.error.messageText) });
|
|
283
|
+
return { specs: [], errors, warnings };
|
|
284
|
+
}
|
|
285
|
+
const parsed = ts2__namespace.parseJsonConfigFileContent(
|
|
286
|
+
configFile.config,
|
|
287
|
+
ts2__namespace.sys,
|
|
288
|
+
path5__namespace.dirname(configPathResolved)
|
|
289
|
+
);
|
|
290
|
+
if (parsed.errors.length) {
|
|
291
|
+
for (const e of parsed.errors) {
|
|
292
|
+
errors.push({ file: e.file?.fileName ?? "tsconfig", message: String(e.messageText) });
|
|
293
|
+
}
|
|
294
|
+
return { specs: [], errors, warnings };
|
|
295
|
+
}
|
|
296
|
+
config = parsed;
|
|
297
|
+
} else {
|
|
298
|
+
config = {
|
|
299
|
+
options: {
|
|
300
|
+
target: ts2__namespace.ScriptTarget.ES2022,
|
|
301
|
+
module: ts2__namespace.ModuleKind.ESNext,
|
|
302
|
+
moduleResolution: ts2__namespace.ModuleResolutionKind.NodeNext,
|
|
303
|
+
strict: true,
|
|
304
|
+
skipLibCheck: true,
|
|
305
|
+
noEmit: true
|
|
306
|
+
},
|
|
307
|
+
fileNames: resolveGlob(projectPath, include),
|
|
308
|
+
errors: []
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const program = ts2__namespace.createProgram(config.fileNames, config.options);
|
|
312
|
+
const typeChecker = program.getTypeChecker();
|
|
313
|
+
const specs = [];
|
|
314
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
315
|
+
const fileName = sourceFile.fileName;
|
|
316
|
+
if (fileName.includes("node_modules") || fileName.endsWith(".d.ts")) continue;
|
|
317
|
+
if (!config.fileNames.some((f) => path5__namespace.resolve(f) === path5__namespace.resolve(fileName))) continue;
|
|
318
|
+
ts2__namespace.forEachChild(sourceFile, (node) => {
|
|
319
|
+
const decl = getExportedFunctionDeclaration(node);
|
|
320
|
+
if (!decl) return;
|
|
321
|
+
const func = decl.func;
|
|
322
|
+
const name = decl.name;
|
|
323
|
+
if (!name) return;
|
|
324
|
+
const host = getJSDocHost(func);
|
|
325
|
+
if (!hasToolTag(host)) return;
|
|
326
|
+
const jsDoc = getJSDocComments(host);
|
|
327
|
+
const description = getDescription(jsDoc);
|
|
328
|
+
if (!description) {
|
|
329
|
+
warnings.push({ file: fileName, message: `Tool ${name}: missing description, using humanized name` });
|
|
330
|
+
}
|
|
331
|
+
const sideEffect = getEffect(host);
|
|
332
|
+
const onWarn = (msg) => warnings.push({ file: fileName, message: `${name}: ${msg}` });
|
|
333
|
+
const { schema } = buildInputSchemaFromParams(func, typeChecker, onWarn);
|
|
334
|
+
const inputSchema = Object.keys(schema.properties ?? {}).length > 0 ? schema : { type: "object", properties: {} };
|
|
335
|
+
const outputSchema = buildOutputSchemaFromReturnType(func, typeChecker, onWarn);
|
|
336
|
+
const sourcePath = path5__namespace.relative(projectPath, fileName) || path5__namespace.basename(fileName);
|
|
337
|
+
const toolName = pathToToolName(sourcePath, name);
|
|
338
|
+
specs.push({
|
|
339
|
+
kind: "function",
|
|
340
|
+
name: toolName,
|
|
341
|
+
description: description || humanize(name),
|
|
342
|
+
inputSchema,
|
|
343
|
+
outputSchema,
|
|
344
|
+
_meta: { hitl: { sideEffect } },
|
|
345
|
+
sourcePath,
|
|
346
|
+
exportName: name
|
|
347
|
+
});
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return { specs, errors, warnings };
|
|
351
|
+
}
|
|
352
|
+
function resolveGlob(projectPath, patterns) {
|
|
353
|
+
const result = [];
|
|
354
|
+
const seen = /* @__PURE__ */ new Set();
|
|
355
|
+
const add = (f) => {
|
|
356
|
+
const abs = path5__namespace.resolve(f);
|
|
357
|
+
if (f.endsWith(".ts") && !f.endsWith(".d.ts") && !seen.has(abs)) {
|
|
358
|
+
seen.add(abs);
|
|
359
|
+
result.push(abs);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
for (const p of patterns) {
|
|
363
|
+
const full = path5__namespace.join(projectPath, p);
|
|
364
|
+
if (full.includes("*")) {
|
|
365
|
+
const baseDir = full.replace(/\*\*\/.*$/, "").replace(/\*.*$/, "").replace(/\/?$/, "") || ".";
|
|
366
|
+
const dir = path5__namespace.resolve(projectPath, baseDir);
|
|
367
|
+
if (fs2__namespace.existsSync(dir)) walk(dir, add);
|
|
368
|
+
} else {
|
|
369
|
+
const resolved = path5__namespace.resolve(projectPath, full);
|
|
370
|
+
if (fs2__namespace.existsSync(resolved)) {
|
|
371
|
+
if (fs2__namespace.statSync(resolved).isFile()) add(resolved);
|
|
372
|
+
else walk(resolved, add);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (result.length > 0) return result;
|
|
377
|
+
const srcDir = path5__namespace.join(projectPath, "src");
|
|
378
|
+
if (fs2__namespace.existsSync(srcDir)) return walkCollect(srcDir);
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
function walkCollect(dir) {
|
|
382
|
+
const out = [];
|
|
383
|
+
walk(dir, (fullPath) => {
|
|
384
|
+
if (fullPath.endsWith(".ts") && !fullPath.endsWith(".d.ts")) out.push(path5__namespace.resolve(fullPath));
|
|
385
|
+
});
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "generated", "dist"]);
|
|
389
|
+
function walk(dir, visit) {
|
|
390
|
+
try {
|
|
391
|
+
const entries = fs2__namespace.readdirSync(dir, { withFileTypes: true });
|
|
392
|
+
for (const e of entries) {
|
|
393
|
+
const full = path5__namespace.join(dir, e.name);
|
|
394
|
+
if (e.isDirectory() && !SKIP_DIRS.has(e.name)) walk(full, visit);
|
|
395
|
+
else if (e.isFile()) visit(full);
|
|
396
|
+
}
|
|
397
|
+
} catch {
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function getExportedFunctionDeclaration(node, _sourceFile) {
|
|
401
|
+
if (ts2__namespace.isFunctionDeclaration(node) && node.name) {
|
|
402
|
+
const exported = (ts2__namespace.getModifiers(node) ?? []).some((m) => m.kind === ts2__namespace.SyntaxKind.ExportKeyword);
|
|
403
|
+
if (exported) return { func: node, name: node.name.getText() };
|
|
404
|
+
return null;
|
|
405
|
+
}
|
|
406
|
+
if (ts2__namespace.isVariableStatement(node)) {
|
|
407
|
+
const exported = (ts2__namespace.getModifiers(node) ?? []).some((m) => m.kind === ts2__namespace.SyntaxKind.ExportKeyword);
|
|
408
|
+
if (!exported) return null;
|
|
409
|
+
for (const decl of node.declarationList.declarations) {
|
|
410
|
+
const init = decl.initializer;
|
|
411
|
+
if (init && ts2__namespace.isArrowFunction(init)) {
|
|
412
|
+
const name = decl.name.getText();
|
|
413
|
+
return { func: init, name };
|
|
414
|
+
}
|
|
415
|
+
if (init && ts2__namespace.isFunctionExpression(init)) {
|
|
416
|
+
const name = decl.name.getText();
|
|
417
|
+
return { func: init, name };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return null;
|
|
422
|
+
}
|
|
423
|
+
function getJSDocHost(node) {
|
|
424
|
+
const parent = node.parent;
|
|
425
|
+
if (ts2__namespace.isVariableDeclaration(parent)) {
|
|
426
|
+
const gp = parent.parent;
|
|
427
|
+
if (ts2__namespace.isVariableDeclarationList(gp) && gp.parent && ts2__namespace.isVariableStatement(gp.parent)) return gp.parent;
|
|
428
|
+
}
|
|
429
|
+
return node;
|
|
430
|
+
}
|
|
431
|
+
function getJSDocComments(host) {
|
|
432
|
+
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
433
|
+
return all.filter((t) => ts2__namespace.isJSDoc(t));
|
|
434
|
+
}
|
|
435
|
+
function hasToolTag(host) {
|
|
436
|
+
const tags = ts2__namespace.getJSDocTags(host);
|
|
437
|
+
for (const tag of tags) {
|
|
438
|
+
const name = tag.tagName?.getText() ?? "";
|
|
439
|
+
if (name === "tool") return true;
|
|
440
|
+
}
|
|
441
|
+
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
442
|
+
for (const t of all) {
|
|
443
|
+
if (ts2__namespace.isJSDoc(t)) {
|
|
444
|
+
const full = t.getFullText();
|
|
445
|
+
if (full.includes(TOOL_TAG)) return true;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
function getDescription(jsDocs, fallbackName) {
|
|
451
|
+
for (const doc of jsDocs) {
|
|
452
|
+
const comment = doc.comment;
|
|
453
|
+
if (typeof comment === "string") {
|
|
454
|
+
const first = comment.split(/\n/)[0]?.trim() ?? "";
|
|
455
|
+
if (first && !first.startsWith("@")) return first;
|
|
456
|
+
}
|
|
457
|
+
if (Array.isArray(comment)) {
|
|
458
|
+
const first = comment[0];
|
|
459
|
+
if (first && typeof first === "object" && "text" in first) {
|
|
460
|
+
const t = first.text.trim();
|
|
461
|
+
if (t && !t.startsWith("@")) return t;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
const full = doc.getFullText();
|
|
465
|
+
const match = full.match(/\*\s*@tool\s+(.+?)(?=\n|$|\*\/)/s);
|
|
466
|
+
if (match?.[1]) return match[1].trim();
|
|
467
|
+
}
|
|
468
|
+
return "";
|
|
469
|
+
}
|
|
470
|
+
function getEffect(host) {
|
|
471
|
+
const tags = ts2__namespace.getJSDocTags(host);
|
|
472
|
+
for (const tag of tags) {
|
|
473
|
+
const name = tag.tagName?.getText() ?? "";
|
|
474
|
+
if (name === "effect") {
|
|
475
|
+
const comment = tag.comment;
|
|
476
|
+
const v = (typeof comment === "string" ? comment : "").trim().toLowerCase();
|
|
477
|
+
if (EFFECT_VALUES.includes(v)) return v;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
const all = ts2__namespace.getJSDocCommentsAndTags(host);
|
|
481
|
+
for (const t of all) {
|
|
482
|
+
if (ts2__namespace.isJSDoc(t)) {
|
|
483
|
+
const full = t.getFullText();
|
|
484
|
+
const match = full.match(/\*\s*@effect\s+(\w+)/);
|
|
485
|
+
if (match && EFFECT_VALUES.includes(match[1])) return match[1];
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return "none";
|
|
489
|
+
}
|
|
490
|
+
function humanize(name) {
|
|
491
|
+
return name.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// src/discovery/load/SkillManifest.ts
|
|
495
|
+
var SkillManifestError = class extends Error {
|
|
496
|
+
constructor(path8, field, message) {
|
|
497
|
+
super(`SKILL.md error in ${path8}: ${message}`);
|
|
498
|
+
this.path = path8;
|
|
499
|
+
this.field = field;
|
|
500
|
+
this.name = "SkillManifestError";
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
var NAME_PATTERN = /^[a-z0-9-]+$/;
|
|
504
|
+
var NAME_MAX_LENGTH = 64;
|
|
505
|
+
var DESCRIPTION_MAX_LENGTH = 1024;
|
|
506
|
+
var COMPATIBILITY_MAX_LENGTH = 500;
|
|
507
|
+
var RESERVED_WORDS = ["anthropic", "claude"];
|
|
508
|
+
var XML_TAG_PATTERN = /<\/?[a-zA-Z][^>]*>/;
|
|
509
|
+
function validateFrontmatter(fm, filePath) {
|
|
510
|
+
if (!fm.name || typeof fm.name !== "string") {
|
|
511
|
+
throw new SkillManifestError(filePath, "name", "name is required");
|
|
512
|
+
}
|
|
513
|
+
if (fm.name.length > NAME_MAX_LENGTH) {
|
|
514
|
+
throw new SkillManifestError(
|
|
515
|
+
filePath,
|
|
516
|
+
"name",
|
|
517
|
+
`name must be at most ${NAME_MAX_LENGTH} characters (got ${fm.name.length})`
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
if (!NAME_PATTERN.test(fm.name)) {
|
|
521
|
+
throw new SkillManifestError(
|
|
522
|
+
filePath,
|
|
523
|
+
"name",
|
|
524
|
+
"name must contain only lowercase letters, numbers, and hyphens"
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
if (fm.name.startsWith("-") || fm.name.endsWith("-")) {
|
|
528
|
+
throw new SkillManifestError(
|
|
529
|
+
filePath,
|
|
530
|
+
"name",
|
|
531
|
+
"name must not start or end with a hyphen"
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
if (fm.name.includes("--")) {
|
|
535
|
+
throw new SkillManifestError(
|
|
536
|
+
filePath,
|
|
537
|
+
"name",
|
|
538
|
+
"name must not contain consecutive hyphens"
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
if (XML_TAG_PATTERN.test(fm.name)) {
|
|
542
|
+
throw new SkillManifestError(filePath, "name", "name cannot contain XML tags");
|
|
543
|
+
}
|
|
544
|
+
for (const reserved of RESERVED_WORDS) {
|
|
545
|
+
if (fm.name.includes(reserved)) {
|
|
546
|
+
throw new SkillManifestError(
|
|
547
|
+
filePath,
|
|
548
|
+
"name",
|
|
549
|
+
`name cannot contain reserved word "${reserved}"`
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (!fm.description || typeof fm.description !== "string") {
|
|
554
|
+
throw new SkillManifestError(
|
|
555
|
+
filePath,
|
|
556
|
+
"description",
|
|
557
|
+
"description is required and must be non-empty"
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
if (fm.description.length > DESCRIPTION_MAX_LENGTH) {
|
|
561
|
+
throw new SkillManifestError(
|
|
562
|
+
filePath,
|
|
563
|
+
"description",
|
|
564
|
+
`description must be at most ${DESCRIPTION_MAX_LENGTH} characters (got ${fm.description.length})`
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
if (XML_TAG_PATTERN.test(fm.description)) {
|
|
568
|
+
throw new SkillManifestError(
|
|
569
|
+
filePath,
|
|
570
|
+
"description",
|
|
571
|
+
"description cannot contain XML tags"
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
if (fm.compatibility != null && typeof fm.compatibility === "string") {
|
|
575
|
+
if (fm.compatibility.length > COMPATIBILITY_MAX_LENGTH) {
|
|
576
|
+
throw new SkillManifestError(
|
|
577
|
+
filePath,
|
|
578
|
+
"compatibility",
|
|
579
|
+
`compatibility must be at most ${COMPATIBILITY_MAX_LENGTH} characters (got ${fm.compatibility.length})`
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
var CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
585
|
+
".py",
|
|
586
|
+
".js",
|
|
587
|
+
".mjs",
|
|
588
|
+
".ts",
|
|
589
|
+
".sh",
|
|
590
|
+
".bash",
|
|
591
|
+
".rb",
|
|
592
|
+
".go"
|
|
593
|
+
]);
|
|
594
|
+
var INSTRUCTION_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt"]);
|
|
595
|
+
var EXCLUDED_FILES = /* @__PURE__ */ new Set(["SKILL.md", "tool.json"]);
|
|
596
|
+
function parseSkillMd(content, filePath) {
|
|
597
|
+
const trimmed = content.trimStart();
|
|
598
|
+
if (!trimmed.startsWith("---")) {
|
|
599
|
+
throw new SkillManifestError(
|
|
600
|
+
filePath,
|
|
601
|
+
"frontmatter",
|
|
602
|
+
"SKILL.md must start with YAML frontmatter (---)"
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
const endIndex = trimmed.indexOf("\n---", 3);
|
|
606
|
+
if (endIndex === -1) {
|
|
607
|
+
throw new SkillManifestError(
|
|
608
|
+
filePath,
|
|
609
|
+
"frontmatter",
|
|
610
|
+
"SKILL.md frontmatter is not closed (missing closing ---)"
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
const yamlBlock = trimmed.slice(4, endIndex).trim();
|
|
614
|
+
const body = trimmed.slice(endIndex + 4).trim();
|
|
615
|
+
let raw;
|
|
616
|
+
try {
|
|
617
|
+
const parsed = yaml__default.default.load(yamlBlock);
|
|
618
|
+
if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
619
|
+
throw new SkillManifestError(
|
|
620
|
+
filePath,
|
|
621
|
+
"frontmatter",
|
|
622
|
+
"YAML frontmatter must be an object (key: value)"
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
raw = parsed;
|
|
626
|
+
} catch (err) {
|
|
627
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
628
|
+
throw new SkillManifestError(
|
|
629
|
+
filePath,
|
|
630
|
+
"frontmatter",
|
|
631
|
+
`Invalid YAML frontmatter: ${message}`
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
const name = stringField(raw, "name", filePath);
|
|
635
|
+
const description = stringField(raw, "description", filePath);
|
|
636
|
+
if (!name || !description) {
|
|
637
|
+
throw new SkillManifestError(
|
|
638
|
+
filePath,
|
|
639
|
+
"frontmatter",
|
|
640
|
+
!name ? "name is required" : "description is required"
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
const license = stringField(raw, "license");
|
|
644
|
+
const compatibility = stringField(raw, "compatibility");
|
|
645
|
+
const allowedTools = stringField(raw, "allowed-tools");
|
|
646
|
+
const metadata = normalizeMetadata(raw.metadata);
|
|
647
|
+
const frontmatter = {
|
|
648
|
+
name,
|
|
649
|
+
description,
|
|
650
|
+
...license && { license },
|
|
651
|
+
...compatibility && { compatibility },
|
|
652
|
+
...allowedTools && { allowedTools },
|
|
653
|
+
...metadata && Object.keys(metadata).length > 0 && { metadata }
|
|
654
|
+
};
|
|
655
|
+
validateFrontmatter(frontmatter, filePath);
|
|
656
|
+
return { frontmatter, instructions: body };
|
|
657
|
+
}
|
|
658
|
+
function stringField(raw, key, filePath) {
|
|
659
|
+
const v = raw[key];
|
|
660
|
+
if (v == null) return "";
|
|
661
|
+
if (typeof v === "string") return v;
|
|
662
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
663
|
+
if (Array.isArray(v)) {
|
|
664
|
+
return v.map((x) => typeof x === "string" ? x : String(x)).join("\n");
|
|
665
|
+
}
|
|
666
|
+
if (filePath) {
|
|
667
|
+
throw new SkillManifestError(
|
|
668
|
+
filePath,
|
|
669
|
+
"frontmatter",
|
|
670
|
+
`Frontmatter field "${key}" must be a string, number, boolean, or array`
|
|
671
|
+
);
|
|
672
|
+
}
|
|
673
|
+
return String(v);
|
|
674
|
+
}
|
|
675
|
+
function normalizeMetadata(val) {
|
|
676
|
+
if (val == null) return void 0;
|
|
677
|
+
if (typeof val === "object" && !Array.isArray(val)) {
|
|
678
|
+
const out = {};
|
|
679
|
+
for (const [k, v] of Object.entries(val)) {
|
|
680
|
+
if (typeof k === "string" && v !== void 0 && v !== null) {
|
|
681
|
+
out[k] = typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return Object.keys(out).length ? out : void 0;
|
|
685
|
+
}
|
|
686
|
+
if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
|
|
687
|
+
return { value: String(val) };
|
|
688
|
+
}
|
|
689
|
+
return void 0;
|
|
690
|
+
}
|
|
691
|
+
async function scanSkillResources(dirPath) {
|
|
692
|
+
const resources = [];
|
|
693
|
+
await scanDir(dirPath, dirPath, resources);
|
|
694
|
+
return resources;
|
|
695
|
+
}
|
|
696
|
+
async function scanDir(basePath, currentPath, resources) {
|
|
697
|
+
let entries;
|
|
698
|
+
try {
|
|
699
|
+
entries = await fs3.readdir(currentPath, { withFileTypes: true });
|
|
700
|
+
} catch {
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
for (const entry of entries) {
|
|
704
|
+
const fullPath = path5.join(currentPath, entry.name);
|
|
705
|
+
if (entry.isDirectory()) {
|
|
706
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
await scanDir(basePath, fullPath, resources);
|
|
710
|
+
} else if (entry.isFile()) {
|
|
711
|
+
if (EXCLUDED_FILES.has(entry.name)) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
const ext = path5.extname(entry.name).toLowerCase();
|
|
715
|
+
const relPath = path5.relative(basePath, fullPath);
|
|
716
|
+
resources.push({
|
|
717
|
+
relativePath: relPath,
|
|
718
|
+
absolutePath: fullPath,
|
|
719
|
+
extension: ext,
|
|
720
|
+
type: inferResourceType(ext)
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
function inferResourceType(ext) {
|
|
726
|
+
if (CODE_EXTENSIONS.has(ext)) return "code";
|
|
727
|
+
if (INSTRUCTION_EXTENSIONS.has(ext)) return "instructions";
|
|
728
|
+
return "data";
|
|
729
|
+
}
|
|
730
|
+
async function loadSkillDefinition(dirPath) {
|
|
731
|
+
const skillMdPath = path5.join(dirPath, "SKILL.md");
|
|
732
|
+
let content;
|
|
733
|
+
try {
|
|
734
|
+
content = await fs3.readFile(skillMdPath, "utf-8");
|
|
735
|
+
} catch (err) {
|
|
736
|
+
throw new SkillManifestError(
|
|
737
|
+
skillMdPath,
|
|
738
|
+
"file",
|
|
739
|
+
`Cannot read SKILL.md: ${err.message}`
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
const { frontmatter, instructions } = parseSkillMd(content, skillMdPath);
|
|
743
|
+
const resources = await scanSkillResources(dirPath);
|
|
744
|
+
return {
|
|
745
|
+
frontmatter,
|
|
746
|
+
instructions,
|
|
747
|
+
resources,
|
|
748
|
+
dirPath,
|
|
749
|
+
skillMdPath
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// src/discovery/errors.ts
|
|
754
|
+
var DiscoveryError = class extends Error {
|
|
755
|
+
/** Absolute path to the tool directory that caused the error */
|
|
756
|
+
toolDir;
|
|
757
|
+
/** Phase in which the error occurred */
|
|
758
|
+
phase;
|
|
759
|
+
/** The underlying cause */
|
|
760
|
+
cause;
|
|
761
|
+
constructor(toolDir, phase, message, cause) {
|
|
762
|
+
super(`[${phase}] ${toolDir}: ${message}`);
|
|
763
|
+
this.name = "DiscoveryError";
|
|
764
|
+
this.toolDir = toolDir;
|
|
765
|
+
this.phase = phase;
|
|
766
|
+
this.cause = cause;
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
var defaultInputSchema = { type: "object", properties: {}, additionalProperties: true };
|
|
770
|
+
async function scanForSkill(projectPath) {
|
|
771
|
+
const projectRoot = path5__namespace.resolve(projectPath);
|
|
772
|
+
const dirs = await findDirsContainingFile(projectRoot, "SKILL.md");
|
|
773
|
+
const skills = [];
|
|
774
|
+
const errors = [];
|
|
775
|
+
for (const dirPath of dirs) {
|
|
776
|
+
const relativePath = path5__namespace.relative(projectRoot, dirPath) || path5__namespace.basename(dirPath);
|
|
777
|
+
try {
|
|
778
|
+
const skillDef = await loadSkillDefinition(dirPath);
|
|
779
|
+
const name = pathToToolName(relativePath, skillDef.frontmatter.name);
|
|
780
|
+
skills.push({
|
|
781
|
+
kind: "skill",
|
|
782
|
+
name,
|
|
783
|
+
description: skillDef.frontmatter.description,
|
|
784
|
+
inputSchema: defaultInputSchema,
|
|
785
|
+
_meta: { hitl: { sideEffect: "none" } },
|
|
786
|
+
sourcePath: relativePath.replace(/\\/g, "/")
|
|
787
|
+
});
|
|
788
|
+
} catch (err) {
|
|
789
|
+
errors.push({ dir: relativePath, message: err instanceof Error ? err.message : String(err) });
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return { skills, errors };
|
|
793
|
+
}
|
|
794
|
+
async function readWorkflowMeta(dirPath, workflowFileName = "workflow.json") {
|
|
795
|
+
const workflowPath = path5.join(dirPath, workflowFileName);
|
|
796
|
+
let raw;
|
|
797
|
+
try {
|
|
798
|
+
raw = await fs3.readFile(workflowPath, "utf-8");
|
|
799
|
+
} catch (err) {
|
|
800
|
+
throw new DiscoveryError(
|
|
801
|
+
dirPath,
|
|
802
|
+
"load",
|
|
803
|
+
`Failed to read workflow: ${workflowPath}`,
|
|
804
|
+
err
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
let workflowDef;
|
|
808
|
+
try {
|
|
809
|
+
workflowDef = JSON.parse(raw);
|
|
810
|
+
} catch (err) {
|
|
811
|
+
throw new DiscoveryError(
|
|
812
|
+
dirPath,
|
|
813
|
+
"load",
|
|
814
|
+
`Invalid JSON in ${workflowPath}`,
|
|
815
|
+
err
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
if (!workflowDef.nodes || !Array.isArray(workflowDef.nodes)) {
|
|
819
|
+
throw new DiscoveryError(
|
|
820
|
+
dirPath,
|
|
821
|
+
"validate",
|
|
822
|
+
`workflow.json must have a "nodes" array`
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
const meta = workflowDef.meta;
|
|
826
|
+
const name = workflowDef.name || meta?.name || path5.basename(dirPath);
|
|
827
|
+
const description = workflowDef.description || meta?.description || `n8n workflow: ${name}`;
|
|
828
|
+
let webhookUrl;
|
|
829
|
+
const nodes = workflowDef.nodes;
|
|
830
|
+
if (Array.isArray(nodes)) {
|
|
831
|
+
const webhookNode = nodes.find(
|
|
832
|
+
(n) => n.type === "n8n-nodes-base.webhook" || n.type?.includes("webhook")
|
|
833
|
+
);
|
|
834
|
+
if (webhookNode?.parameters && typeof webhookNode.parameters === "object") {
|
|
835
|
+
const params = webhookNode.parameters;
|
|
836
|
+
const pathVal = params.path ?? params.webhookPath;
|
|
837
|
+
if (typeof pathVal === "string" && pathVal.startsWith("http")) {
|
|
838
|
+
webhookUrl = pathVal;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
return { name, description, webhookUrl, workflowDef };
|
|
843
|
+
}
|
|
844
|
+
async function loadN8nTool(dirPath, manifest) {
|
|
845
|
+
const { workflowDef } = await readWorkflowMeta(
|
|
846
|
+
dirPath,
|
|
847
|
+
manifest.entryPoint ?? "workflow.json"
|
|
848
|
+
);
|
|
849
|
+
return { manifest, dirPath, workflowDef };
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// src/codegen/scan/scanN8n.ts
|
|
853
|
+
var defaultInputSchema2 = { type: "object", properties: {}, additionalProperties: true };
|
|
854
|
+
async function scanForN8n(projectPath) {
|
|
855
|
+
const projectRoot = path5__namespace.resolve(projectPath);
|
|
856
|
+
const dirs = await findDirsContainingFile(projectRoot, "workflow.json");
|
|
857
|
+
const n8n = [];
|
|
858
|
+
const errors = [];
|
|
859
|
+
for (const dirPath of dirs) {
|
|
860
|
+
const relativePath = path5__namespace.relative(projectRoot, dirPath) || path5__namespace.basename(dirPath);
|
|
861
|
+
try {
|
|
862
|
+
const { name: wfName, description: wfDesc, webhookUrl } = await readWorkflowMeta(dirPath);
|
|
863
|
+
const toolName = pathToToolName(relativePath, wfName);
|
|
864
|
+
n8n.push({
|
|
865
|
+
kind: "n8n",
|
|
866
|
+
name: toolName,
|
|
867
|
+
description: wfDesc,
|
|
868
|
+
inputSchema: defaultInputSchema2,
|
|
869
|
+
_meta: { hitl: { sideEffect: "external_write" } },
|
|
870
|
+
sourcePath: relativePath.replace(/\\/g, "/"),
|
|
871
|
+
webhookUrl
|
|
872
|
+
});
|
|
873
|
+
} catch (err) {
|
|
874
|
+
errors.push({ dir: relativePath, message: err instanceof Error ? err.message : String(err) });
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return { n8n, errors };
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/codegen/scan/scanTools.ts
|
|
881
|
+
async function scanForAllTools(projectPath, options = {}) {
|
|
882
|
+
const include = options.include ?? ["**/*.ts"];
|
|
883
|
+
const tsconfigPath = options.tsconfigPath;
|
|
884
|
+
const includeN8n = options.includeN8n === true;
|
|
885
|
+
const [functionResult, skillResult, n8nResult] = await Promise.all([
|
|
886
|
+
Promise.resolve(scanForTools({ projectPath, include, tsconfigPath })),
|
|
887
|
+
scanForSkill(projectPath),
|
|
888
|
+
includeN8n ? scanForN8n(projectPath) : Promise.resolve({ n8n: [], errors: [] })
|
|
889
|
+
]);
|
|
890
|
+
const specs = [
|
|
891
|
+
...functionResult.specs,
|
|
892
|
+
...skillResult.skills,
|
|
893
|
+
...n8nResult.n8n
|
|
894
|
+
];
|
|
895
|
+
const errors = [
|
|
896
|
+
...functionResult.errors,
|
|
897
|
+
...skillResult.errors.map((e) => ({ file: e.dir, message: e.message })),
|
|
898
|
+
...includeN8n ? n8nResult.errors.map((e) => ({ file: e.dir, message: e.message })) : []
|
|
899
|
+
];
|
|
900
|
+
const warnings = [...functionResult.warnings];
|
|
901
|
+
return { specs, errors, warnings };
|
|
902
|
+
}
|
|
903
|
+
var __dirname$1 = path5__namespace.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-Z7TGIG77.cjs', document.baseURI).href))));
|
|
904
|
+
async function loadTemplate(name) {
|
|
905
|
+
for (const dir of [
|
|
906
|
+
path5__namespace.join(__dirname$1, "templates"),
|
|
907
|
+
path5__namespace.join(__dirname$1, "..", "templates")
|
|
908
|
+
]) {
|
|
909
|
+
try {
|
|
910
|
+
return await fs3__namespace.readFile(path5__namespace.join(dir, name), "utf-8");
|
|
911
|
+
} catch {
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
throw new Error(`Template not found: ${name}. Tried templates/ next to generator and ../templates.`);
|
|
916
|
+
}
|
|
917
|
+
var TEMPLATE_NAMES = {
|
|
918
|
+
mcpServer: "mcp-server.js",
|
|
919
|
+
toolIndex: "tool-index.js",
|
|
920
|
+
skillInvoker: "skill-invoker.js",
|
|
921
|
+
n8nInvoker: "n8n-invoker.js"
|
|
922
|
+
};
|
|
923
|
+
function buildToolIndexCases(specs, fromGeneratedToProject) {
|
|
924
|
+
return specs.map((s) => {
|
|
925
|
+
const modPath = path5__namespace.join(fromGeneratedToProject, s.sourcePath).replace(/\\/g, "/");
|
|
926
|
+
return ` case "${s.name}": return (await import("${modPath}")).${s.exportName};`;
|
|
927
|
+
}).join("\n");
|
|
928
|
+
}
|
|
929
|
+
function buildSkillInvokerCases(specs, fromGeneratedToProject) {
|
|
930
|
+
return specs.map((s) => {
|
|
931
|
+
const handlerPath = path5__namespace.join(fromGeneratedToProject, s.sourcePath, "handler").replace(/\\/g, "/");
|
|
932
|
+
const descEscaped = s.description.replace(/"/g, '\\"');
|
|
933
|
+
return ` case "${s.name}": {
|
|
934
|
+
const mod = await import("${handlerPath}.js").catch(() => import("${handlerPath}.mjs"));
|
|
935
|
+
const fn = mod.default ?? mod.handler;
|
|
936
|
+
if (typeof fn !== "function") return { result: null, error: "No handler" };
|
|
937
|
+
const ctx = { requestId: "mcp", taskId: "mcp", skill: { name: "${s.name}", description: "${descEscaped}", instructions: "", resources: [], readResource: async () => "", getResourcesByType: () => [], dirPath: "" } };
|
|
938
|
+
const out = await fn(args, ctx);
|
|
939
|
+
return out?.result !== undefined ? out.result : out;
|
|
940
|
+
}`;
|
|
941
|
+
}).join("\n");
|
|
942
|
+
}
|
|
943
|
+
function buildN8nInvokerCases(specs) {
|
|
944
|
+
return specs.map((s) => {
|
|
945
|
+
const url = s.webhookUrl ? `"${s.webhookUrl}"` : "process.env.N8N_WEBHOOK_" + s.name.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase() + " ?? null";
|
|
946
|
+
return ` case "${s.name}": {
|
|
947
|
+
const url = ${url};
|
|
948
|
+
if (!url) throw new Error("n8n webhook not configured for ${s.name}. Set N8N_WEBHOOK_* or add webhook to workflow.");
|
|
949
|
+
const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(args) });
|
|
950
|
+
if (!res.ok) throw new Error("n8n request failed: " + res.status);
|
|
951
|
+
return res.json().catch(() => ({}));
|
|
952
|
+
}`;
|
|
953
|
+
}).join("\n");
|
|
954
|
+
}
|
|
955
|
+
async function generate(options) {
|
|
956
|
+
const { specs, outDir, projectPath } = options;
|
|
957
|
+
await fs3__namespace.mkdir(outDir, { recursive: true });
|
|
958
|
+
const functionSpecs = specs.filter((s) => s.kind === "function");
|
|
959
|
+
const skillSpecs = specs.filter((s) => s.kind === "skill");
|
|
960
|
+
const n8nSpecs = specs.filter((s) => s.kind === "n8n");
|
|
961
|
+
const toolSpecsJson = specs.map((s) => ({
|
|
962
|
+
kind: s.kind,
|
|
963
|
+
name: s.name,
|
|
964
|
+
description: s.description,
|
|
965
|
+
inputSchema: s.inputSchema,
|
|
966
|
+
...s.kind === "function" && {
|
|
967
|
+
outputSchema: s.outputSchema ?? { type: "object", additionalProperties: true },
|
|
968
|
+
sourcePath: s.sourcePath,
|
|
969
|
+
exportName: s.exportName
|
|
970
|
+
},
|
|
971
|
+
_meta: s._meta,
|
|
972
|
+
...s.kind === "skill" && { sourcePath: s.sourcePath },
|
|
973
|
+
...s.kind === "n8n" && { sourcePath: s.sourcePath, webhookUrl: s.webhookUrl }
|
|
974
|
+
}));
|
|
975
|
+
await fs3__namespace.writeFile(
|
|
976
|
+
path5__namespace.join(outDir, "tool-specs.json"),
|
|
977
|
+
JSON.stringify(toolSpecsJson, null, 2),
|
|
978
|
+
"utf-8"
|
|
979
|
+
);
|
|
980
|
+
const configJson = { projectPath: path5__namespace.resolve(projectPath) };
|
|
981
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "config.json"), JSON.stringify(configJson, null, 2), "utf-8");
|
|
982
|
+
const rel = path5__namespace.relative(outDir, projectPath) || ".";
|
|
983
|
+
const fromGeneratedToProject = rel.split(path5__namespace.sep).length ? rel : ".";
|
|
984
|
+
const [mcpServerTemplate, toolIndexTemplate, skillInvokerTemplate, n8nInvokerTemplate] = await Promise.all([
|
|
985
|
+
loadTemplate(TEMPLATE_NAMES.mcpServer),
|
|
986
|
+
loadTemplate(TEMPLATE_NAMES.toolIndex),
|
|
987
|
+
loadTemplate(TEMPLATE_NAMES.skillInvoker),
|
|
988
|
+
loadTemplate(TEMPLATE_NAMES.n8nInvoker)
|
|
989
|
+
]);
|
|
990
|
+
const toolIndexTs = toolIndexTemplate.replace("{{CASES}}", buildToolIndexCases(functionSpecs, fromGeneratedToProject));
|
|
991
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "tool-index.ts"), toolIndexTs, "utf-8");
|
|
992
|
+
const skillCases = buildSkillInvokerCases(skillSpecs, fromGeneratedToProject);
|
|
993
|
+
const skillDefaultCase = skillSpecs.length === 0 ? "default: throw new Error('Unknown skill: ' + name);" : 'default: throw new Error("Unknown skill: " + name);';
|
|
994
|
+
const skillInvokerTs = skillInvokerTemplate.replace("{{CASES}}", skillCases).replace("{{DEFAULT_CASE}}", skillDefaultCase);
|
|
995
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "skill-invoker.ts"), skillInvokerTs, "utf-8");
|
|
996
|
+
const n8nCases = buildN8nInvokerCases(n8nSpecs);
|
|
997
|
+
const n8nDefaultCase = n8nSpecs.length === 0 ? "default: throw new Error('Unknown n8n tool: ' + name);" : 'default: throw new Error("Unknown n8n tool: " + name);';
|
|
998
|
+
const n8nInvokerTs = n8nInvokerTemplate.replace("{{CASES}}", n8nCases).replace("{{DEFAULT_CASE}}", n8nDefaultCase);
|
|
999
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "n8n-invoker.ts"), n8nInvokerTs, "utf-8");
|
|
1000
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "mcp-server.ts"), mcpServerTemplate, "utf-8");
|
|
1001
|
+
const mcpJson = {
|
|
1002
|
+
command: "npx",
|
|
1003
|
+
args: ["-y", "tsx", path5__namespace.join(outDir, "mcp-server.ts")]
|
|
1004
|
+
};
|
|
1005
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "mcp.json"), JSON.stringify(mcpJson, null, 2), "utf-8");
|
|
1006
|
+
const packageJson = {
|
|
1007
|
+
name: "function-tools-mcp",
|
|
1008
|
+
version: "1.0.0",
|
|
1009
|
+
type: "module",
|
|
1010
|
+
description: "MCP server generated from @tool functions, SKILL.md, and workflow.json",
|
|
1011
|
+
main: "mcp-server.ts",
|
|
1012
|
+
scripts: { start: "npx tsx mcp-server.ts" },
|
|
1013
|
+
dependencies: {
|
|
1014
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
1015
|
+
typescript: ">=5.0.0",
|
|
1016
|
+
tsx: ">=4.0.0"
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
await fs3__namespace.writeFile(path5__namespace.join(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
1020
|
+
return {
|
|
1021
|
+
entryPath: path5__namespace.join(outDir, "mcp-server.ts"),
|
|
1022
|
+
mcpJsonPath: path5__namespace.join(outDir, "mcp.json")
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
// src/codegen/build.ts
|
|
1027
|
+
async function buildMcpPackage(options = {}) {
|
|
1028
|
+
const projectPath = path5__namespace.resolve(options.projectPath ?? process.cwd());
|
|
1029
|
+
const outDir = path5__namespace.resolve(projectPath, options.outDir ?? "dist");
|
|
1030
|
+
const include = options.include ?? ["**/*.ts"];
|
|
1031
|
+
const tsconfigPath = options.tsconfigPath;
|
|
1032
|
+
const scanResult = await scanForAllTools(projectPath, {
|
|
1033
|
+
include,
|
|
1034
|
+
tsconfigPath,
|
|
1035
|
+
includeN8n: options.includeN8n
|
|
1036
|
+
});
|
|
1037
|
+
if (scanResult.errors.length > 0) {
|
|
1038
|
+
const msg = scanResult.errors.map((e) => `${e.file}: ${e.message}`).join("; ");
|
|
1039
|
+
throw new Error(`Scan failed: ${msg}`);
|
|
1040
|
+
}
|
|
1041
|
+
const allSpecs = scanResult.specs;
|
|
1042
|
+
if (allSpecs.length === 0) {
|
|
1043
|
+
throw new Error(
|
|
1044
|
+
"No tools found. Add @tool functions (JSDoc), SKILL.md directories, or workflow.json directories."
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
const { entryPath, mcpJsonPath } = await generate({
|
|
1048
|
+
specs: allSpecs,
|
|
1049
|
+
outDir,
|
|
1050
|
+
projectPath
|
|
1051
|
+
});
|
|
1052
|
+
return {
|
|
1053
|
+
outDir,
|
|
1054
|
+
toolCount: allSpecs.length,
|
|
1055
|
+
entryPath,
|
|
1056
|
+
mcpJsonPath
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
var buildFunctionToTool = buildMcpPackage;
|
|
1060
|
+
async function runMcpServer(options = {}) {
|
|
1061
|
+
const base = options.path ?? process.cwd();
|
|
1062
|
+
const candidates = [
|
|
1063
|
+
path5__namespace.join(base, "mcp-server.ts"),
|
|
1064
|
+
path5__namespace.join(base, "mcp-server.js"),
|
|
1065
|
+
path5__namespace.join(base, "dist", "mcp-server.ts"),
|
|
1066
|
+
path5__namespace.join(base, "dist", "mcp-server.js"),
|
|
1067
|
+
path5__namespace.join(base, "generated", "mcp-server.ts"),
|
|
1068
|
+
path5__namespace.join(base, "generated", "mcp-server.js")
|
|
1069
|
+
];
|
|
1070
|
+
let entry = "";
|
|
1071
|
+
for (const p of candidates) {
|
|
1072
|
+
try {
|
|
1073
|
+
await fs3__namespace.access(p);
|
|
1074
|
+
entry = p;
|
|
1075
|
+
break;
|
|
1076
|
+
} catch {
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (!entry) {
|
|
1080
|
+
throw new Error(
|
|
1081
|
+
`MCP entrypoint not found. Run "agent-tool build" first, or pass --path to a directory containing mcp-server.ts. Tried: ${candidates.join(", ")}`
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
const dir = path5__namespace.dirname(entry);
|
|
1085
|
+
const child = child_process.spawn("npx", ["-y", "tsx", path5__namespace.basename(entry)], {
|
|
1086
|
+
cwd: dir,
|
|
1087
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
1088
|
+
shell: false
|
|
1089
|
+
});
|
|
1090
|
+
return { process: child };
|
|
1091
|
+
}
|
|
1092
|
+
var runGeneratedMCP = runMcpServer;
|
|
1093
|
+
|
|
1094
|
+
exports.DiscoveryError = DiscoveryError;
|
|
1095
|
+
exports.SkillManifestError = SkillManifestError;
|
|
1096
|
+
exports.buildFunctionToTool = buildFunctionToTool;
|
|
1097
|
+
exports.buildMcpPackage = buildMcpPackage;
|
|
1098
|
+
exports.initProject = initProject;
|
|
1099
|
+
exports.loadN8nTool = loadN8nTool;
|
|
1100
|
+
exports.loadSkillDefinition = loadSkillDefinition;
|
|
1101
|
+
exports.parseSkillMd = parseSkillMd;
|
|
1102
|
+
exports.runGeneratedMCP = runGeneratedMCP;
|
|
1103
|
+
exports.runMcpServer = runMcpServer;
|
|
1104
|
+
exports.scanForTools = scanForTools;
|
|
1105
|
+
exports.scanSkillResources = scanSkillResources;
|
|
1106
|
+
exports.validateFrontmatter = validateFrontmatter;
|
|
1107
|
+
//# sourceMappingURL=chunk-Z7TGIG77.cjs.map
|
|
1108
|
+
//# sourceMappingURL=chunk-Z7TGIG77.cjs.map
|