opentool 0.10.1 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.d.ts +3 -4
- package/dist/cli/index.js +93 -78
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +436 -417
- package/dist/index.js.map +1 -1
- package/dist/payment-orkZA9se.d.ts +96 -0
- package/dist/{validate-BgNU5laL.d.ts → validate-DbhJ_r0Z.d.ts} +1 -1
- package/dist/x402/index.d.ts +2 -96
- package/dist/x402/index.js +157 -157
- package/dist/x402/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/base/package.json +1 -1
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { M as Metadata, I as InternalToolDefinition } from '../validate-
|
|
3
|
-
export { G as GenerateMetadataOptions, a as GenerateMetadataResult, V as ValidateOptions, g as generateMetadata, b as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, c as validateFullCommand } from '../validate-
|
|
2
|
+
import { M as Metadata, I as InternalToolDefinition } from '../validate-DbhJ_r0Z.js';
|
|
3
|
+
export { G as GenerateMetadataOptions, a as GenerateMetadataResult, V as ValidateOptions, g as generateMetadata, b as generateMetadataCommand, l as loadAndValidateTools, v as validateCommand, c as validateFullCommand } from '../validate-DbhJ_r0Z.js';
|
|
4
4
|
import 'zod';
|
|
5
|
-
import '../
|
|
6
|
-
import 'viem';
|
|
5
|
+
import '../payment-orkZA9se.js';
|
|
7
6
|
|
|
8
7
|
interface BuildOptions {
|
|
9
8
|
input: string;
|
package/dist/cli/index.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as path6 from 'path';
|
|
3
|
-
import path6__default from 'path';
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
2
|
import { program } from 'commander';
|
|
6
3
|
import * as fs4 from 'fs';
|
|
7
4
|
import { promises } from 'fs';
|
|
5
|
+
import * as path5 from 'path';
|
|
8
6
|
import { tmpdir } from 'os';
|
|
9
7
|
import { build } from 'esbuild';
|
|
10
8
|
import { z } from 'zod';
|
|
11
9
|
import { createRequire } from 'module';
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
12
11
|
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
|
|
13
|
-
import 'viem';
|
|
14
|
-
import 'viem/accounts';
|
|
15
|
-
import 'viem/chains';
|
|
16
12
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
17
13
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
18
14
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
19
|
-
import * as
|
|
15
|
+
import * as http from 'http';
|
|
20
16
|
import dotenv from 'dotenv';
|
|
21
17
|
|
|
22
|
-
var getFilename = () => fileURLToPath(import.meta.url);
|
|
23
|
-
var __filename$1 = /* @__PURE__ */ getFilename();
|
|
24
18
|
function resolveTsconfig(projectRoot) {
|
|
25
|
-
const candidate =
|
|
19
|
+
const candidate = path5.join(projectRoot, "tsconfig.json");
|
|
26
20
|
if (fs4.existsSync(candidate)) {
|
|
27
21
|
return candidate;
|
|
28
22
|
}
|
|
@@ -33,7 +27,7 @@ async function transpileWithEsbuild(options) {
|
|
|
33
27
|
throw new Error("No entry points provided for esbuild transpilation");
|
|
34
28
|
}
|
|
35
29
|
const projectRoot = options.projectRoot;
|
|
36
|
-
const tempBase = options.outDir ?? fs4.mkdtempSync(
|
|
30
|
+
const tempBase = options.outDir ?? fs4.mkdtempSync(path5.join(tmpdir(), "opentool-"));
|
|
37
31
|
if (!fs4.existsSync(tempBase)) {
|
|
38
32
|
fs4.mkdirSync(tempBase, { recursive: true });
|
|
39
33
|
}
|
|
@@ -66,6 +60,9 @@ async function transpileWithEsbuild(options) {
|
|
|
66
60
|
if (options.external && options.external.length > 0) {
|
|
67
61
|
buildOptions.external = options.external;
|
|
68
62
|
}
|
|
63
|
+
if (options.nodePaths && options.nodePaths.length > 0) {
|
|
64
|
+
buildOptions.nodePaths = options.nodePaths;
|
|
65
|
+
}
|
|
69
66
|
if (options.outBase) {
|
|
70
67
|
buildOptions.outbase = options.outBase;
|
|
71
68
|
}
|
|
@@ -77,7 +74,7 @@ async function transpileWithEsbuild(options) {
|
|
|
77
74
|
}
|
|
78
75
|
await build(buildOptions);
|
|
79
76
|
if (options.format === "esm") {
|
|
80
|
-
const packageJsonPath =
|
|
77
|
+
const packageJsonPath = path5.join(tempBase, "package.json");
|
|
81
78
|
if (!fs4.existsSync(packageJsonPath)) {
|
|
82
79
|
fs4.writeFileSync(packageJsonPath, JSON.stringify({ type: "module" }), "utf8");
|
|
83
80
|
}
|
|
@@ -208,11 +205,11 @@ var BuildMetadataSchema = z.object({
|
|
|
208
205
|
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
209
206
|
}).strict();
|
|
210
207
|
createRequire(
|
|
211
|
-
typeof __filename
|
|
208
|
+
typeof __filename !== "undefined" ? __filename : import.meta.url
|
|
212
209
|
);
|
|
213
210
|
function resolveCompiledPath(outDir, originalFile, extension = ".js") {
|
|
214
|
-
const baseName =
|
|
215
|
-
return
|
|
211
|
+
const baseName = path5.basename(originalFile).replace(/\.[^.]+$/, "");
|
|
212
|
+
return path5.join(outDir, `${baseName}${extension}`);
|
|
216
213
|
}
|
|
217
214
|
async function importFresh(modulePath) {
|
|
218
215
|
const fileUrl = pathToFileURL(modulePath).href;
|
|
@@ -224,14 +221,14 @@ async function importFresh(modulePath) {
|
|
|
224
221
|
// src/cli/shared/metadata.ts
|
|
225
222
|
var METADATA_ENTRY = "metadata.ts";
|
|
226
223
|
async function loadMetadata(projectRoot) {
|
|
227
|
-
const absPath =
|
|
224
|
+
const absPath = path5.join(projectRoot, METADATA_ENTRY);
|
|
228
225
|
if (!fs4.existsSync(absPath)) {
|
|
229
226
|
return {
|
|
230
227
|
metadata: MetadataSchema.parse({}),
|
|
231
228
|
sourcePath: "smart defaults (metadata.ts missing)"
|
|
232
229
|
};
|
|
233
230
|
}
|
|
234
|
-
const tempDir =
|
|
231
|
+
const tempDir = path5.join(projectRoot, ".opentool-temp");
|
|
235
232
|
if (fs4.existsSync(tempDir)) {
|
|
236
233
|
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
237
234
|
}
|
|
@@ -272,7 +269,7 @@ function extractMetadataExport(moduleExports) {
|
|
|
272
269
|
return moduleExports;
|
|
273
270
|
}
|
|
274
271
|
function readPackageJson(projectRoot) {
|
|
275
|
-
const packagePath =
|
|
272
|
+
const packagePath = path5.join(projectRoot, "package.json");
|
|
276
273
|
if (!fs4.existsSync(packagePath)) {
|
|
277
274
|
return {};
|
|
278
275
|
}
|
|
@@ -288,7 +285,7 @@ async function buildMetadataArtifact(options) {
|
|
|
288
285
|
const packageInfo = readPackageJson(projectRoot);
|
|
289
286
|
const { metadata: authored, sourcePath } = await loadMetadata(projectRoot);
|
|
290
287
|
const defaultsApplied = [];
|
|
291
|
-
const folderName =
|
|
288
|
+
const folderName = path5.basename(projectRoot);
|
|
292
289
|
const name = resolveField(
|
|
293
290
|
"name",
|
|
294
291
|
authored.name,
|
|
@@ -751,7 +748,7 @@ function ensureTrailingSlash(url) {
|
|
|
751
748
|
return url.endsWith("/") ? url : `${url}/`;
|
|
752
749
|
}
|
|
753
750
|
|
|
754
|
-
// src/x402/
|
|
751
|
+
// src/x402/payment.ts
|
|
755
752
|
var PAYMENT_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("opentool.x402.context");
|
|
756
753
|
var X402PaymentRequiredError = class extends Error {
|
|
757
754
|
constructor(response, verification) {
|
|
@@ -991,6 +988,8 @@ function validateCronTokens(fields, context) {
|
|
|
991
988
|
|
|
992
989
|
// src/cli/validate.ts
|
|
993
990
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
991
|
+
var OPENTOOL_ROOT = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
992
|
+
var OPENTOOL_NODE_MODULES = path5.join(OPENTOOL_ROOT, "node_modules");
|
|
994
993
|
var MIN_TEMPLATE_CONFIG_VERSION = 2;
|
|
995
994
|
var TEMPLATE_PREVIEW_TITLE_MAX = 80;
|
|
996
995
|
var TEMPLATE_PREVIEW_SUBTITLE_MAX = 120;
|
|
@@ -1077,36 +1076,36 @@ function normalizeTemplatePreview(value, file, toolName, requirePreview) {
|
|
|
1077
1076
|
};
|
|
1078
1077
|
}
|
|
1079
1078
|
async function validateCommand(options) {
|
|
1080
|
-
console.log("\u{1F50D} Validating OpenTool
|
|
1079
|
+
console.log("\u{1F50D} Validating OpenTool project...");
|
|
1081
1080
|
try {
|
|
1082
|
-
const toolsDir =
|
|
1081
|
+
const toolsDir = path5.resolve(options.input);
|
|
1083
1082
|
if (!fs4.existsSync(toolsDir)) {
|
|
1084
1083
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
1085
1084
|
}
|
|
1086
|
-
const projectRoot =
|
|
1085
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
1087
1086
|
const tools = await loadAndValidateTools(toolsDir, { projectRoot });
|
|
1088
1087
|
if (tools.length === 0) {
|
|
1089
|
-
throw new Error("No valid tools found -
|
|
1088
|
+
throw new Error("No valid tools found - validation aborted");
|
|
1090
1089
|
}
|
|
1091
1090
|
const { metadata, defaultsApplied, sourceMetadataPath } = await buildMetadataArtifact({
|
|
1092
1091
|
projectRoot,
|
|
1093
1092
|
tools
|
|
1094
1093
|
});
|
|
1095
1094
|
logMetadataSummary(metadata, defaultsApplied, sourceMetadataPath);
|
|
1096
|
-
console.log("\n\u2705
|
|
1095
|
+
console.log("\n\u2705 OpenTool validation passed!\n");
|
|
1097
1096
|
} catch (error) {
|
|
1098
|
-
console.error("\u274C
|
|
1097
|
+
console.error("\u274C OpenTool validation failed:", error);
|
|
1099
1098
|
process.exit(1);
|
|
1100
1099
|
}
|
|
1101
1100
|
}
|
|
1102
1101
|
async function validateFullCommand(options) {
|
|
1103
1102
|
console.log("\u{1F50D} Running full OpenTool validation...\n");
|
|
1104
1103
|
try {
|
|
1105
|
-
const toolsDir =
|
|
1104
|
+
const toolsDir = path5.resolve(options.input);
|
|
1106
1105
|
if (!fs4.existsSync(toolsDir)) {
|
|
1107
1106
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
1108
1107
|
}
|
|
1109
|
-
const projectRoot =
|
|
1108
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
1110
1109
|
const tools = await loadAndValidateTools(toolsDir, { projectRoot });
|
|
1111
1110
|
if (tools.length === 0) {
|
|
1112
1111
|
throw new Error("No tools discovered in the target directory");
|
|
@@ -1134,12 +1133,12 @@ async function validateFullCommand(options) {
|
|
|
1134
1133
|
}
|
|
1135
1134
|
}
|
|
1136
1135
|
async function loadAndValidateTools(toolsDir, options = {}) {
|
|
1137
|
-
const files = fs4.readdirSync(toolsDir).filter((file) => SUPPORTED_EXTENSIONS.includes(
|
|
1136
|
+
const files = fs4.readdirSync(toolsDir).filter((file) => SUPPORTED_EXTENSIONS.includes(path5.extname(file)));
|
|
1138
1137
|
if (files.length === 0) {
|
|
1139
1138
|
return [];
|
|
1140
1139
|
}
|
|
1141
|
-
const projectRoot = options.projectRoot ??
|
|
1142
|
-
const tempDir =
|
|
1140
|
+
const projectRoot = options.projectRoot ?? path5.dirname(toolsDir);
|
|
1141
|
+
const tempDir = path5.join(toolsDir, ".opentool-temp");
|
|
1143
1142
|
if (fs4.existsSync(tempDir)) {
|
|
1144
1143
|
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
1145
1144
|
}
|
|
@@ -1149,17 +1148,20 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1149
1148
|
throw new Error(`Tool filename must be kebab-case: ${f}`);
|
|
1150
1149
|
}
|
|
1151
1150
|
}
|
|
1152
|
-
const entryPoints = files.map((file) =>
|
|
1151
|
+
const entryPoints = files.map((file) => path5.join(toolsDir, file));
|
|
1152
|
+
const fallbackNodePaths = [OPENTOOL_NODE_MODULES].filter((dir) => fs4.existsSync(dir));
|
|
1153
1153
|
const { outDir, cleanup } = await transpileWithEsbuild({
|
|
1154
1154
|
entryPoints,
|
|
1155
1155
|
projectRoot,
|
|
1156
1156
|
format: "esm",
|
|
1157
1157
|
outDir: tempDir,
|
|
1158
1158
|
bundle: true,
|
|
1159
|
-
external: ["opentool", "opentool/*"]
|
|
1159
|
+
external: ["opentool", "opentool/*"],
|
|
1160
|
+
...fallbackNodePaths.length > 0 ? { nodePaths: fallbackNodePaths } : {}
|
|
1160
1161
|
});
|
|
1161
1162
|
const tools = [];
|
|
1162
1163
|
try {
|
|
1164
|
+
ensureLocalRuntimeLinks(tempDir);
|
|
1163
1165
|
for (const file of files) {
|
|
1164
1166
|
const compiledPath = resolveCompiledPath(outDir, file);
|
|
1165
1167
|
if (!fs4.existsSync(compiledPath)) {
|
|
@@ -1313,11 +1315,6 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1313
1315
|
if (!schema) {
|
|
1314
1316
|
throw new Error(`${file}: POST tools must export a Zod schema as 'schema'`);
|
|
1315
1317
|
}
|
|
1316
|
-
if (schedule && typeof schedule.cron === "string") {
|
|
1317
|
-
throw new Error(
|
|
1318
|
-
`${file}: POST tools must not define profile.schedule; use GET + cron for scheduled tasks.`
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
1318
|
}
|
|
1322
1319
|
const httpHandlers = [...httpHandlersRaw];
|
|
1323
1320
|
if (httpHandlers.length === 0) {
|
|
@@ -1365,7 +1362,7 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1365
1362
|
httpHandlers,
|
|
1366
1363
|
mcpConfig: normalizeMcpConfig(toolModule.mcp, file),
|
|
1367
1364
|
filename: toBaseName(file),
|
|
1368
|
-
sourcePath:
|
|
1365
|
+
sourcePath: path5.join(toolsDir, file),
|
|
1369
1366
|
handler: async (params) => adapter(params),
|
|
1370
1367
|
payment: paymentExport ?? null,
|
|
1371
1368
|
schedule: normalizedSchedule,
|
|
@@ -1384,6 +1381,24 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1384
1381
|
}
|
|
1385
1382
|
return tools;
|
|
1386
1383
|
}
|
|
1384
|
+
function ensureLocalRuntimeLinks(tempDir) {
|
|
1385
|
+
const nodeModulesDir = path5.join(tempDir, "node_modules");
|
|
1386
|
+
fs4.mkdirSync(nodeModulesDir, { recursive: true });
|
|
1387
|
+
const packageLinks = [
|
|
1388
|
+
{ name: "opentool", target: OPENTOOL_ROOT },
|
|
1389
|
+
{ name: "zod", target: path5.join(OPENTOOL_NODE_MODULES, "zod") }
|
|
1390
|
+
];
|
|
1391
|
+
for (const { name, target } of packageLinks) {
|
|
1392
|
+
if (!fs4.existsSync(target)) {
|
|
1393
|
+
continue;
|
|
1394
|
+
}
|
|
1395
|
+
const linkPath = path5.join(nodeModulesDir, name);
|
|
1396
|
+
if (fs4.existsSync(linkPath)) {
|
|
1397
|
+
continue;
|
|
1398
|
+
}
|
|
1399
|
+
fs4.symlinkSync(target, linkPath, "junction");
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1387
1402
|
function extractToolModule(exportsObject, filename) {
|
|
1388
1403
|
const candidates = [exportsObject, exportsObject?.default];
|
|
1389
1404
|
for (const candidate of candidates) {
|
|
@@ -1571,12 +1586,12 @@ async function buildCommand(options) {
|
|
|
1571
1586
|
}
|
|
1572
1587
|
}
|
|
1573
1588
|
async function buildProject(options) {
|
|
1574
|
-
const toolsDir =
|
|
1589
|
+
const toolsDir = path5.resolve(options.input);
|
|
1575
1590
|
if (!fs4.existsSync(toolsDir)) {
|
|
1576
1591
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
1577
1592
|
}
|
|
1578
|
-
const projectRoot =
|
|
1579
|
-
const outputDir =
|
|
1593
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
1594
|
+
const outputDir = path5.resolve(options.output);
|
|
1580
1595
|
fs4.mkdirSync(outputDir, { recursive: true });
|
|
1581
1596
|
const serverName = options.name ?? "opentool-server";
|
|
1582
1597
|
const serverVersion = options.version ?? "1.0.0";
|
|
@@ -1588,7 +1603,7 @@ async function buildProject(options) {
|
|
|
1588
1603
|
projectRoot,
|
|
1589
1604
|
tools
|
|
1590
1605
|
});
|
|
1591
|
-
const metadataPath =
|
|
1606
|
+
const metadataPath = path5.join(outputDir, "metadata.json");
|
|
1592
1607
|
fs4.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
1593
1608
|
const compiledTools = await emitTools(tools, {
|
|
1594
1609
|
projectRoot,
|
|
@@ -1611,7 +1626,7 @@ async function buildProject(options) {
|
|
|
1611
1626
|
serverVersion,
|
|
1612
1627
|
compiledTools});
|
|
1613
1628
|
} else {
|
|
1614
|
-
const serverPath =
|
|
1629
|
+
const serverPath = path5.join(outputDir, "mcp-server.js");
|
|
1615
1630
|
if (fs4.existsSync(serverPath)) {
|
|
1616
1631
|
fs4.rmSync(serverPath);
|
|
1617
1632
|
}
|
|
@@ -1626,7 +1641,7 @@ async function buildProject(options) {
|
|
|
1626
1641
|
};
|
|
1627
1642
|
}
|
|
1628
1643
|
async function emitTools(tools, config) {
|
|
1629
|
-
const toolsOutDir =
|
|
1644
|
+
const toolsOutDir = path5.join(config.outputDir, "tools");
|
|
1630
1645
|
if (fs4.existsSync(toolsOutDir)) {
|
|
1631
1646
|
fs4.rmSync(toolsOutDir, { recursive: true, force: true });
|
|
1632
1647
|
}
|
|
@@ -1648,9 +1663,9 @@ async function emitTools(tools, config) {
|
|
|
1648
1663
|
if (!tool.sourcePath) {
|
|
1649
1664
|
throw new Error(`Missing sourcePath for tool ${tool.filename}`);
|
|
1650
1665
|
}
|
|
1651
|
-
const base =
|
|
1652
|
-
const modulePath =
|
|
1653
|
-
if (!fs4.existsSync(
|
|
1666
|
+
const base = path5.basename(tool.sourcePath).replace(/\.[^.]+$/, "");
|
|
1667
|
+
const modulePath = path5.join("tools", `${base}.js`);
|
|
1668
|
+
if (!fs4.existsSync(path5.join(config.outputDir, modulePath))) {
|
|
1654
1669
|
throw new Error(`Expected compiled output missing: ${modulePath}`);
|
|
1655
1670
|
}
|
|
1656
1671
|
const defaultMcpMethod = tool.mcpConfig?.defaultMethod;
|
|
@@ -1667,7 +1682,7 @@ async function emitTools(tools, config) {
|
|
|
1667
1682
|
return compiled;
|
|
1668
1683
|
}
|
|
1669
1684
|
async function emitSharedModules(config) {
|
|
1670
|
-
const srcDir =
|
|
1685
|
+
const srcDir = path5.join(config.projectRoot, "src");
|
|
1671
1686
|
if (!fs4.existsSync(srcDir)) {
|
|
1672
1687
|
return null;
|
|
1673
1688
|
}
|
|
@@ -1675,7 +1690,7 @@ async function emitSharedModules(config) {
|
|
|
1675
1690
|
if (sharedFiles.length === 0) {
|
|
1676
1691
|
return null;
|
|
1677
1692
|
}
|
|
1678
|
-
const sharedOutDir =
|
|
1693
|
+
const sharedOutDir = path5.join(config.outputDir, "src");
|
|
1679
1694
|
await transpileWithEsbuild({
|
|
1680
1695
|
entryPoints: sharedFiles,
|
|
1681
1696
|
projectRoot: config.projectRoot,
|
|
@@ -1693,7 +1708,7 @@ function collectSourceFiles(dir) {
|
|
|
1693
1708
|
const ignoreDirs = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".opentool-temp"]);
|
|
1694
1709
|
const entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
1695
1710
|
for (const entry of entries) {
|
|
1696
|
-
const fullPath =
|
|
1711
|
+
const fullPath = path5.join(dir, entry.name);
|
|
1697
1712
|
if (entry.isDirectory()) {
|
|
1698
1713
|
if (ignoreDirs.has(entry.name)) {
|
|
1699
1714
|
continue;
|
|
@@ -1701,7 +1716,7 @@ function collectSourceFiles(dir) {
|
|
|
1701
1716
|
results.push(...collectSourceFiles(fullPath));
|
|
1702
1717
|
continue;
|
|
1703
1718
|
}
|
|
1704
|
-
const ext =
|
|
1719
|
+
const ext = path5.extname(entry.name);
|
|
1705
1720
|
if (supported.has(ext) && !entry.name.endsWith(".d.ts")) {
|
|
1706
1721
|
results.push(fullPath);
|
|
1707
1722
|
}
|
|
@@ -1803,13 +1818,13 @@ module.exports = { server };
|
|
|
1803
1818
|
}
|
|
1804
1819
|
async function writeMcpServer(options) {
|
|
1805
1820
|
const serverCode = renderMcpServer(options);
|
|
1806
|
-
const serverPath =
|
|
1821
|
+
const serverPath = path5.join(options.outputDir, "mcp-server.js");
|
|
1807
1822
|
fs4.writeFileSync(serverPath, serverCode);
|
|
1808
1823
|
fs4.chmodSync(serverPath, 493);
|
|
1809
1824
|
}
|
|
1810
1825
|
function writeToolsManifest(options) {
|
|
1811
|
-
const manifestPath =
|
|
1812
|
-
const legacyManifestPath =
|
|
1826
|
+
const manifestPath = path5.join(options.outputDir, "tools.json");
|
|
1827
|
+
const legacyManifestPath = path5.join(options.outputDir, ".well-known", "opentool", "cron.json");
|
|
1813
1828
|
if (fs4.existsSync(legacyManifestPath)) {
|
|
1814
1829
|
fs4.rmSync(legacyManifestPath, { force: true });
|
|
1815
1830
|
}
|
|
@@ -1843,7 +1858,7 @@ function writeToolsManifest(options) {
|
|
|
1843
1858
|
function logBuildSummary(artifacts, options) {
|
|
1844
1859
|
const end = timestamp();
|
|
1845
1860
|
console.log(`[${end}] Build completed successfully!`);
|
|
1846
|
-
console.log(`Output directory: ${
|
|
1861
|
+
console.log(`Output directory: ${path5.resolve(options.output)}`);
|
|
1847
1862
|
console.log("Generated files:");
|
|
1848
1863
|
const hasMcp = artifacts.compiledTools.some((tool) => tool.mcpEnabled);
|
|
1849
1864
|
if (hasMcp) {
|
|
@@ -1878,9 +1893,9 @@ function timestamp() {
|
|
|
1878
1893
|
function escapeForJs(value) {
|
|
1879
1894
|
return value.replace(/'/g, "\\'");
|
|
1880
1895
|
}
|
|
1881
|
-
var
|
|
1896
|
+
var __dirname$1 = path5.dirname(fileURLToPath(import.meta.url));
|
|
1882
1897
|
var packageJson = JSON.parse(
|
|
1883
|
-
fs4.readFileSync(
|
|
1898
|
+
fs4.readFileSync(path5.resolve(__dirname$1, "../../package.json"), "utf-8")
|
|
1884
1899
|
);
|
|
1885
1900
|
var cyan = "\x1B[36m";
|
|
1886
1901
|
var bold = "\x1B[1m";
|
|
@@ -1893,11 +1908,11 @@ async function devCommand(options) {
|
|
|
1893
1908
|
const log = enableStdio ? (_message) => {
|
|
1894
1909
|
} : (message) => console.log(message);
|
|
1895
1910
|
try {
|
|
1896
|
-
const toolsDir =
|
|
1911
|
+
const toolsDir = path5.resolve(options.input);
|
|
1897
1912
|
if (!fs4.existsSync(toolsDir)) {
|
|
1898
1913
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
1899
1914
|
}
|
|
1900
|
-
const projectRoot =
|
|
1915
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
1901
1916
|
loadEnvFiles(projectRoot);
|
|
1902
1917
|
let toolDefinitions = await loadToolDefinitions(toolsDir, projectRoot);
|
|
1903
1918
|
if (toolDefinitions.length === 0) {
|
|
@@ -1907,7 +1922,7 @@ async function devCommand(options) {
|
|
|
1907
1922
|
const stdioController = enableStdio ? await startMcpServer(() => toolDefinitions) : null;
|
|
1908
1923
|
if (watch2) {
|
|
1909
1924
|
const reloadableExtensions = /\.(ts|js|mjs|cjs|tsx|jsx)$/i;
|
|
1910
|
-
const tempDir =
|
|
1925
|
+
const tempDir = path5.join(toolsDir, ".opentool-temp");
|
|
1911
1926
|
const watchTargets = /* @__PURE__ */ new Set([toolsDir]);
|
|
1912
1927
|
if (projectRoot !== toolsDir) {
|
|
1913
1928
|
watchTargets.add(projectRoot);
|
|
@@ -1936,16 +1951,16 @@ Detected change in ${changedPath ?? "tools directory"}, reloading...${reset}`);
|
|
|
1936
1951
|
if (filename && !reloadableExtensions.test(filename)) {
|
|
1937
1952
|
return;
|
|
1938
1953
|
}
|
|
1939
|
-
const fullPath = filename ?
|
|
1954
|
+
const fullPath = filename ? path5.join(target, filename) : void 0;
|
|
1940
1955
|
if (fullPath && fullPath.startsWith(tempDir)) {
|
|
1941
1956
|
return;
|
|
1942
1957
|
}
|
|
1943
|
-
const displayPath = fullPath ?
|
|
1958
|
+
const displayPath = fullPath ? path5.relative(projectRoot, fullPath) || path5.basename(fullPath) : path5.relative(projectRoot, target) || path5.basename(target);
|
|
1944
1959
|
await scheduleReload(displayPath);
|
|
1945
1960
|
});
|
|
1946
1961
|
}
|
|
1947
1962
|
}
|
|
1948
|
-
const server =
|
|
1963
|
+
const server = http.createServer(async (req, res) => {
|
|
1949
1964
|
const method = (req.method || "GET").toUpperCase();
|
|
1950
1965
|
const url = new URL(req.url || "/", `http://localhost:${port}`);
|
|
1951
1966
|
const routePath = url.pathname;
|
|
@@ -2162,7 +2177,7 @@ function routeName(tool) {
|
|
|
2162
2177
|
function loadEnvFiles(projectRoot) {
|
|
2163
2178
|
const envFiles = [".env.local", ".env"];
|
|
2164
2179
|
for (const file of envFiles) {
|
|
2165
|
-
const candidate =
|
|
2180
|
+
const candidate = path5.join(projectRoot, file);
|
|
2166
2181
|
if (fs4.existsSync(candidate)) {
|
|
2167
2182
|
dotenv.config({ path: candidate, override: false });
|
|
2168
2183
|
}
|
|
@@ -2230,17 +2245,17 @@ async function generateMetadataCommand(options) {
|
|
|
2230
2245
|
}
|
|
2231
2246
|
}
|
|
2232
2247
|
async function generateMetadata(options) {
|
|
2233
|
-
const toolsDir =
|
|
2248
|
+
const toolsDir = path5.resolve(options.input);
|
|
2234
2249
|
if (!fs4.existsSync(toolsDir)) {
|
|
2235
2250
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
2236
2251
|
}
|
|
2237
|
-
const projectRoot =
|
|
2252
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
2238
2253
|
const tools = await loadAndValidateTools(toolsDir, { projectRoot });
|
|
2239
2254
|
const { metadata, defaultsApplied } = await buildMetadataArtifact({
|
|
2240
2255
|
projectRoot,
|
|
2241
2256
|
tools
|
|
2242
2257
|
});
|
|
2243
|
-
const outputPath = options.output ?
|
|
2258
|
+
const outputPath = options.output ? path5.resolve(options.output) : path5.join(projectRoot, "metadata.json");
|
|
2244
2259
|
fs4.writeFileSync(outputPath, JSON.stringify(metadata, null, 2));
|
|
2245
2260
|
return {
|
|
2246
2261
|
metadata,
|
|
@@ -2253,8 +2268,8 @@ function timestamp2() {
|
|
|
2253
2268
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
2254
2269
|
}
|
|
2255
2270
|
function resolveTemplateDir() {
|
|
2256
|
-
const here =
|
|
2257
|
-
return
|
|
2271
|
+
const here = path5.dirname(fileURLToPath(import.meta.url));
|
|
2272
|
+
return path5.resolve(here, "../../templates/base");
|
|
2258
2273
|
}
|
|
2259
2274
|
async function directoryIsEmpty(targetDir) {
|
|
2260
2275
|
try {
|
|
@@ -2271,8 +2286,8 @@ async function copyDir(src, dest) {
|
|
|
2271
2286
|
await promises.mkdir(dest, { recursive: true });
|
|
2272
2287
|
const entries = await promises.readdir(src, { withFileTypes: true });
|
|
2273
2288
|
for (const entry of entries) {
|
|
2274
|
-
const srcPath =
|
|
2275
|
-
const destPath =
|
|
2289
|
+
const srcPath = path5.join(src, entry.name);
|
|
2290
|
+
const destPath = path5.join(dest, entry.name);
|
|
2276
2291
|
if (entry.isDirectory()) {
|
|
2277
2292
|
await copyDir(srcPath, destPath);
|
|
2278
2293
|
} else if (entry.isFile()) {
|
|
@@ -2287,7 +2302,7 @@ function toDisplayName(value) {
|
|
|
2287
2302
|
return value.trim().replace(/[-_]+/g, " ").replace(/\b\w/g, (ch) => ch.toUpperCase()) || "OpenTool Project";
|
|
2288
2303
|
}
|
|
2289
2304
|
async function updatePackageJson(targetDir, name, description) {
|
|
2290
|
-
const filePath =
|
|
2305
|
+
const filePath = path5.join(targetDir, "package.json");
|
|
2291
2306
|
const raw = await promises.readFile(filePath, "utf-8");
|
|
2292
2307
|
const pkg = JSON.parse(raw);
|
|
2293
2308
|
pkg.name = toPackageName(name);
|
|
@@ -2298,7 +2313,7 @@ async function updatePackageJson(targetDir, name, description) {
|
|
|
2298
2313
|
`, "utf-8");
|
|
2299
2314
|
}
|
|
2300
2315
|
async function updateMetadata(targetDir, name, description) {
|
|
2301
|
-
const filePath =
|
|
2316
|
+
const filePath = path5.join(targetDir, "metadata.ts");
|
|
2302
2317
|
const raw = await promises.readFile(filePath, "utf-8");
|
|
2303
2318
|
const displayName = toDisplayName(name);
|
|
2304
2319
|
const resolvedDescription = description || "OpenTool project";
|
|
@@ -2306,14 +2321,14 @@ async function updateMetadata(targetDir, name, description) {
|
|
|
2306
2321
|
await promises.writeFile(filePath, updated, "utf-8");
|
|
2307
2322
|
}
|
|
2308
2323
|
async function initCommand(options) {
|
|
2309
|
-
const targetDir =
|
|
2324
|
+
const targetDir = path5.resolve(process.cwd(), options.dir || ".");
|
|
2310
2325
|
const templateDir = resolveTemplateDir();
|
|
2311
2326
|
const empty = await directoryIsEmpty(targetDir);
|
|
2312
2327
|
if (!empty && !options.force) {
|
|
2313
2328
|
throw new Error(`Directory not empty: ${targetDir}. Use --force to overwrite.`);
|
|
2314
2329
|
}
|
|
2315
2330
|
await copyDir(templateDir, targetDir);
|
|
2316
|
-
const projectName = options.name ||
|
|
2331
|
+
const projectName = options.name || path5.basename(targetDir);
|
|
2317
2332
|
const description = options.description;
|
|
2318
2333
|
await updatePackageJson(targetDir, projectName, description);
|
|
2319
2334
|
await updateMetadata(targetDir, projectName, description);
|
|
@@ -2330,8 +2345,8 @@ program.command("dev").description("Start HTTP dev server (optional MCP stdio)")
|
|
|
2330
2345
|
});
|
|
2331
2346
|
});
|
|
2332
2347
|
program.command("build").description("Build tools for deployment").option("-i, --input <dir>", "Input directory containing tools", "tools").option("-o, --output <dir>", "Output directory for built tools", "dist").option("--name <name>", "Server name", "opentool-server").option("--version <version>", "Server version", "1.0.0").action(buildCommand);
|
|
2333
|
-
program.command("validate").description("Validate
|
|
2334
|
-
program.command("validate-full").description("Full validation
|
|
2348
|
+
program.command("validate").description("Validate OpenTool project (tool handlers, profile/schema rules, metadata synthesis)").option("-i, --input <dir>", "Input directory containing tools", "tools").action(validateCommand);
|
|
2349
|
+
program.command("validate-full").description("Full OpenTool validation with detailed tool summary").option("-i, --input <dir>", "Input directory containing tools", "tools").action(validateFullCommand);
|
|
2335
2350
|
program.command("metadata").description("Generate OpenTool metadata JSON without building").option("-i, --input <dir>", "Input directory containing tools", "tools").option("-o, --output <file>", "Output file path for metadata.json", "metadata.json").option("--name <name>", "Server name", "opentool-server").option("--version <version>", "Server version", "1.0.0").action(generateMetadataCommand);
|
|
2336
2351
|
program.command("init").description("Create a new OpenTool project in the target directory").option("-d, --dir <dir>", "Target directory", ".").option("-n, --name <name>", "Project name").option("--description <description>", "Project description").option("--force", "Overwrite existing files", false).action(async (cmdOptions) => {
|
|
2337
2352
|
await initCommand({
|