@easynet/agent-tool 1.0.1 → 1.0.2
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 +92 -50
- package/dist/api/adapters/LangChainToolsHub.d.ts +34 -0
- package/dist/api/adapters/LangChainToolsHub.d.ts.map +1 -0
- package/dist/api/createAgentTools.d.ts +24 -0
- package/dist/api/createAgentTools.d.ts.map +1 -0
- package/dist/api/expose/index.d.ts +16 -0
- package/dist/api/expose/index.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/build.d.ts.map +1 -0
- package/dist/{codegen → api/expose/mcp-build}/generator.d.ts +3 -3
- package/dist/api/expose/mcp-build/generator.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/index.d.ts +8 -0
- package/dist/api/expose/mcp-build/index.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/init.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/run.d.ts.map +1 -0
- package/dist/api/expose/mcp-build/types.d.ts +25 -0
- package/dist/api/expose/mcp-build/types.d.ts.map +1 -0
- package/dist/api/expose/mcpServer.d.ts +75 -0
- package/dist/api/expose/mcpServer.d.ts.map +1 -0
- package/dist/api/expose/openapi.d.ts +23 -0
- package/dist/api/expose/openapi.d.ts.map +1 -0
- package/dist/api/expose/openapiHttp.d.ts +67 -0
- package/dist/api/expose/openapiHttp.d.ts.map +1 -0
- package/dist/api/main.cjs +56 -0
- package/dist/api/main.cjs.map +1 -0
- package/dist/api/main.d.ts +23 -0
- package/dist/api/main.d.ts.map +1 -0
- package/dist/api/main.js +7 -0
- package/dist/api/main.js.map +1 -0
- package/dist/api/runtimeFromConfig.d.ts +34 -0
- package/dist/api/runtimeFromConfig.d.ts.map +1 -0
- package/dist/canonicalCoreSchemas-CTW6CCFY.cjs +20 -0
- package/dist/canonicalCoreSchemas-CTW6CCFY.cjs.map +1 -0
- package/dist/canonicalCoreSchemas-YLHVHYJZ.js +3 -0
- package/dist/canonicalCoreSchemas-YLHVHYJZ.js.map +1 -0
- package/dist/{chunk-AXUNV4MK.js → chunk-5SWSNVMI.js} +3 -3
- package/dist/chunk-5SWSNVMI.js.map +1 -0
- package/dist/chunk-6F5JHLZ7.cjs +243 -0
- package/dist/chunk-6F5JHLZ7.cjs.map +1 -0
- package/dist/chunk-AE6FSNGY.js +201 -0
- package/dist/chunk-AE6FSNGY.js.map +1 -0
- package/dist/chunk-BZOKPJMP.cjs +120 -0
- package/dist/chunk-BZOKPJMP.cjs.map +1 -0
- package/dist/chunk-FA2ZEICE.cjs +1620 -0
- package/dist/chunk-FA2ZEICE.cjs.map +1 -0
- package/dist/chunk-FR2CXERF.js +239 -0
- package/dist/chunk-FR2CXERF.js.map +1 -0
- package/dist/chunk-MGEQPAHV.cjs +475 -0
- package/dist/chunk-MGEQPAHV.cjs.map +1 -0
- package/dist/{chunk-BM4EVYI5.js → chunk-PJ4RUBZL.js} +836 -122
- package/dist/chunk-PJ4RUBZL.js.map +1 -0
- package/dist/chunk-Q7KPGWC6.js +1584 -0
- package/dist/chunk-Q7KPGWC6.js.map +1 -0
- package/dist/chunk-QVH6IQKQ.js +469 -0
- package/dist/chunk-QVH6IQKQ.js.map +1 -0
- package/dist/{chunk-3YLVPZRJ.cjs → chunk-SOFUWEZ6.cjs} +3 -3
- package/dist/chunk-SOFUWEZ6.cjs.map +1 -0
- package/dist/chunk-TBMWJWQ2.js +116 -0
- package/dist/chunk-TBMWJWQ2.js.map +1 -0
- package/dist/{chunk-Z7TGIG77.cjs → chunk-ZBNRHRGM.cjs} +843 -127
- package/dist/chunk-ZBNRHRGM.cjs.map +1 -0
- package/dist/chunk-ZNJBRLKN.cjs +210 -0
- package/dist/chunk-ZNJBRLKN.cjs.map +1 -0
- package/dist/core/index.cjs +20 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/{core.d.ts → core/index.d.ts} +2 -3
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/registry/ToolRegistry.d.ts.map +1 -0
- package/dist/core/runtime/Budget.d.ts.map +1 -0
- package/dist/core/runtime/Evidence.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntime.d.ts +4 -4
- package/dist/core/runtime/PTCRuntime.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntimeObservability.d.ts +4 -4
- package/dist/core/runtime/PTCRuntimeObservability.d.ts.map +1 -0
- package/dist/{runtime → core/runtime}/PTCRuntimePipeline.d.ts +4 -4
- package/dist/core/runtime/PTCRuntimePipeline.d.ts.map +1 -0
- package/dist/core/runtime/PolicyEngine.d.ts.map +1 -0
- package/dist/core/runtime/Retry.d.ts.map +1 -0
- package/dist/core/runtime/SchemaValidator.d.ts.map +1 -0
- package/dist/core/runtime.cjs +24 -0
- package/dist/core/runtime.cjs.map +1 -0
- package/dist/core/runtime.d.ts +12 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +3 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/types/Events.d.ts.map +1 -0
- package/dist/core/types/ToolIntent.d.ts.map +1 -0
- package/dist/{types → core/types}/ToolResult.d.ts +6 -1
- package/dist/core/types/ToolResult.d.ts.map +1 -0
- package/dist/{types → core/types}/ToolSpec.d.ts +15 -5
- package/dist/core/types/ToolSpec.d.ts.map +1 -0
- package/dist/core/types/ToolTypeHandler.d.ts +88 -0
- package/dist/core/types/ToolTypeHandler.d.ts.map +1 -0
- package/dist/{types → core/types}/index.d.ts +2 -1
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/index.cjs +249 -2749
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +61 -55
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +126 -2688
- package/dist/index.js.map +1 -1
- package/dist/observability/EventLog.d.ts +1 -1
- package/dist/observability/EventLog.d.ts.map +1 -1
- package/dist/tools/discoveryFactory.d.ts +117 -0
- package/dist/tools/discoveryFactory.d.ts.map +1 -0
- package/dist/tools/function/index.d.ts +10 -0
- package/dist/tools/function/index.d.ts.map +1 -0
- package/dist/{codegen/scan → tools/function}/scanner.d.ts +5 -2
- package/dist/{codegen/scan → tools/function}/scanner.d.ts.map +1 -1
- package/dist/{codegen/scan → tools/function}/schemaFromTs.d.ts +1 -1
- package/dist/tools/function/schemaFromTs.d.ts.map +1 -0
- package/dist/tools/function/types.d.ts +20 -0
- package/dist/tools/function/types.d.ts.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/{discovery/load → tools/langchain}/LangChainLoader.d.ts +1 -1
- package/dist/tools/langchain/LangChainLoader.d.ts.map +1 -0
- package/dist/tools/langchain/directoryApply.d.ts +5 -0
- package/dist/tools/langchain/directoryApply.d.ts.map +1 -0
- package/dist/tools/langchain/directoryLoad.d.ts +13 -0
- package/dist/tools/langchain/directoryLoad.d.ts.map +1 -0
- package/dist/tools/langchain/index.d.ts +3 -0
- package/dist/tools/langchain/index.d.ts.map +1 -0
- package/dist/tools/langchain/scanner.d.ts +8 -0
- package/dist/tools/langchain/scanner.d.ts.map +1 -0
- package/dist/tools/langchain/types.d.ts +5 -0
- package/dist/tools/langchain/types.d.ts.map +1 -0
- package/dist/{mcp → tools/mcp}/MCPClientAdapter.d.ts +3 -3
- package/dist/tools/mcp/MCPClientAdapter.d.ts.map +1 -0
- package/dist/{discovery/load → tools/mcp}/MCPLoader.d.ts +1 -1
- package/dist/tools/mcp/MCPLoader.d.ts.map +1 -0
- package/dist/tools/mcp/MCPProcessManager.d.ts +29 -0
- package/dist/tools/mcp/MCPProcessManager.d.ts.map +1 -0
- package/dist/{mcp → tools/mcp}/connectMCP.d.ts +3 -3
- package/dist/tools/mcp/connectMCP.d.ts.map +1 -0
- package/dist/tools/mcp/directoryApply.d.ts +10 -0
- package/dist/tools/mcp/directoryApply.d.ts.map +1 -0
- package/dist/{mcp → tools/mcp}/index.d.ts +6 -1
- package/dist/tools/mcp/index.d.ts.map +1 -0
- package/dist/tools/mcp/mcpSpecToToolSpec.d.ts +8 -0
- package/dist/tools/mcp/mcpSpecToToolSpec.d.ts.map +1 -0
- package/dist/{mcp → tools/mcp}/registerMCPTools.d.ts +2 -2
- package/dist/tools/mcp/registerMCPTools.d.ts.map +1 -0
- package/dist/tools/mcp/scanner.d.ts +8 -0
- package/dist/tools/mcp/scanner.d.ts.map +1 -0
- package/dist/tools/mcp/types.d.ts +3 -0
- package/dist/tools/mcp/types.d.ts.map +1 -0
- package/dist/{discovery/load → tools/n8n}/N8nLoader.d.ts +3 -3
- package/dist/tools/n8n/N8nLoader.d.ts.map +1 -0
- package/dist/tools/n8n/directoryApply.d.ts +10 -0
- package/dist/tools/n8n/directoryApply.d.ts.map +1 -0
- package/dist/tools/n8n/index.d.ts +6 -0
- package/dist/tools/n8n/index.d.ts.map +1 -0
- package/dist/tools/n8n/scanN8n.d.ts +20 -0
- package/dist/tools/n8n/scanN8n.d.ts.map +1 -0
- package/dist/tools/n8n/types.d.ts +18 -0
- package/dist/tools/n8n/types.d.ts.map +1 -0
- package/dist/tools/scanPackage.d.ts +42 -0
- package/dist/tools/scanPackage.d.ts.map +1 -0
- package/dist/{discovery/load → tools/skill}/SkillLoader.d.ts +1 -1
- package/dist/tools/skill/SkillLoader.d.ts.map +1 -0
- package/dist/tools/skill/SkillManifest.d.ts.map +1 -0
- package/dist/tools/skill/SkillMdParser.d.ts.map +1 -0
- package/dist/tools/skill/directoryApply.d.ts +10 -0
- package/dist/tools/skill/directoryApply.d.ts.map +1 -0
- package/dist/tools/skill/index.d.ts +8 -0
- package/dist/tools/skill/index.d.ts.map +1 -0
- package/dist/tools/skill/scanSkill.d.ts +20 -0
- package/dist/tools/skill/scanSkill.d.ts.map +1 -0
- package/dist/tools/skill/types.d.ts +19 -0
- package/dist/tools/skill/types.d.ts.map +1 -0
- package/dist/tools/util/canonicalCoreSchemas.d.ts +19 -0
- package/dist/tools/util/canonicalCoreSchemas.d.ts.map +1 -0
- package/dist/tools/util/index.d.ts +13 -0
- package/dist/tools/util/index.d.ts.map +1 -0
- package/dist/tools/util/resolveEntry.d.ts +6 -0
- package/dist/tools/util/resolveEntry.d.ts.map +1 -0
- package/dist/tools/util/scanUtil.d.ts +9 -0
- package/dist/tools/util/scanUtil.d.ts.map +1 -0
- package/dist/tools/util/toolConfig.d.ts +32 -0
- package/dist/tools/util/toolConfig.d.ts.map +1 -0
- package/dist/tools/util/toolDescriptor.d.ts +92 -0
- package/dist/tools/util/toolDescriptor.d.ts.map +1 -0
- package/dist/utils/cli/index.cjs +419 -0
- package/dist/utils/cli/index.cjs.map +1 -0
- package/dist/utils/cli/index.d.ts +9 -0
- package/dist/utils/cli/index.d.ts.map +1 -0
- package/dist/utils/cli/index.js +412 -0
- package/dist/utils/cli/index.js.map +1 -0
- package/dist/utils/cli/toolRuntime.d.ts +19 -0
- package/dist/utils/cli/toolRuntime.d.ts.map +1 -0
- package/dist/utils/npmCache.d.ts +28 -0
- package/dist/utils/npmCache.d.ts.map +1 -0
- package/package.json +20 -11
- package/dist/chunk-3YLVPZRJ.cjs.map +0 -1
- package/dist/chunk-AXUNV4MK.js.map +0 -1
- package/dist/chunk-BM4EVYI5.js.map +0 -1
- package/dist/chunk-P3UEAZHK.cjs +0 -171
- package/dist/chunk-P3UEAZHK.cjs.map +0 -1
- package/dist/chunk-RPAMQCFH.js +0 -167
- package/dist/chunk-RPAMQCFH.js.map +0 -1
- package/dist/chunk-Z7TGIG77.cjs.map +0 -1
- package/dist/cli.cjs +0 -154
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.ts +0 -10
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -147
- package/dist/cli.js.map +0 -1
- package/dist/codegen/build.d.ts.map +0 -1
- package/dist/codegen/generator.d.ts.map +0 -1
- package/dist/codegen/index.d.ts +0 -21
- package/dist/codegen/index.d.ts.map +0 -1
- package/dist/codegen/init.d.ts.map +0 -1
- package/dist/codegen/run.d.ts.map +0 -1
- package/dist/codegen/scan/scanN8n.d.ts +0 -17
- package/dist/codegen/scan/scanN8n.d.ts.map +0 -1
- package/dist/codegen/scan/scanSkill.d.ts +0 -17
- package/dist/codegen/scan/scanSkill.d.ts.map +0 -1
- package/dist/codegen/scan/scanTools.d.ts +0 -31
- package/dist/codegen/scan/scanTools.d.ts.map +0 -1
- package/dist/codegen/scan/schemaFromTs.d.ts.map +0 -1
- package/dist/codegen/types.d.ts +0 -81
- package/dist/codegen/types.d.ts.map +0 -1
- package/dist/core.cjs +0 -20
- package/dist/core.cjs.map +0 -1
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js +0 -3
- package/dist/core.js.map +0 -1
- package/dist/discovery/MCPProcessManager.d.ts +0 -57
- package/dist/discovery/MCPProcessManager.d.ts.map +0 -1
- package/dist/discovery/errors.d.ts +0 -13
- package/dist/discovery/errors.d.ts.map +0 -1
- package/dist/discovery/load/LangChainLoader.d.ts.map +0 -1
- package/dist/discovery/load/MCPLoader.d.ts.map +0 -1
- package/dist/discovery/load/N8nLoader.d.ts.map +0 -1
- package/dist/discovery/load/SkillLoader.d.ts.map +0 -1
- package/dist/discovery/load/SkillManifest.d.ts.map +0 -1
- package/dist/discovery/load/SkillMdParser.d.ts.map +0 -1
- package/dist/discovery/load/index.d.ts +0 -6
- package/dist/discovery/load/index.d.ts.map +0 -1
- package/dist/discovery/load/resolveEntry.d.ts +0 -7
- package/dist/discovery/load/resolveEntry.d.ts.map +0 -1
- package/dist/discovery/scan/DirectoryScanner.d.ts +0 -37
- package/dist/discovery/scan/DirectoryScanner.d.ts.map +0 -1
- package/dist/discovery/scan/scanUtil.d.ts +0 -16
- package/dist/discovery/scan/scanUtil.d.ts.map +0 -1
- package/dist/discovery/types.d.ts +0 -99
- package/dist/discovery/types.d.ts.map +0 -1
- package/dist/llm/AgentLLMAdapter.d.ts +0 -27
- package/dist/llm/AgentLLMAdapter.d.ts.map +0 -1
- package/dist/llm/LangChainToolsHub.d.ts +0 -31
- package/dist/llm/LangChainToolsHub.d.ts.map +0 -1
- package/dist/llm/OpenAICompatibleClient.d.ts +0 -64
- package/dist/llm/OpenAICompatibleClient.d.ts.map +0 -1
- package/dist/llm/ReActAgent.d.ts +0 -35
- package/dist/llm/ReActAgent.d.ts.map +0 -1
- package/dist/llm-export.cjs +0 -20
- package/dist/llm-export.cjs.map +0 -1
- package/dist/llm-export.d.ts +0 -9
- package/dist/llm-export.d.ts.map +0 -1
- package/dist/llm-export.js +0 -3
- package/dist/llm-export.js.map +0 -1
- package/dist/mcp/MCPClientAdapter.d.ts.map +0 -1
- package/dist/mcp/connectMCP.d.ts.map +0 -1
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/registerMCPTools.d.ts.map +0 -1
- package/dist/registry/ToolRegistry.d.ts.map +0 -1
- package/dist/report/AgentReportGenerator.d.ts +0 -53
- package/dist/report/AgentReportGenerator.d.ts.map +0 -1
- package/dist/report/agent-report-template.html +0 -362
- package/dist/report/index.d.ts +0 -3
- package/dist/report/index.d.ts.map +0 -1
- package/dist/report/types.d.ts +0 -101
- package/dist/report/types.d.ts.map +0 -1
- package/dist/runAgent.d.ts +0 -37
- package/dist/runAgent.d.ts.map +0 -1
- package/dist/runtime/Budget.d.ts.map +0 -1
- package/dist/runtime/Evidence.d.ts.map +0 -1
- package/dist/runtime/PTCRuntime.d.ts.map +0 -1
- package/dist/runtime/PTCRuntimeObservability.d.ts.map +0 -1
- package/dist/runtime/PTCRuntimePipeline.d.ts.map +0 -1
- package/dist/runtime/PolicyEngine.d.ts.map +0 -1
- package/dist/runtime/Retry.d.ts.map +0 -1
- package/dist/runtime/SchemaValidator.d.ts.map +0 -1
- package/dist/toolDescriptor.d.ts +0 -38
- package/dist/toolDescriptor.d.ts.map +0 -1
- package/dist/types/Events.d.ts.map +0 -1
- package/dist/types/ToolIntent.d.ts.map +0 -1
- package/dist/types/ToolResult.d.ts.map +0 -1
- package/dist/types/ToolSpec.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/extensions/examples/README.md +0 -40
- package/extensions/examples/scripts/agent-tool-react-stock.mjs +0 -30
- package/extensions/examples/tools/instruction-only/skill/SKILL.md +0 -26
- package/extensions/examples/tools/web-search/mcp/mcp.json +0 -8
- /package/dist/{codegen → api/expose/mcp-build}/build.d.ts +0 -0
- /package/dist/{codegen → api/expose/mcp-build}/init.d.ts +0 -0
- /package/dist/{codegen → api/expose/mcp-build}/run.d.ts +0 -0
- /package/dist/{registry → core/registry}/ToolRegistry.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Budget.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Evidence.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/PolicyEngine.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/Retry.d.ts +0 -0
- /package/dist/{runtime → core/runtime}/SchemaValidator.d.ts +0 -0
- /package/dist/{types → core/types}/Events.d.ts +0 -0
- /package/dist/{types → core/types}/ToolIntent.d.ts +0 -0
- /package/dist/{discovery/load → tools/skill}/SkillManifest.d.ts +0 -0
- /package/dist/{discovery/load → tools/skill}/SkillMdParser.d.ts +0 -0
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { DEFAULT_OUTPUT_SCHEMA } from './chunk-5SWSNVMI.js';
|
|
2
|
+
import { LANGCHAIN_DIR_NAME, LANGCHAIN_KIND, MCP_KIND } from './chunk-Q7KPGWC6.js';
|
|
1
3
|
import * as fs3 from 'fs/promises';
|
|
2
|
-
import { readdir, readFile } from 'fs/promises';
|
|
3
|
-
import * as
|
|
4
|
+
import { readdir, readFile, access, stat } from 'fs/promises';
|
|
5
|
+
import * as path9 from 'path';
|
|
4
6
|
import { join, extname, relative, basename } from 'path';
|
|
5
7
|
import * as fs2 from 'fs';
|
|
6
8
|
import * as ts2 from 'typescript';
|
|
7
9
|
import yaml from 'js-yaml';
|
|
8
|
-
import { fileURLToPath } from 'url';
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
9
11
|
import { spawn } from 'child_process';
|
|
10
12
|
|
|
11
|
-
// src/codegen/init.ts
|
|
12
13
|
var TEMPLATES = {
|
|
13
14
|
"package.json": `{
|
|
14
15
|
"name": "my-mcp-tools",
|
|
@@ -92,12 +93,12 @@ Edit \`src/tools/*.ts\` (add \`@tool\` JSDoc) and/or \`skills/*/SKILL.md\`, then
|
|
|
92
93
|
`
|
|
93
94
|
};
|
|
94
95
|
async function initProject(options = {}) {
|
|
95
|
-
const targetPath =
|
|
96
|
+
const targetPath = path9.resolve(options.targetPath ?? process.cwd());
|
|
96
97
|
const filesCreated = [];
|
|
97
98
|
await fs3.mkdir(targetPath, { recursive: true });
|
|
98
99
|
for (const [relPath, content] of Object.entries(TEMPLATES)) {
|
|
99
|
-
const fullPath =
|
|
100
|
-
await fs3.mkdir(
|
|
100
|
+
const fullPath = path9.join(targetPath, relPath);
|
|
101
|
+
await fs3.mkdir(path9.dirname(fullPath), { recursive: true });
|
|
101
102
|
try {
|
|
102
103
|
await fs3.access(fullPath);
|
|
103
104
|
if (relPath === "package.json") continue;
|
|
@@ -113,7 +114,7 @@ async function findDirsContainingFile(rootPath, fileName) {
|
|
|
113
114
|
await collectDirsWithFile(rootPath, fileName, found);
|
|
114
115
|
return found;
|
|
115
116
|
}
|
|
116
|
-
async function collectDirsWithFile(dir, fileName,
|
|
117
|
+
async function collectDirsWithFile(dir, fileName, acc) {
|
|
117
118
|
let entries;
|
|
118
119
|
try {
|
|
119
120
|
const e = await readdir(dir, { withFileTypes: true });
|
|
@@ -125,22 +126,16 @@ async function collectDirsWithFile(dir, fileName, found) {
|
|
|
125
126
|
} catch {
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
|
-
if (entries.some((x) => x.isFile && x.name === fileName))
|
|
129
|
-
found.push(dir);
|
|
130
|
-
}
|
|
129
|
+
if (entries.some((x) => x.isFile && x.name === fileName)) acc.push(dir);
|
|
131
130
|
for (const entry of entries) {
|
|
132
|
-
if (!entry.isDirectory || entry.name === "node_modules" || entry.name.startsWith("."))
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
await collectDirsWithFile(join(dir, entry.name), fileName, found);
|
|
131
|
+
if (!entry.isDirectory || entry.name === "node_modules" || entry.name.startsWith(".")) continue;
|
|
132
|
+
await collectDirsWithFile(join(dir, entry.name), fileName, acc);
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
function pathToToolName(sourcePath, programName) {
|
|
139
136
|
const normalized = sourcePath.replace(/\\/g, "/").replace(/\.(ts|tsx|js|mjs|json)$/i, "");
|
|
140
137
|
const segments = normalized.split("/").filter(Boolean);
|
|
141
|
-
|
|
142
|
-
const pathPart = segments.join(".");
|
|
143
|
-
return `${pathPart}.${programName}`;
|
|
138
|
+
return segments.length === 0 ? programName : `${segments.join(".")}.${programName}`;
|
|
144
139
|
}
|
|
145
140
|
function buildOutputSchemaFromReturnType(node, typeChecker, onWarn) {
|
|
146
141
|
const sig = typeChecker.getSignatureFromDeclaration(node);
|
|
@@ -235,19 +230,60 @@ function typeToJsonSchema(type, typeChecker, onWarn) {
|
|
|
235
230
|
return { type: "object" };
|
|
236
231
|
}
|
|
237
232
|
|
|
238
|
-
// src/
|
|
233
|
+
// src/tools/function/types.ts
|
|
234
|
+
var FUNCTION_KIND = "function";
|
|
235
|
+
|
|
236
|
+
// src/tools/skill/types.ts
|
|
237
|
+
var SKILL_KIND = "skill";
|
|
238
|
+
var SKILL_DIR_NAME = "skill";
|
|
239
|
+
|
|
240
|
+
// src/tools/n8n/types.ts
|
|
241
|
+
var N8N_KIND = "n8n";
|
|
242
|
+
|
|
243
|
+
// src/tools/mcp/mcpSpecToToolSpec.ts
|
|
244
|
+
var DEFAULT_OUTPUT = { type: "object", additionalProperties: true };
|
|
245
|
+
function mcpSpecToToolSpec(spec, projectPath) {
|
|
246
|
+
const base = {
|
|
247
|
+
name: spec.name,
|
|
248
|
+
version: "1.0.0",
|
|
249
|
+
kind: spec.kind,
|
|
250
|
+
description: spec.description,
|
|
251
|
+
inputSchema: spec.inputSchema ?? DEFAULT_OUTPUT,
|
|
252
|
+
outputSchema: "outputSchema" in spec && spec.outputSchema ? spec.outputSchema : DEFAULT_OUTPUT_SCHEMA,
|
|
253
|
+
capabilities: [],
|
|
254
|
+
_meta: spec._meta,
|
|
255
|
+
...spec.kind === N8N_KIND && "webhookUrl" in spec && spec.webhookUrl ? { endpoint: spec.webhookUrl } : {}
|
|
256
|
+
};
|
|
257
|
+
if (spec.kind === FUNCTION_KIND && "sourcePath" in spec && "exportName" in spec) {
|
|
258
|
+
base._meta = {
|
|
259
|
+
...base._meta,
|
|
260
|
+
sourcePath: spec.sourcePath,
|
|
261
|
+
exportName: spec.exportName,
|
|
262
|
+
...projectPath && { projectPath }
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (spec.kind === SKILL_KIND && "sourcePath" in spec && projectPath) {
|
|
266
|
+
base._meta = { ...base._meta, sourcePath: spec.sourcePath, projectPath };
|
|
267
|
+
}
|
|
268
|
+
if (spec.kind === N8N_KIND && "sourcePath" in spec && projectPath) {
|
|
269
|
+
base._meta = { ...base._meta, sourcePath: spec.sourcePath, projectPath };
|
|
270
|
+
}
|
|
271
|
+
return base;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/tools/function/scanner.ts
|
|
239
275
|
var TOOL_TAG = "@tool";
|
|
240
276
|
var EFFECT_VALUES = ["none", "local_write", "external_write", "destructive"];
|
|
241
277
|
function scanForTools(options) {
|
|
242
|
-
const projectPath =
|
|
243
|
-
const tsconfigPath = options.tsconfigPath ??
|
|
278
|
+
const projectPath = path9.resolve(options.projectPath);
|
|
279
|
+
const tsconfigPath = options.tsconfigPath ?? path9.join(projectPath, "tsconfig.json");
|
|
244
280
|
const include = options.include ?? ["**/*.ts"];
|
|
245
281
|
const errors = [];
|
|
246
282
|
const warnings = [];
|
|
247
283
|
let config;
|
|
248
|
-
let configPathResolved =
|
|
284
|
+
let configPathResolved = path9.resolve(projectPath, tsconfigPath);
|
|
249
285
|
if (!fs2.existsSync(configPathResolved)) {
|
|
250
|
-
configPathResolved =
|
|
286
|
+
configPathResolved = path9.join(projectPath, "tsconfig.json");
|
|
251
287
|
}
|
|
252
288
|
if (fs2.existsSync(configPathResolved)) {
|
|
253
289
|
const configFile = ts2.readConfigFile(configPathResolved, ts2.sys.readFile);
|
|
@@ -258,7 +294,7 @@ function scanForTools(options) {
|
|
|
258
294
|
const parsed = ts2.parseJsonConfigFileContent(
|
|
259
295
|
configFile.config,
|
|
260
296
|
ts2.sys,
|
|
261
|
-
|
|
297
|
+
path9.dirname(configPathResolved)
|
|
262
298
|
);
|
|
263
299
|
if (parsed.errors.length) {
|
|
264
300
|
for (const e of parsed.errors) {
|
|
@@ -287,7 +323,7 @@ function scanForTools(options) {
|
|
|
287
323
|
for (const sourceFile of program.getSourceFiles()) {
|
|
288
324
|
const fileName = sourceFile.fileName;
|
|
289
325
|
if (fileName.includes("node_modules") || fileName.endsWith(".d.ts")) continue;
|
|
290
|
-
if (!config.fileNames.some((f) =>
|
|
326
|
+
if (!config.fileNames.some((f) => path9.resolve(f) === path9.resolve(fileName))) continue;
|
|
291
327
|
ts2.forEachChild(sourceFile, (node) => {
|
|
292
328
|
const decl = getExportedFunctionDeclaration(node);
|
|
293
329
|
if (!decl) return;
|
|
@@ -306,10 +342,10 @@ function scanForTools(options) {
|
|
|
306
342
|
const { schema } = buildInputSchemaFromParams(func, typeChecker, onWarn);
|
|
307
343
|
const inputSchema = Object.keys(schema.properties ?? {}).length > 0 ? schema : { type: "object", properties: {} };
|
|
308
344
|
const outputSchema = buildOutputSchemaFromReturnType(func, typeChecker, onWarn);
|
|
309
|
-
const sourcePath =
|
|
345
|
+
const sourcePath = path9.relative(projectPath, fileName) || path9.basename(fileName);
|
|
310
346
|
const toolName = pathToToolName(sourcePath, name);
|
|
311
347
|
specs.push({
|
|
312
|
-
kind:
|
|
348
|
+
kind: FUNCTION_KIND,
|
|
313
349
|
name: toolName,
|
|
314
350
|
description: description || humanize(name),
|
|
315
351
|
inputSchema,
|
|
@@ -326,20 +362,20 @@ function resolveGlob(projectPath, patterns) {
|
|
|
326
362
|
const result = [];
|
|
327
363
|
const seen = /* @__PURE__ */ new Set();
|
|
328
364
|
const add = (f) => {
|
|
329
|
-
const abs =
|
|
365
|
+
const abs = path9.resolve(f);
|
|
330
366
|
if (f.endsWith(".ts") && !f.endsWith(".d.ts") && !seen.has(abs)) {
|
|
331
367
|
seen.add(abs);
|
|
332
368
|
result.push(abs);
|
|
333
369
|
}
|
|
334
370
|
};
|
|
335
371
|
for (const p of patterns) {
|
|
336
|
-
const full =
|
|
372
|
+
const full = path9.join(projectPath, p);
|
|
337
373
|
if (full.includes("*")) {
|
|
338
374
|
const baseDir = full.replace(/\*\*\/.*$/, "").replace(/\*.*$/, "").replace(/\/?$/, "") || ".";
|
|
339
|
-
const dir =
|
|
375
|
+
const dir = path9.resolve(projectPath, baseDir);
|
|
340
376
|
if (fs2.existsSync(dir)) walk(dir, add);
|
|
341
377
|
} else {
|
|
342
|
-
const resolved =
|
|
378
|
+
const resolved = path9.resolve(projectPath, full);
|
|
343
379
|
if (fs2.existsSync(resolved)) {
|
|
344
380
|
if (fs2.statSync(resolved).isFile()) add(resolved);
|
|
345
381
|
else walk(resolved, add);
|
|
@@ -347,14 +383,14 @@ function resolveGlob(projectPath, patterns) {
|
|
|
347
383
|
}
|
|
348
384
|
}
|
|
349
385
|
if (result.length > 0) return result;
|
|
350
|
-
const srcDir =
|
|
386
|
+
const srcDir = path9.join(projectPath, "src");
|
|
351
387
|
if (fs2.existsSync(srcDir)) return walkCollect(srcDir);
|
|
352
388
|
return [];
|
|
353
389
|
}
|
|
354
390
|
function walkCollect(dir) {
|
|
355
391
|
const out = [];
|
|
356
392
|
walk(dir, (fullPath) => {
|
|
357
|
-
if (fullPath.endsWith(".ts") && !fullPath.endsWith(".d.ts")) out.push(
|
|
393
|
+
if (fullPath.endsWith(".ts") && !fullPath.endsWith(".d.ts")) out.push(path9.resolve(fullPath));
|
|
358
394
|
});
|
|
359
395
|
return out;
|
|
360
396
|
}
|
|
@@ -363,7 +399,7 @@ function walk(dir, visit) {
|
|
|
363
399
|
try {
|
|
364
400
|
const entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
365
401
|
for (const e of entries) {
|
|
366
|
-
const full =
|
|
402
|
+
const full = path9.join(dir, e.name);
|
|
367
403
|
if (e.isDirectory() && !SKIP_DIRS.has(e.name)) walk(full, visit);
|
|
368
404
|
else if (e.isFile()) visit(full);
|
|
369
405
|
}
|
|
@@ -463,12 +499,26 @@ function getEffect(host) {
|
|
|
463
499
|
function humanize(name) {
|
|
464
500
|
return name.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
|
|
465
501
|
}
|
|
502
|
+
function scan(projectPath, options = {}) {
|
|
503
|
+
const root = path9.resolve(projectPath);
|
|
504
|
+
const result = scanForTools({
|
|
505
|
+
projectPath: root,
|
|
506
|
+
include: options.include ?? ["**/*.ts"],
|
|
507
|
+
tsconfigPath: options.tsconfigPath
|
|
508
|
+
});
|
|
509
|
+
const specs = result.specs.map((s) => mcpSpecToToolSpec(s, root));
|
|
510
|
+
return Promise.resolve({
|
|
511
|
+
specs,
|
|
512
|
+
errors: result.errors,
|
|
513
|
+
warnings: result.warnings
|
|
514
|
+
});
|
|
515
|
+
}
|
|
466
516
|
|
|
467
|
-
// src/
|
|
517
|
+
// src/tools/skill/SkillManifest.ts
|
|
468
518
|
var SkillManifestError = class extends Error {
|
|
469
|
-
constructor(
|
|
470
|
-
super(`SKILL.md error in ${
|
|
471
|
-
this.path =
|
|
519
|
+
constructor(path12, field, message) {
|
|
520
|
+
super(`SKILL.md error in ${path12}: ${message}`);
|
|
521
|
+
this.path = path12;
|
|
472
522
|
this.field = field;
|
|
473
523
|
this.name = "SkillManifestError";
|
|
474
524
|
}
|
|
@@ -722,36 +772,38 @@ async function loadSkillDefinition(dirPath) {
|
|
|
722
772
|
skillMdPath
|
|
723
773
|
};
|
|
724
774
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
phase;
|
|
732
|
-
/** The underlying cause */
|
|
733
|
-
cause;
|
|
734
|
-
constructor(toolDir, phase, message, cause) {
|
|
735
|
-
super(`[${phase}] ${toolDir}: ${message}`);
|
|
736
|
-
this.name = "DiscoveryError";
|
|
737
|
-
this.toolDir = toolDir;
|
|
738
|
-
this.phase = phase;
|
|
739
|
-
this.cause = cause;
|
|
775
|
+
var DEFAULT_EXTENSIONS = [".js", ".mjs"];
|
|
776
|
+
async function resolveEntryPoint(dirPath, baseName, extensions = DEFAULT_EXTENSIONS) {
|
|
777
|
+
if (extensions.some((ext) => baseName.endsWith(ext))) {
|
|
778
|
+
const fullPath = join(dirPath, baseName);
|
|
779
|
+
await stat(fullPath);
|
|
780
|
+
return fullPath;
|
|
740
781
|
}
|
|
741
|
-
|
|
782
|
+
for (const ext of extensions) {
|
|
783
|
+
const fullPath = join(dirPath, `${baseName}${ext}`);
|
|
784
|
+
try {
|
|
785
|
+
await stat(fullPath);
|
|
786
|
+
return fullPath;
|
|
787
|
+
} catch {
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
throw new Error(
|
|
791
|
+
`Could not find entry point in ${dirPath}. Tried: ${extensions.map((e) => baseName + e).join(", ")}`
|
|
792
|
+
);
|
|
793
|
+
}
|
|
742
794
|
var defaultInputSchema = { type: "object", properties: {}, additionalProperties: true };
|
|
743
795
|
async function scanForSkill(projectPath) {
|
|
744
|
-
const projectRoot =
|
|
796
|
+
const projectRoot = path9.resolve(projectPath);
|
|
745
797
|
const dirs = await findDirsContainingFile(projectRoot, "SKILL.md");
|
|
746
798
|
const skills = [];
|
|
747
799
|
const errors = [];
|
|
748
800
|
for (const dirPath of dirs) {
|
|
749
|
-
const relativePath =
|
|
801
|
+
const relativePath = path9.relative(projectRoot, dirPath) || path9.basename(dirPath);
|
|
750
802
|
try {
|
|
751
803
|
const skillDef = await loadSkillDefinition(dirPath);
|
|
752
804
|
const name = pathToToolName(relativePath, skillDef.frontmatter.name);
|
|
753
805
|
skills.push({
|
|
754
|
-
kind:
|
|
806
|
+
kind: SKILL_KIND,
|
|
755
807
|
name,
|
|
756
808
|
description: skillDef.frontmatter.description,
|
|
757
809
|
inputSchema: defaultInputSchema,
|
|
@@ -764,6 +816,15 @@ async function scanForSkill(projectPath) {
|
|
|
764
816
|
}
|
|
765
817
|
return { skills, errors };
|
|
766
818
|
}
|
|
819
|
+
async function scan2(projectPath, _options = {}) {
|
|
820
|
+
const root = path9.resolve(projectPath);
|
|
821
|
+
const result = await scanForSkill(root);
|
|
822
|
+
const specs = result.skills.map((s) => mcpSpecToToolSpec(s, root));
|
|
823
|
+
return {
|
|
824
|
+
specs,
|
|
825
|
+
errors: result.errors.map((e) => ({ file: e.dir, message: e.message }))
|
|
826
|
+
};
|
|
827
|
+
}
|
|
767
828
|
async function readWorkflowMeta(dirPath, workflowFileName = "workflow.json") {
|
|
768
829
|
const workflowPath = join(dirPath, workflowFileName);
|
|
769
830
|
let raw;
|
|
@@ -822,20 +883,20 @@ async function loadN8nTool(dirPath, manifest) {
|
|
|
822
883
|
return { manifest, dirPath, workflowDef };
|
|
823
884
|
}
|
|
824
885
|
|
|
825
|
-
// src/
|
|
886
|
+
// src/tools/n8n/scanN8n.ts
|
|
826
887
|
var defaultInputSchema2 = { type: "object", properties: {}, additionalProperties: true };
|
|
827
888
|
async function scanForN8n(projectPath) {
|
|
828
|
-
const projectRoot =
|
|
889
|
+
const projectRoot = path9.resolve(projectPath);
|
|
829
890
|
const dirs = await findDirsContainingFile(projectRoot, "workflow.json");
|
|
830
891
|
const n8n = [];
|
|
831
892
|
const errors = [];
|
|
832
893
|
for (const dirPath of dirs) {
|
|
833
|
-
const relativePath =
|
|
894
|
+
const relativePath = path9.relative(projectRoot, dirPath) || path9.basename(dirPath);
|
|
834
895
|
try {
|
|
835
896
|
const { name: wfName, description: wfDesc, webhookUrl } = await readWorkflowMeta(dirPath);
|
|
836
897
|
const toolName = pathToToolName(relativePath, wfName);
|
|
837
898
|
n8n.push({
|
|
838
|
-
kind:
|
|
899
|
+
kind: N8N_KIND,
|
|
839
900
|
name: toolName,
|
|
840
901
|
description: wfDesc,
|
|
841
902
|
inputSchema: defaultInputSchema2,
|
|
@@ -849,38 +910,683 @@ async function scanForN8n(projectPath) {
|
|
|
849
910
|
}
|
|
850
911
|
return { n8n, errors };
|
|
851
912
|
}
|
|
913
|
+
async function scan3(projectPath, _options = {}) {
|
|
914
|
+
const root = path9.resolve(projectPath);
|
|
915
|
+
const result = await scanForN8n(root);
|
|
916
|
+
const specs = result.n8n.map((s) => mcpSpecToToolSpec(s, root));
|
|
917
|
+
return {
|
|
918
|
+
specs,
|
|
919
|
+
errors: result.errors.map((e) => ({ file: e.dir, message: e.message }))
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
async function scan4(projectPath, options = {}) {
|
|
923
|
+
const root = path9.resolve(projectPath);
|
|
924
|
+
const namespace = options.namespace ?? "dir";
|
|
925
|
+
const errors = [];
|
|
926
|
+
const scanner = new DirectoryScanner({
|
|
927
|
+
roots: [root],
|
|
928
|
+
namespace,
|
|
929
|
+
extensions: options.extensions,
|
|
930
|
+
onError: (dir, err) => {
|
|
931
|
+
errors.push({ file: dir, message: err.message });
|
|
932
|
+
options.onError?.(dir, err);
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
let specs;
|
|
936
|
+
try {
|
|
937
|
+
specs = await scanner.scan();
|
|
938
|
+
} catch (err) {
|
|
939
|
+
errors.push({
|
|
940
|
+
file: root,
|
|
941
|
+
message: err instanceof Error ? err.message : String(err)
|
|
942
|
+
});
|
|
943
|
+
return { specs: [], errors };
|
|
944
|
+
}
|
|
945
|
+
const filtered = specs.filter((s) => s.kind === MCP_KIND);
|
|
946
|
+
return { specs: filtered, errors };
|
|
947
|
+
}
|
|
948
|
+
async function scan5(projectPath, options = {}) {
|
|
949
|
+
const root = path9.resolve(projectPath);
|
|
950
|
+
const namespace = options.namespace ?? "dir";
|
|
951
|
+
const errors = [];
|
|
952
|
+
const scanner = new DirectoryScanner({
|
|
953
|
+
roots: [root],
|
|
954
|
+
namespace,
|
|
955
|
+
extensions: options.extensions,
|
|
956
|
+
onError: (dir, err) => {
|
|
957
|
+
errors.push({ file: dir, message: err.message });
|
|
958
|
+
options.onError?.(dir, err);
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
let specs;
|
|
962
|
+
try {
|
|
963
|
+
specs = await scanner.scan();
|
|
964
|
+
} catch (err) {
|
|
965
|
+
errors.push({
|
|
966
|
+
file: root,
|
|
967
|
+
message: err instanceof Error ? err.message : String(err)
|
|
968
|
+
});
|
|
969
|
+
return { specs: [], errors };
|
|
970
|
+
}
|
|
971
|
+
const filtered = specs.filter((s) => s.kind === LANGCHAIN_KIND);
|
|
972
|
+
return { specs: filtered, errors };
|
|
973
|
+
}
|
|
974
|
+
async function loadLangChainTool(dirPath, manifest, extensions) {
|
|
975
|
+
let entryFile;
|
|
976
|
+
try {
|
|
977
|
+
entryFile = await resolveEntryPoint(
|
|
978
|
+
dirPath,
|
|
979
|
+
manifest.entryPoint ?? "index",
|
|
980
|
+
extensions
|
|
981
|
+
);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
throw new DiscoveryError(
|
|
984
|
+
dirPath,
|
|
985
|
+
"load",
|
|
986
|
+
`Cannot find LangChain entry point`,
|
|
987
|
+
err
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
let mod;
|
|
991
|
+
try {
|
|
992
|
+
mod = await import(pathToFileURL(entryFile).href);
|
|
993
|
+
} catch (err) {
|
|
994
|
+
throw new DiscoveryError(
|
|
995
|
+
dirPath,
|
|
996
|
+
"load",
|
|
997
|
+
`Failed to import ${entryFile}`,
|
|
998
|
+
err
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
const tool = mod.default ?? mod.tool ?? mod;
|
|
1002
|
+
if (!tool || typeof tool.invoke !== "function") {
|
|
1003
|
+
throw new DiscoveryError(
|
|
1004
|
+
dirPath,
|
|
1005
|
+
"validate",
|
|
1006
|
+
`Entry point must export an object with invoke() method (LangChainToolLike)`
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
return { manifest, dirPath, impl: tool };
|
|
1010
|
+
}
|
|
1011
|
+
var DEFAULT_EXTENSIONS2 = [".js", ".mjs"];
|
|
1012
|
+
async function listSkillProgramFiles(dirPath, extensions = DEFAULT_EXTENSIONS2) {
|
|
1013
|
+
let entries;
|
|
1014
|
+
try {
|
|
1015
|
+
const dirEntries = await readdir(dirPath, { withFileTypes: true });
|
|
1016
|
+
entries = dirEntries.map((entry) => ({
|
|
1017
|
+
name: entry.name,
|
|
1018
|
+
isFile: entry.isFile()
|
|
1019
|
+
}));
|
|
1020
|
+
} catch {
|
|
1021
|
+
return [];
|
|
1022
|
+
}
|
|
1023
|
+
return entries.filter((e) => e.isFile).map((e) => e.name).filter((name) => {
|
|
1024
|
+
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
1025
|
+
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
1026
|
+
return extensions.some((ext) => name.endsWith(ext));
|
|
1027
|
+
}).sort((a, b) => {
|
|
1028
|
+
if (a === "handler.js" || a === "index.js") return -1;
|
|
1029
|
+
if (b === "handler.js" || b === "index.js") return 1;
|
|
1030
|
+
return a.localeCompare(b);
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
function isLangChainLikeTool(val) {
|
|
1034
|
+
return val != null && typeof val === "object" && "invoke" in val && typeof val.invoke === "function";
|
|
1035
|
+
}
|
|
1036
|
+
function isConstructable(val) {
|
|
1037
|
+
return typeof val === "function" && typeof val.prototype === "object";
|
|
1038
|
+
}
|
|
1039
|
+
async function loadOneSkillProgram(dirPath, manifest, entryFile, skillDef, programKey, extensions) {
|
|
1040
|
+
let impl;
|
|
1041
|
+
try {
|
|
1042
|
+
const fullPath = await resolveEntryPoint(dirPath, entryFile, extensions ?? [".js", ".mjs"]);
|
|
1043
|
+
const mod = await import(pathToFileURL(fullPath).href);
|
|
1044
|
+
const fn = mod.default ?? mod.handler ?? mod.Tool;
|
|
1045
|
+
if (isLangChainLikeTool(fn)) {
|
|
1046
|
+
impl = fn;
|
|
1047
|
+
} else if (isConstructable(fn)) {
|
|
1048
|
+
const instance = new fn();
|
|
1049
|
+
if (isLangChainLikeTool(instance)) impl = instance;
|
|
1050
|
+
} else if (typeof fn === "function") {
|
|
1051
|
+
impl = fn;
|
|
1052
|
+
}
|
|
1053
|
+
} catch {
|
|
1054
|
+
}
|
|
1055
|
+
return {
|
|
1056
|
+
manifest,
|
|
1057
|
+
dirPath,
|
|
1058
|
+
impl,
|
|
1059
|
+
skillDefinition: skillDef,
|
|
1060
|
+
programKey
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
async function loadSkillTools(dirPath, manifest, extensions) {
|
|
1064
|
+
let skillDef;
|
|
1065
|
+
try {
|
|
1066
|
+
skillDef = await loadSkillDefinition(dirPath);
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
throw new DiscoveryError(
|
|
1069
|
+
dirPath,
|
|
1070
|
+
"load",
|
|
1071
|
+
`Failed to parse SKILL.md: ${err.message}`,
|
|
1072
|
+
err
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
const programs = manifest.programs;
|
|
1076
|
+
if (programs && typeof programs === "object" && Object.keys(programs).length > 0) {
|
|
1077
|
+
const result = [];
|
|
1078
|
+
for (const [programKey, entryFile2] of Object.entries(programs)) {
|
|
1079
|
+
const loaded2 = await loadOneSkillProgram(
|
|
1080
|
+
dirPath,
|
|
1081
|
+
manifest,
|
|
1082
|
+
entryFile2,
|
|
1083
|
+
skillDef,
|
|
1084
|
+
programKey,
|
|
1085
|
+
extensions
|
|
1086
|
+
);
|
|
1087
|
+
result.push(loaded2);
|
|
1088
|
+
}
|
|
1089
|
+
return result;
|
|
1090
|
+
}
|
|
1091
|
+
const exts = extensions ?? DEFAULT_EXTENSIONS2;
|
|
1092
|
+
const files = await listSkillProgramFiles(dirPath, exts);
|
|
1093
|
+
if (files.length >= 2) {
|
|
1094
|
+
const result = [];
|
|
1095
|
+
for (let i = 0; i < files.length; i++) {
|
|
1096
|
+
const file = files[i];
|
|
1097
|
+
const programKey = i === 0 ? "default" : file.replace(/\.[^.]+$/, "");
|
|
1098
|
+
const loaded2 = await loadOneSkillProgram(
|
|
1099
|
+
dirPath,
|
|
1100
|
+
manifest,
|
|
1101
|
+
file,
|
|
1102
|
+
skillDef,
|
|
1103
|
+
programKey,
|
|
1104
|
+
extensions
|
|
1105
|
+
);
|
|
1106
|
+
result.push(loaded2);
|
|
1107
|
+
}
|
|
1108
|
+
return result;
|
|
1109
|
+
}
|
|
1110
|
+
const entryFile = manifest.entryPoint ?? files[0] ?? "handler";
|
|
1111
|
+
const loaded = await loadOneSkillProgram(
|
|
1112
|
+
dirPath,
|
|
1113
|
+
manifest,
|
|
1114
|
+
entryFile,
|
|
1115
|
+
skillDef,
|
|
1116
|
+
void 0,
|
|
1117
|
+
extensions
|
|
1118
|
+
);
|
|
1119
|
+
return [loaded];
|
|
1120
|
+
}
|
|
1121
|
+
async function listLangchainEntryFiles(dirPath, extensions) {
|
|
1122
|
+
let entries;
|
|
1123
|
+
try {
|
|
1124
|
+
const dirEntries = await readdir(dirPath, { withFileTypes: true });
|
|
1125
|
+
entries = dirEntries.map((entry) => ({
|
|
1126
|
+
name: entry.name,
|
|
1127
|
+
isFile: entry.isFile()
|
|
1128
|
+
}));
|
|
1129
|
+
} catch {
|
|
1130
|
+
return [];
|
|
1131
|
+
}
|
|
1132
|
+
return entries.filter((e) => e.isFile).map((e) => e.name).filter((name) => {
|
|
1133
|
+
if (name.startsWith(".") || name.startsWith("_")) return false;
|
|
1134
|
+
if (name.endsWith(".d.ts")) return false;
|
|
1135
|
+
if (name.includes(".test.") || name.includes(".spec.")) return false;
|
|
1136
|
+
return extensions.some((ext) => name.endsWith(ext));
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
async function loadLangChainToolsFromDir(dirPath, dirName, manifest, strict, namespace, extensions, langchainDirName, toSpec, onError) {
|
|
1140
|
+
const entryFiles = await listLangchainEntryFiles(dirPath, extensions);
|
|
1141
|
+
if (entryFiles.length === 0) {
|
|
1142
|
+
if (strict) {
|
|
1143
|
+
throw new DiscoveryError(dirPath, "load", "No LangChain entry files found");
|
|
1144
|
+
}
|
|
1145
|
+
return [];
|
|
1146
|
+
}
|
|
1147
|
+
const specs = [];
|
|
1148
|
+
const useDirNameForSingle = dirName !== langchainDirName;
|
|
1149
|
+
for (const entryFile of entryFiles) {
|
|
1150
|
+
const fileManifest = { ...manifest, entryPoint: entryFile };
|
|
1151
|
+
try {
|
|
1152
|
+
const loaded = await loadLangChainTool(dirPath, fileManifest, extensions);
|
|
1153
|
+
const fileBase = basename(entryFile).replace(/\.[^.]+$/, "");
|
|
1154
|
+
const nameHint = entryFiles.length === 1 && useDirNameForSingle ? dirName : fileBase;
|
|
1155
|
+
specs.push(toSpec(loaded, nameHint, dirPath, namespace));
|
|
1156
|
+
} catch (error) {
|
|
1157
|
+
const err = error;
|
|
1158
|
+
if (err instanceof DiscoveryError && err.phase === "validate") {
|
|
1159
|
+
if (strict) throw err;
|
|
1160
|
+
continue;
|
|
1161
|
+
}
|
|
1162
|
+
onError?.(join(dirPath, entryFile), err);
|
|
1163
|
+
if (strict) throw err;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return specs;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/tools/mcp/directoryApply.ts
|
|
1170
|
+
function applyLoadedToSpec(spec, loaded, _manifest, _defaultDirName, _namespace) {
|
|
1171
|
+
if (loaded.mcpConfig?.url) spec.endpoint = loaded.mcpConfig.url;
|
|
1172
|
+
spec.impl = loaded.mcpConfig;
|
|
1173
|
+
}
|
|
1174
|
+
var directoryMarker = {
|
|
1175
|
+
kind: "mcp",
|
|
1176
|
+
markerFile: "mcp.json",
|
|
1177
|
+
defaultEntryPoint: "mcp.json"
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
// src/tools/langchain/directoryApply.ts
|
|
1181
|
+
function applyLoadedToSpec2(spec, loaded, manifest, _defaultDirName, namespace) {
|
|
1182
|
+
spec.impl = loaded.impl;
|
|
1183
|
+
if (!manifest.name && loaded.impl) {
|
|
1184
|
+
const toolName = loaded.impl.name;
|
|
1185
|
+
if (toolName) spec.name = `${namespace}/${toolName}`;
|
|
1186
|
+
}
|
|
1187
|
+
if (!manifest.description && loaded.impl) {
|
|
1188
|
+
const d = loaded.impl.description;
|
|
1189
|
+
if (d) spec.description = d;
|
|
1190
|
+
}
|
|
1191
|
+
if (!manifest.inputSchema && loaded.impl) {
|
|
1192
|
+
const schema = loaded.impl.schema;
|
|
1193
|
+
if (schema) spec.inputSchema = schema;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// src/tools/skill/directoryApply.ts
|
|
1198
|
+
function applyLoadedToSpec3(spec, loaded, manifest, defaultDirName, namespace) {
|
|
1199
|
+
const skillDef = loaded.skillDefinition;
|
|
1200
|
+
if (skillDef) {
|
|
1201
|
+
spec.name = manifest.name ?? skillDef.frontmatter.name;
|
|
1202
|
+
spec.description = skillDef.frontmatter.description;
|
|
1203
|
+
if (loaded.programKey === "default") {
|
|
1204
|
+
spec.name = `${namespace}/${defaultDirName}`;
|
|
1205
|
+
} else if (loaded.programKey) {
|
|
1206
|
+
spec.name = `${namespace}/${defaultDirName}/${loaded.programKey}`;
|
|
1207
|
+
}
|
|
1208
|
+
const impl = loaded.impl;
|
|
1209
|
+
if (impl && typeof impl === "object" && typeof impl.invoke === "function") {
|
|
1210
|
+
if (impl.description != null && impl.description !== "")
|
|
1211
|
+
spec.description = impl.description;
|
|
1212
|
+
if (impl.schema != null && typeof impl.schema === "object")
|
|
1213
|
+
spec.inputSchema = impl.schema;
|
|
1214
|
+
}
|
|
1215
|
+
spec.impl = { ...skillDef, handler: loaded.impl };
|
|
1216
|
+
} else {
|
|
1217
|
+
spec.impl = loaded.impl;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
var directoryMarker2 = {
|
|
1221
|
+
kind: "skill",
|
|
1222
|
+
markerFile: "SKILL.md",
|
|
1223
|
+
defaultEntryPoint: "handler"
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
// src/tools/n8n/directoryApply.ts
|
|
1227
|
+
function applyLoadedToSpec4(spec, loaded, manifest, _defaultDirName, _namespace) {
|
|
1228
|
+
const workflow = loaded.workflowDef;
|
|
1229
|
+
if (workflow?.id) spec.resourceId = String(workflow.id);
|
|
1230
|
+
if (!manifest.description && workflow) {
|
|
1231
|
+
const d = workflow.description ?? workflow.meta?.description ?? (typeof workflow.name === "string" ? workflow.name : void 0);
|
|
1232
|
+
if (d) spec.description = d;
|
|
1233
|
+
}
|
|
1234
|
+
spec.impl = loaded.workflowDef;
|
|
1235
|
+
}
|
|
1236
|
+
var directoryMarker3 = {
|
|
1237
|
+
kind: "n8n",
|
|
1238
|
+
markerFile: "workflow.json",
|
|
1239
|
+
defaultEntryPoint: "workflow.json"
|
|
1240
|
+
};
|
|
852
1241
|
|
|
853
|
-
// src/
|
|
1242
|
+
// src/tools/discoveryFactory.ts
|
|
1243
|
+
var DiscoveryError = class extends Error {
|
|
1244
|
+
toolDir;
|
|
1245
|
+
phase;
|
|
1246
|
+
cause;
|
|
1247
|
+
constructor(toolDir, phase, message, cause) {
|
|
1248
|
+
super(`[${phase}] ${toolDir}: ${message}`);
|
|
1249
|
+
this.name = "DiscoveryError";
|
|
1250
|
+
this.toolDir = toolDir;
|
|
1251
|
+
this.phase = phase;
|
|
1252
|
+
this.cause = cause;
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
var DIRECTORY_KINDS = ["mcp", "langchain", "skill", "n8n"];
|
|
1256
|
+
var DIRECTORY_DISCOVERABLE_KINDS = DIRECTORY_KINDS;
|
|
1257
|
+
var DIRECTORY_KIND_MARKERS = [
|
|
1258
|
+
directoryMarker2,
|
|
1259
|
+
directoryMarker3,
|
|
1260
|
+
directoryMarker
|
|
1261
|
+
];
|
|
1262
|
+
var DIRECTORY_LOADERS = {
|
|
1263
|
+
mcp: async (dirPath, manifest) => [await loadMCPTool(dirPath, manifest)],
|
|
1264
|
+
langchain: async (dirPath, manifest, ext) => [await loadLangChainTool(dirPath, manifest, ext)],
|
|
1265
|
+
skill: (dirPath, manifest, ext) => loadSkillTools(dirPath, manifest, ext),
|
|
1266
|
+
n8n: async (dirPath, manifest) => [await loadN8nTool(dirPath, manifest)]
|
|
1267
|
+
};
|
|
1268
|
+
function getDirectoryLoader(kind) {
|
|
1269
|
+
const loader = DIRECTORY_LOADERS[kind];
|
|
1270
|
+
if (!loader) {
|
|
1271
|
+
throw new DiscoveryError("", "manifest", `Unknown directory tool kind: "${kind}"`);
|
|
1272
|
+
}
|
|
1273
|
+
return loader;
|
|
1274
|
+
}
|
|
1275
|
+
function applyDirectoryLoadedToSpec(spec, loaded, manifest, defaultDirName, namespace) {
|
|
1276
|
+
switch (manifest.kind) {
|
|
1277
|
+
case "mcp":
|
|
1278
|
+
return applyLoadedToSpec(spec, loaded);
|
|
1279
|
+
case "langchain":
|
|
1280
|
+
return applyLoadedToSpec2(spec, loaded, manifest, defaultDirName, namespace);
|
|
1281
|
+
case "skill":
|
|
1282
|
+
return applyLoadedToSpec3(spec, loaded, manifest, defaultDirName, namespace);
|
|
1283
|
+
case "n8n":
|
|
1284
|
+
return applyLoadedToSpec4(spec, loaded, manifest);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
async function discoverTools(type, projectPath, options = {}) {
|
|
1288
|
+
const root = path9.resolve(projectPath);
|
|
1289
|
+
switch (type) {
|
|
1290
|
+
case "function":
|
|
1291
|
+
return scan(root, options);
|
|
1292
|
+
case "skill":
|
|
1293
|
+
return scan2(root, options);
|
|
1294
|
+
case "n8n":
|
|
1295
|
+
return scan3(root, options);
|
|
1296
|
+
case "mcp":
|
|
1297
|
+
return scan4(root, options);
|
|
1298
|
+
case "langchain":
|
|
1299
|
+
return scan5(root, options);
|
|
1300
|
+
default: {
|
|
1301
|
+
const _ = type;
|
|
1302
|
+
return _;
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
var DEFAULT_EXTENSIONS3 = [".js", ".mjs"];
|
|
1307
|
+
var DirectoryScanner = class {
|
|
1308
|
+
roots;
|
|
1309
|
+
extensions;
|
|
1310
|
+
onError;
|
|
1311
|
+
constructor(options) {
|
|
1312
|
+
const defaultNamespace = options.namespace ?? "dir";
|
|
1313
|
+
this.roots = options.roots.map((root) => {
|
|
1314
|
+
if (typeof root === "string") {
|
|
1315
|
+
return { path: root, namespace: defaultNamespace };
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
path: root.path,
|
|
1319
|
+
namespace: root.namespace ?? defaultNamespace
|
|
1320
|
+
};
|
|
1321
|
+
});
|
|
1322
|
+
this.extensions = options.extensions ?? DEFAULT_EXTENSIONS3;
|
|
1323
|
+
this.onError = options.onError;
|
|
1324
|
+
}
|
|
1325
|
+
async scan() {
|
|
1326
|
+
const specs = [];
|
|
1327
|
+
for (const root of this.roots) {
|
|
1328
|
+
const rootSpecs = await this.scanRoot(root.path, root.namespace);
|
|
1329
|
+
specs.push(...rootSpecs);
|
|
1330
|
+
}
|
|
1331
|
+
return specs;
|
|
1332
|
+
}
|
|
1333
|
+
async scanRoot(rootPath, namespace) {
|
|
1334
|
+
return this.scanRecursive(rootPath, namespace);
|
|
1335
|
+
}
|
|
1336
|
+
async scanRecursive(dirPath, namespace) {
|
|
1337
|
+
const specs = [];
|
|
1338
|
+
let dirEntries;
|
|
1339
|
+
try {
|
|
1340
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
1341
|
+
dirEntries = entries.map((entry) => ({
|
|
1342
|
+
name: entry.name,
|
|
1343
|
+
isDirectory: entry.isDirectory()
|
|
1344
|
+
}));
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
this.onError?.(dirPath, error);
|
|
1347
|
+
return specs;
|
|
1348
|
+
}
|
|
1349
|
+
const dirName = basename(dirPath);
|
|
1350
|
+
try {
|
|
1351
|
+
const loadedSpecs = await this.loadToolDir(dirPath, dirName, namespace);
|
|
1352
|
+
if (loadedSpecs.length > 0) specs.push(...loadedSpecs);
|
|
1353
|
+
} catch (error) {
|
|
1354
|
+
this.onError?.(dirPath, error);
|
|
1355
|
+
}
|
|
1356
|
+
for (const entry of dirEntries) {
|
|
1357
|
+
if (!entry.isDirectory) continue;
|
|
1358
|
+
const childPath = join(dirPath, entry.name);
|
|
1359
|
+
try {
|
|
1360
|
+
const childSpecs = await this.scanRecursive(childPath, namespace);
|
|
1361
|
+
specs.push(...childSpecs);
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
this.onError?.(childPath, error);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
return specs;
|
|
1367
|
+
}
|
|
1368
|
+
async loadToolDir(dirPath, dirName, namespace) {
|
|
1369
|
+
const manifestPath = join(dirPath, "tool.json");
|
|
1370
|
+
let manifestRaw;
|
|
1371
|
+
try {
|
|
1372
|
+
manifestRaw = await readFile(manifestPath, "utf-8");
|
|
1373
|
+
} catch {
|
|
1374
|
+
const inferred = await this.inferManifest(dirPath, dirName);
|
|
1375
|
+
if (!inferred) return [];
|
|
1376
|
+
if (inferred.kind === "langchain") {
|
|
1377
|
+
if (inferred.entryPoint) {
|
|
1378
|
+
const loaded3 = await loadLangChainTool(dirPath, inferred, this.extensions);
|
|
1379
|
+
return [this.toToolSpec(loaded3, dirName, dirPath, namespace)];
|
|
1380
|
+
}
|
|
1381
|
+
return loadLangChainToolsFromDir(
|
|
1382
|
+
dirPath,
|
|
1383
|
+
dirName,
|
|
1384
|
+
inferred,
|
|
1385
|
+
false,
|
|
1386
|
+
namespace,
|
|
1387
|
+
this.extensions,
|
|
1388
|
+
LANGCHAIN_DIR_NAME,
|
|
1389
|
+
(loaded3, nameHint, dp, ns) => this.toToolSpec(loaded3, nameHint, dp, ns),
|
|
1390
|
+
this.onError
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
if (inferred.kind === "skill") {
|
|
1394
|
+
const loadedList = await loadSkillTools(dirPath, inferred, this.extensions);
|
|
1395
|
+
return loadedList.map(
|
|
1396
|
+
(loaded3) => this.toToolSpec(loaded3, dirName, dirPath, namespace)
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
const loaded2 = await this.loadByKind(dirPath, inferred);
|
|
1400
|
+
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
1401
|
+
}
|
|
1402
|
+
let manifest;
|
|
1403
|
+
try {
|
|
1404
|
+
manifest = JSON.parse(manifestRaw);
|
|
1405
|
+
} catch (err) {
|
|
1406
|
+
throw new DiscoveryError(dirPath, "manifest", "Invalid JSON in tool.json", err);
|
|
1407
|
+
}
|
|
1408
|
+
if (!manifest.kind) {
|
|
1409
|
+
throw new DiscoveryError(dirPath, "manifest", `tool.json must have a "kind" field`);
|
|
1410
|
+
}
|
|
1411
|
+
if (manifest.enabled === false) return [];
|
|
1412
|
+
if (manifest.kind === "langchain") {
|
|
1413
|
+
if (manifest.entryPoint) {
|
|
1414
|
+
const loaded2 = await loadLangChainTool(dirPath, manifest, this.extensions);
|
|
1415
|
+
return [this.toToolSpec(loaded2, dirName, dirPath, namespace)];
|
|
1416
|
+
}
|
|
1417
|
+
return loadLangChainToolsFromDir(
|
|
1418
|
+
dirPath,
|
|
1419
|
+
dirName,
|
|
1420
|
+
manifest,
|
|
1421
|
+
true,
|
|
1422
|
+
namespace,
|
|
1423
|
+
this.extensions,
|
|
1424
|
+
LANGCHAIN_DIR_NAME,
|
|
1425
|
+
(loaded2, nameHint, dp, ns) => this.toToolSpec(loaded2, nameHint, dp, ns),
|
|
1426
|
+
this.onError
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
if (manifest.kind === "skill") {
|
|
1430
|
+
const loadedList = await loadSkillTools(dirPath, manifest, this.extensions);
|
|
1431
|
+
return loadedList.map(
|
|
1432
|
+
(loaded2) => this.toToolSpec(loaded2, dirName, dirPath, namespace)
|
|
1433
|
+
);
|
|
1434
|
+
}
|
|
1435
|
+
const loaded = await this.loadByKind(dirPath, manifest);
|
|
1436
|
+
return [this.toToolSpec(loaded, dirName, dirPath, namespace)];
|
|
1437
|
+
}
|
|
1438
|
+
async inferManifest(dirPath, dirName) {
|
|
1439
|
+
const kinds = [];
|
|
1440
|
+
for (const m of DIRECTORY_KIND_MARKERS) {
|
|
1441
|
+
if (await this.fileExists(join(dirPath, m.markerFile))) kinds.push(m.kind);
|
|
1442
|
+
}
|
|
1443
|
+
const isLangchainDir = dirName === LANGCHAIN_DIR_NAME;
|
|
1444
|
+
const hasLangchain = isLangchainDir ? (await listLangchainEntryFiles(dirPath, this.extensions)).length > 0 : dirName !== SKILL_DIR_NAME && await this.hasEntryPoint(dirPath, "index");
|
|
1445
|
+
if (hasLangchain) kinds.push("langchain");
|
|
1446
|
+
if (kinds.length === 0) return null;
|
|
1447
|
+
if (kinds.length > 1) {
|
|
1448
|
+
throw new DiscoveryError(
|
|
1449
|
+
dirPath,
|
|
1450
|
+
"manifest",
|
|
1451
|
+
`Ambiguous tool kind (found ${kinds.join(", ")}). Add tool.json to disambiguate.`
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
const kind = kinds[0];
|
|
1455
|
+
const manifest = { kind };
|
|
1456
|
+
const marker = DIRECTORY_KIND_MARKERS.find((m) => m.kind === kind);
|
|
1457
|
+
if (marker) {
|
|
1458
|
+
manifest.entryPoint = marker.defaultEntryPoint;
|
|
1459
|
+
}
|
|
1460
|
+
if (kind === "langchain" && !isLangchainDir) manifest.entryPoint = "index";
|
|
1461
|
+
return manifest;
|
|
1462
|
+
}
|
|
1463
|
+
async fileExists(path12) {
|
|
1464
|
+
try {
|
|
1465
|
+
await access(path12);
|
|
1466
|
+
return true;
|
|
1467
|
+
} catch {
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
async hasEntryPoint(dirPath, baseName) {
|
|
1472
|
+
try {
|
|
1473
|
+
await resolveEntryPoint(dirPath, baseName, this.extensions);
|
|
1474
|
+
return true;
|
|
1475
|
+
} catch {
|
|
1476
|
+
return false;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
async loadByKind(dirPath, manifest) {
|
|
1480
|
+
const kind = manifest.kind;
|
|
1481
|
+
const loader = getDirectoryLoader(kind);
|
|
1482
|
+
const result = await loader(dirPath, manifest, this.extensions);
|
|
1483
|
+
const list = Array.isArray(result) ? result : [result];
|
|
1484
|
+
if (list.length === 0) {
|
|
1485
|
+
throw new DiscoveryError(dirPath, "load", "No tools loaded", new Error("empty"));
|
|
1486
|
+
}
|
|
1487
|
+
return list[0];
|
|
1488
|
+
}
|
|
1489
|
+
toToolSpec(loaded, dirName, dirPath, namespace) {
|
|
1490
|
+
const { manifest } = loaded;
|
|
1491
|
+
const kindDirNames = new Set(DIRECTORY_DISCOVERABLE_KINDS);
|
|
1492
|
+
const parentName = basename(join(dirPath, ".."));
|
|
1493
|
+
const isKindDir = kindDirNames.has(dirName);
|
|
1494
|
+
const defaultDirName = isKindDir ? parentName : dirName;
|
|
1495
|
+
const inferredName = isKindDir ? `${namespace}/${defaultDirName}-${dirName}` : `${namespace}/${defaultDirName}`;
|
|
1496
|
+
const name = manifest.name ?? inferredName;
|
|
1497
|
+
const spec = this.buildBaseSpec(manifest, name, dirName);
|
|
1498
|
+
applyDirectoryLoadedToSpec(spec, loaded, manifest, defaultDirName, namespace);
|
|
1499
|
+
return spec;
|
|
1500
|
+
}
|
|
1501
|
+
buildBaseSpec(manifest, name, dirName) {
|
|
1502
|
+
return {
|
|
1503
|
+
name,
|
|
1504
|
+
version: manifest.version ?? "1.0.0",
|
|
1505
|
+
kind: manifest.kind,
|
|
1506
|
+
description: manifest.description ?? `${manifest.kind} tool: ${dirName}`,
|
|
1507
|
+
tags: manifest.tags,
|
|
1508
|
+
inputSchema: manifest.inputSchema ?? { type: "object", additionalProperties: true },
|
|
1509
|
+
outputSchema: manifest.outputSchema ?? { type: "object", additionalProperties: true },
|
|
1510
|
+
capabilities: manifest.capabilities ?? [],
|
|
1511
|
+
costHints: manifest.costHints
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
// src/tools/mcp/MCPLoader.ts
|
|
1517
|
+
function isCursorFormat(obj) {
|
|
1518
|
+
return typeof obj === "object" && obj !== null && "mcpServers" in obj && typeof obj.mcpServers === "object" && obj.mcpServers !== null;
|
|
1519
|
+
}
|
|
1520
|
+
function extractMCPConfig(parsed, toolName) {
|
|
1521
|
+
if (isCursorFormat(parsed)) {
|
|
1522
|
+
const servers = parsed.mcpServers;
|
|
1523
|
+
const keys = Object.keys(servers);
|
|
1524
|
+
if (keys.length === 0) {
|
|
1525
|
+
return {};
|
|
1526
|
+
}
|
|
1527
|
+
const name = toolName && keys.includes(toolName) ? toolName : keys[0];
|
|
1528
|
+
return servers[name];
|
|
1529
|
+
}
|
|
1530
|
+
return parsed;
|
|
1531
|
+
}
|
|
1532
|
+
async function loadMCPTool(dirPath, manifest) {
|
|
1533
|
+
const mcpPath = join(dirPath, manifest.entryPoint ?? "mcp.json");
|
|
1534
|
+
let raw;
|
|
1535
|
+
try {
|
|
1536
|
+
raw = await readFile(mcpPath, "utf-8");
|
|
1537
|
+
} catch (err) {
|
|
1538
|
+
throw new DiscoveryError(
|
|
1539
|
+
dirPath,
|
|
1540
|
+
"load",
|
|
1541
|
+
`Failed to read MCP config: ${mcpPath}`,
|
|
1542
|
+
err
|
|
1543
|
+
);
|
|
1544
|
+
}
|
|
1545
|
+
let parsed;
|
|
1546
|
+
try {
|
|
1547
|
+
parsed = JSON.parse(raw);
|
|
1548
|
+
} catch (err) {
|
|
1549
|
+
throw new DiscoveryError(
|
|
1550
|
+
dirPath,
|
|
1551
|
+
"load",
|
|
1552
|
+
`Invalid JSON in ${mcpPath}`,
|
|
1553
|
+
err
|
|
1554
|
+
);
|
|
1555
|
+
}
|
|
1556
|
+
const baseName = manifest.name?.split("/").pop();
|
|
1557
|
+
const config = extractMCPConfig(parsed, baseName);
|
|
1558
|
+
if (!config.command && !config.url) {
|
|
1559
|
+
throw new DiscoveryError(
|
|
1560
|
+
dirPath,
|
|
1561
|
+
"validate",
|
|
1562
|
+
`mcp.json must have either "command" or "url" field`
|
|
1563
|
+
);
|
|
1564
|
+
}
|
|
1565
|
+
return { manifest, dirPath, mcpConfig: config };
|
|
1566
|
+
}
|
|
854
1567
|
async function scanForAllTools(projectPath, options = {}) {
|
|
855
1568
|
const include = options.include ?? ["**/*.ts"];
|
|
856
1569
|
const tsconfigPath = options.tsconfigPath;
|
|
857
1570
|
const includeN8n = options.includeN8n === true;
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
1571
|
+
const opts = { include, tsconfigPath };
|
|
1572
|
+
const results = await Promise.all([
|
|
1573
|
+
discoverTools("function", projectPath, opts),
|
|
1574
|
+
discoverTools("skill", projectPath, opts),
|
|
1575
|
+
...includeN8n ? [discoverTools("n8n", projectPath, opts)] : []
|
|
862
1576
|
]);
|
|
863
|
-
const specs =
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
...n8nResult.n8n
|
|
867
|
-
];
|
|
868
|
-
const errors = [
|
|
869
|
-
...functionResult.errors,
|
|
870
|
-
...skillResult.errors.map((e) => ({ file: e.dir, message: e.message })),
|
|
871
|
-
...includeN8n ? n8nResult.errors.map((e) => ({ file: e.dir, message: e.message })) : []
|
|
872
|
-
];
|
|
873
|
-
const warnings = [...functionResult.warnings];
|
|
1577
|
+
const specs = results.flatMap((r) => r.specs);
|
|
1578
|
+
const errors = results.flatMap((r) => r.errors);
|
|
1579
|
+
const warnings = results.flatMap((r) => r.warnings ?? []);
|
|
874
1580
|
return { specs, errors, warnings };
|
|
875
1581
|
}
|
|
876
|
-
var __dirname$1 =
|
|
1582
|
+
var __dirname$1 = path9.dirname(fileURLToPath(import.meta.url));
|
|
877
1583
|
async function loadTemplate(name) {
|
|
878
1584
|
for (const dir of [
|
|
879
|
-
|
|
880
|
-
|
|
1585
|
+
path9.join(__dirname$1, "templates"),
|
|
1586
|
+
path9.join(__dirname$1, "..", "templates")
|
|
881
1587
|
]) {
|
|
882
1588
|
try {
|
|
883
|
-
return await fs3.readFile(
|
|
1589
|
+
return await fs3.readFile(path9.join(dir, name), "utf-8");
|
|
884
1590
|
} catch {
|
|
885
1591
|
continue;
|
|
886
1592
|
}
|
|
@@ -895,14 +1601,14 @@ var TEMPLATE_NAMES = {
|
|
|
895
1601
|
};
|
|
896
1602
|
function buildToolIndexCases(specs, fromGeneratedToProject) {
|
|
897
1603
|
return specs.map((s) => {
|
|
898
|
-
const modPath =
|
|
899
|
-
return ` case "${s.name}": return (await import("${modPath}")).${s.exportName};`;
|
|
1604
|
+
const modPath = path9.join(fromGeneratedToProject, s._meta.sourcePath).replace(/\\/g, "/");
|
|
1605
|
+
return ` case "${s.name}": return (await import("${modPath}")).${s._meta.exportName};`;
|
|
900
1606
|
}).join("\n");
|
|
901
1607
|
}
|
|
902
1608
|
function buildSkillInvokerCases(specs, fromGeneratedToProject) {
|
|
903
1609
|
return specs.map((s) => {
|
|
904
|
-
const handlerPath =
|
|
905
|
-
const descEscaped = s.description.replace(/"/g, '\\"');
|
|
1610
|
+
const handlerPath = path9.join(fromGeneratedToProject, s._meta.sourcePath, "handler").replace(/\\/g, "/");
|
|
1611
|
+
const descEscaped = (s.description ?? "").replace(/"/g, '\\"');
|
|
906
1612
|
return ` case "${s.name}": {
|
|
907
1613
|
const mod = await import("${handlerPath}.js").catch(() => import("${handlerPath}.mjs"));
|
|
908
1614
|
const fn = mod.default ?? mod.handler;
|
|
@@ -915,7 +1621,8 @@ function buildSkillInvokerCases(specs, fromGeneratedToProject) {
|
|
|
915
1621
|
}
|
|
916
1622
|
function buildN8nInvokerCases(specs) {
|
|
917
1623
|
return specs.map((s) => {
|
|
918
|
-
const
|
|
1624
|
+
const webhookUrl = s.endpoint;
|
|
1625
|
+
const url = webhookUrl ? `"${webhookUrl}"` : "process.env.N8N_WEBHOOK_" + s.name.replace(/[^a-zA-Z0-9]/g, "_").toUpperCase() + " ?? null";
|
|
919
1626
|
return ` case "${s.name}": {
|
|
920
1627
|
const url = ${url};
|
|
921
1628
|
if (!url) throw new Error("n8n webhook not configured for ${s.name}. Set N8N_WEBHOOK_* or add webhook to workflow.");
|
|
@@ -928,32 +1635,39 @@ function buildN8nInvokerCases(specs) {
|
|
|
928
1635
|
async function generate(options) {
|
|
929
1636
|
const { specs, outDir, projectPath } = options;
|
|
930
1637
|
await fs3.mkdir(outDir, { recursive: true });
|
|
931
|
-
const functionSpecs = specs.filter(
|
|
932
|
-
|
|
933
|
-
|
|
1638
|
+
const functionSpecs = specs.filter(
|
|
1639
|
+
(s) => s.kind === FUNCTION_KIND && s._meta?.sourcePath != null && s._meta?.exportName != null
|
|
1640
|
+
);
|
|
1641
|
+
const skillSpecs = specs.filter(
|
|
1642
|
+
(s) => s.kind === SKILL_KIND && s._meta?.sourcePath != null
|
|
1643
|
+
);
|
|
1644
|
+
const n8nSpecs = specs.filter((s) => s.kind === N8N_KIND);
|
|
934
1645
|
const toolSpecsJson = specs.map((s) => ({
|
|
935
1646
|
kind: s.kind,
|
|
936
1647
|
name: s.name,
|
|
937
1648
|
description: s.description,
|
|
938
1649
|
inputSchema: s.inputSchema,
|
|
939
|
-
...s.kind ===
|
|
1650
|
+
...s.kind === FUNCTION_KIND && s._meta?.sourcePath != null && s._meta?.exportName != null && {
|
|
940
1651
|
outputSchema: s.outputSchema ?? { type: "object", additionalProperties: true },
|
|
941
|
-
sourcePath: s.sourcePath,
|
|
942
|
-
exportName: s.exportName
|
|
1652
|
+
sourcePath: s._meta.sourcePath,
|
|
1653
|
+
exportName: s._meta.exportName
|
|
943
1654
|
},
|
|
944
1655
|
_meta: s._meta,
|
|
945
|
-
...s.kind ===
|
|
946
|
-
...s.kind ===
|
|
1656
|
+
...s.kind === SKILL_KIND && s._meta?.sourcePath != null && { sourcePath: s._meta.sourcePath },
|
|
1657
|
+
...s.kind === N8N_KIND && {
|
|
1658
|
+
sourcePath: s._meta?.sourcePath,
|
|
1659
|
+
webhookUrl: s.endpoint
|
|
1660
|
+
}
|
|
947
1661
|
}));
|
|
948
1662
|
await fs3.writeFile(
|
|
949
|
-
|
|
1663
|
+
path9.join(outDir, "tool-specs.json"),
|
|
950
1664
|
JSON.stringify(toolSpecsJson, null, 2),
|
|
951
1665
|
"utf-8"
|
|
952
1666
|
);
|
|
953
|
-
const configJson = { projectPath:
|
|
954
|
-
await fs3.writeFile(
|
|
955
|
-
const rel =
|
|
956
|
-
const fromGeneratedToProject = rel.split(
|
|
1667
|
+
const configJson = { projectPath: path9.resolve(projectPath) };
|
|
1668
|
+
await fs3.writeFile(path9.join(outDir, "config.json"), JSON.stringify(configJson, null, 2), "utf-8");
|
|
1669
|
+
const rel = path9.relative(outDir, projectPath) || ".";
|
|
1670
|
+
const fromGeneratedToProject = rel.split(path9.sep).length ? rel : ".";
|
|
957
1671
|
const [mcpServerTemplate, toolIndexTemplate, skillInvokerTemplate, n8nInvokerTemplate] = await Promise.all([
|
|
958
1672
|
loadTemplate(TEMPLATE_NAMES.mcpServer),
|
|
959
1673
|
loadTemplate(TEMPLATE_NAMES.toolIndex),
|
|
@@ -961,21 +1675,21 @@ async function generate(options) {
|
|
|
961
1675
|
loadTemplate(TEMPLATE_NAMES.n8nInvoker)
|
|
962
1676
|
]);
|
|
963
1677
|
const toolIndexTs = toolIndexTemplate.replace("{{CASES}}", buildToolIndexCases(functionSpecs, fromGeneratedToProject));
|
|
964
|
-
await fs3.writeFile(
|
|
1678
|
+
await fs3.writeFile(path9.join(outDir, "tool-index.ts"), toolIndexTs, "utf-8");
|
|
965
1679
|
const skillCases = buildSkillInvokerCases(skillSpecs, fromGeneratedToProject);
|
|
966
1680
|
const skillDefaultCase = skillSpecs.length === 0 ? "default: throw new Error('Unknown skill: ' + name);" : 'default: throw new Error("Unknown skill: " + name);';
|
|
967
1681
|
const skillInvokerTs = skillInvokerTemplate.replace("{{CASES}}", skillCases).replace("{{DEFAULT_CASE}}", skillDefaultCase);
|
|
968
|
-
await fs3.writeFile(
|
|
1682
|
+
await fs3.writeFile(path9.join(outDir, "skill-invoker.ts"), skillInvokerTs, "utf-8");
|
|
969
1683
|
const n8nCases = buildN8nInvokerCases(n8nSpecs);
|
|
970
1684
|
const n8nDefaultCase = n8nSpecs.length === 0 ? "default: throw new Error('Unknown n8n tool: ' + name);" : 'default: throw new Error("Unknown n8n tool: " + name);';
|
|
971
1685
|
const n8nInvokerTs = n8nInvokerTemplate.replace("{{CASES}}", n8nCases).replace("{{DEFAULT_CASE}}", n8nDefaultCase);
|
|
972
|
-
await fs3.writeFile(
|
|
973
|
-
await fs3.writeFile(
|
|
1686
|
+
await fs3.writeFile(path9.join(outDir, "n8n-invoker.ts"), n8nInvokerTs, "utf-8");
|
|
1687
|
+
await fs3.writeFile(path9.join(outDir, "mcp-server.ts"), mcpServerTemplate, "utf-8");
|
|
974
1688
|
const mcpJson = {
|
|
975
1689
|
command: "npx",
|
|
976
|
-
args: ["-y", "tsx",
|
|
1690
|
+
args: ["-y", "tsx", path9.join(outDir, "mcp-server.ts")]
|
|
977
1691
|
};
|
|
978
|
-
await fs3.writeFile(
|
|
1692
|
+
await fs3.writeFile(path9.join(outDir, "mcp.json"), JSON.stringify(mcpJson, null, 2), "utf-8");
|
|
979
1693
|
const packageJson = {
|
|
980
1694
|
name: "function-tools-mcp",
|
|
981
1695
|
version: "1.0.0",
|
|
@@ -989,17 +1703,17 @@ async function generate(options) {
|
|
|
989
1703
|
tsx: ">=4.0.0"
|
|
990
1704
|
}
|
|
991
1705
|
};
|
|
992
|
-
await fs3.writeFile(
|
|
1706
|
+
await fs3.writeFile(path9.join(outDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
|
|
993
1707
|
return {
|
|
994
|
-
entryPath:
|
|
995
|
-
mcpJsonPath:
|
|
1708
|
+
entryPath: path9.join(outDir, "mcp-server.ts"),
|
|
1709
|
+
mcpJsonPath: path9.join(outDir, "mcp.json")
|
|
996
1710
|
};
|
|
997
1711
|
}
|
|
998
1712
|
|
|
999
|
-
// src/
|
|
1713
|
+
// src/api/expose/mcp-build/build.ts
|
|
1000
1714
|
async function buildMcpPackage(options = {}) {
|
|
1001
|
-
const projectPath =
|
|
1002
|
-
const outDir =
|
|
1715
|
+
const projectPath = path9.resolve(options.projectPath ?? process.cwd());
|
|
1716
|
+
const outDir = path9.resolve(projectPath, options.outDir ?? "dist");
|
|
1003
1717
|
const include = options.include ?? ["**/*.ts"];
|
|
1004
1718
|
const tsconfigPath = options.tsconfigPath;
|
|
1005
1719
|
const scanResult = await scanForAllTools(projectPath, {
|
|
@@ -1033,12 +1747,12 @@ var buildFunctionToTool = buildMcpPackage;
|
|
|
1033
1747
|
async function runMcpServer(options = {}) {
|
|
1034
1748
|
const base = options.path ?? process.cwd();
|
|
1035
1749
|
const candidates = [
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1750
|
+
path9.join(base, "mcp-server.ts"),
|
|
1751
|
+
path9.join(base, "mcp-server.js"),
|
|
1752
|
+
path9.join(base, "dist", "mcp-server.ts"),
|
|
1753
|
+
path9.join(base, "dist", "mcp-server.js"),
|
|
1754
|
+
path9.join(base, "generated", "mcp-server.ts"),
|
|
1755
|
+
path9.join(base, "generated", "mcp-server.js")
|
|
1042
1756
|
];
|
|
1043
1757
|
let entry = "";
|
|
1044
1758
|
for (const p of candidates) {
|
|
@@ -1054,8 +1768,8 @@ async function runMcpServer(options = {}) {
|
|
|
1054
1768
|
`MCP entrypoint not found. Run "agent-tool build" first, or pass --path to a directory containing mcp-server.ts. Tried: ${candidates.join(", ")}`
|
|
1055
1769
|
);
|
|
1056
1770
|
}
|
|
1057
|
-
const dir =
|
|
1058
|
-
const child = spawn("npx", ["-y", "tsx",
|
|
1771
|
+
const dir = path9.dirname(entry);
|
|
1772
|
+
const child = spawn("npx", ["-y", "tsx", path9.basename(entry)], {
|
|
1059
1773
|
cwd: dir,
|
|
1060
1774
|
stdio: ["pipe", "pipe", "inherit"],
|
|
1061
1775
|
shell: false
|
|
@@ -1064,6 +1778,6 @@ async function runMcpServer(options = {}) {
|
|
|
1064
1778
|
}
|
|
1065
1779
|
var runGeneratedMCP = runMcpServer;
|
|
1066
1780
|
|
|
1067
|
-
export { DiscoveryError, SkillManifestError, buildFunctionToTool, buildMcpPackage, initProject,
|
|
1068
|
-
//# sourceMappingURL=chunk-
|
|
1069
|
-
//# sourceMappingURL=chunk-
|
|
1781
|
+
export { DirectoryScanner, DiscoveryError, SkillManifestError, buildFunctionToTool, buildMcpPackage, initProject, loadMCPTool, loadSkillDefinition, parseSkillMd, runGeneratedMCP, runMcpServer, scan, scanForTools, scanSkillResources, validateFrontmatter };
|
|
1782
|
+
//# sourceMappingURL=chunk-PJ4RUBZL.js.map
|
|
1783
|
+
//# sourceMappingURL=chunk-PJ4RUBZL.js.map
|