opentool 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/hyperliquid/index.js +32 -102
- package/dist/adapters/hyperliquid/index.js.map +1 -1
- package/dist/ai/index.js +9 -22
- package/dist/ai/index.js.map +1 -1
- package/dist/cli/index.js +52 -103
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +90 -241
- package/dist/index.js.map +1 -1
- package/dist/store/index.js +7 -21
- package/dist/store/index.js.map +1 -1
- package/dist/viem/index.d.ts +1 -0
- package/dist/viem/index.js +3 -0
- package/dist/viem/index.js.map +1 -0
- package/dist/wallet/index.js +7 -37
- package/dist/wallet/index.js.map +1 -1
- package/dist/x402/index.js +12 -4
- package/dist/x402/index.js.map +1 -1
- package/package.json +21 -16
- package/templates/base/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -128,10 +128,7 @@ var X402PaymentSchema = z.object({
|
|
|
128
128
|
}),
|
|
129
129
|
metadata: z.record(z.string(), z.unknown()).optional()
|
|
130
130
|
}).passthrough();
|
|
131
|
-
var PaymentConfigSchema = z.union([
|
|
132
|
-
X402PaymentSchema,
|
|
133
|
-
z.record(z.string(), z.unknown())
|
|
134
|
-
]);
|
|
131
|
+
var PaymentConfigSchema = z.union([X402PaymentSchema, z.record(z.string(), z.unknown())]);
|
|
135
132
|
var DiscoveryMetadataSchema = z.object({
|
|
136
133
|
keywords: z.array(z.string()).optional(),
|
|
137
134
|
category: z.string().optional(),
|
|
@@ -460,7 +457,7 @@ function buildDiscovery(authored) {
|
|
|
460
457
|
}
|
|
461
458
|
const merged = {
|
|
462
459
|
...legacyDiscovery,
|
|
463
|
-
...authored.discovery
|
|
460
|
+
...authored.discovery
|
|
464
461
|
};
|
|
465
462
|
return Object.keys(merged).length > 0 ? merged : void 0;
|
|
466
463
|
}
|
|
@@ -592,7 +589,10 @@ async function verifyX402Payment(attempt, definition, options = {}) {
|
|
|
592
589
|
console.log("[x402] Facilitator /verify response", { status: verifyResponse.status });
|
|
593
590
|
if (!verifyResponse.ok) {
|
|
594
591
|
const errorText = await verifyResponse.text().catch(() => "");
|
|
595
|
-
console.error("[x402] Facilitator /verify error", {
|
|
592
|
+
console.error("[x402] Facilitator /verify error", {
|
|
593
|
+
status: verifyResponse.status,
|
|
594
|
+
body: errorText
|
|
595
|
+
});
|
|
596
596
|
return {
|
|
597
597
|
success: false,
|
|
598
598
|
failure: {
|
|
@@ -640,7 +640,10 @@ async function verifyX402Payment(attempt, definition, options = {}) {
|
|
|
640
640
|
console.log("[x402] Facilitator /settle response", { status: settleResponse.status });
|
|
641
641
|
if (!settleResponse.ok) {
|
|
642
642
|
const errorText = await settleResponse.text().catch(() => "");
|
|
643
|
-
console.error("[x402] Facilitator /settle error", {
|
|
643
|
+
console.error("[x402] Facilitator /settle error", {
|
|
644
|
+
status: settleResponse.status,
|
|
645
|
+
body: errorText
|
|
646
|
+
});
|
|
644
647
|
return {
|
|
645
648
|
success: false,
|
|
646
649
|
failure: {
|
|
@@ -658,7 +661,9 @@ async function verifyX402Payment(attempt, definition, options = {}) {
|
|
|
658
661
|
});
|
|
659
662
|
}
|
|
660
663
|
} catch (error) {
|
|
661
|
-
console.error("[x402] Settlement exception", {
|
|
664
|
+
console.error("[x402] Settlement exception", {
|
|
665
|
+
error: error instanceof Error ? error.message : String(error)
|
|
666
|
+
});
|
|
662
667
|
return {
|
|
663
668
|
success: false,
|
|
664
669
|
failure: {
|
|
@@ -747,7 +752,7 @@ function ensureTrailingSlash(url) {
|
|
|
747
752
|
}
|
|
748
753
|
|
|
749
754
|
// src/x402/index.ts
|
|
750
|
-
var PAYMENT_CONTEXT_SYMBOL = Symbol.for("opentool.x402.context");
|
|
755
|
+
var PAYMENT_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("opentool.x402.context");
|
|
751
756
|
var X402PaymentRequiredError = class extends Error {
|
|
752
757
|
constructor(response, verification) {
|
|
753
758
|
super("X402 Payment required");
|
|
@@ -838,9 +843,7 @@ function createMcpAdapter(options) {
|
|
|
838
843
|
const defaultMethod = resolveDefaultMethod(options);
|
|
839
844
|
const httpHandler = options.httpHandlers[defaultMethod];
|
|
840
845
|
if (!httpHandler) {
|
|
841
|
-
throw new Error(
|
|
842
|
-
`Tool "${options.name}" does not export an HTTP handler for ${defaultMethod}`
|
|
843
|
-
);
|
|
846
|
+
throw new Error(`Tool "${options.name}" does not export an HTTP handler for ${defaultMethod}`);
|
|
844
847
|
}
|
|
845
848
|
return async function invoke(rawArguments) {
|
|
846
849
|
const validated = normalizedSchema ? normalizedSchema.parse(rawArguments ?? {}) : rawArguments;
|
|
@@ -948,15 +951,7 @@ async function responseToToolResponse(response) {
|
|
|
948
951
|
}
|
|
949
952
|
|
|
950
953
|
// src/types/index.ts
|
|
951
|
-
var HTTP_METHODS = [
|
|
952
|
-
"GET",
|
|
953
|
-
"HEAD",
|
|
954
|
-
"POST",
|
|
955
|
-
"PUT",
|
|
956
|
-
"DELETE",
|
|
957
|
-
"PATCH",
|
|
958
|
-
"OPTIONS"
|
|
959
|
-
];
|
|
954
|
+
var HTTP_METHODS = ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"];
|
|
960
955
|
|
|
961
956
|
// src/utils/schedule.ts
|
|
962
957
|
var CRON_WRAPPED_REGEX = /^cron\((.*)\)$/i;
|
|
@@ -969,7 +964,9 @@ function normalizeScheduleExpression(raw, context) {
|
|
|
969
964
|
const cronBody = extractCronBody(value);
|
|
970
965
|
const cronFields = cronBody.trim().split(/\s+/).filter(Boolean);
|
|
971
966
|
if (cronFields.length !== 5 && cronFields.length !== 6) {
|
|
972
|
-
throw new Error(
|
|
967
|
+
throw new Error(
|
|
968
|
+
`${context}: cron expression must have 5 or 6 fields (got ${cronFields.length})`
|
|
969
|
+
);
|
|
973
970
|
}
|
|
974
971
|
validateCronTokens(cronFields, context);
|
|
975
972
|
return {
|
|
@@ -993,14 +990,7 @@ function validateCronTokens(fields, context) {
|
|
|
993
990
|
}
|
|
994
991
|
|
|
995
992
|
// src/cli/validate.ts
|
|
996
|
-
var SUPPORTED_EXTENSIONS = [
|
|
997
|
-
".ts",
|
|
998
|
-
".tsx",
|
|
999
|
-
".js",
|
|
1000
|
-
".jsx",
|
|
1001
|
-
".mjs",
|
|
1002
|
-
".cjs"
|
|
1003
|
-
];
|
|
993
|
+
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
1004
994
|
var MIN_TEMPLATE_CONFIG_VERSION = 2;
|
|
1005
995
|
var TEMPLATE_PREVIEW_TITLE_MAX = 80;
|
|
1006
996
|
var TEMPLATE_PREVIEW_SUBTITLE_MAX = 120;
|
|
@@ -1070,14 +1060,10 @@ function normalizeTemplatePreview(value, file, toolName, requirePreview) {
|
|
|
1070
1060
|
required: true,
|
|
1071
1061
|
max: TEMPLATE_PREVIEW_SUBTITLE_MAX
|
|
1072
1062
|
});
|
|
1073
|
-
const description = parseNonEmptyString(
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
required: true,
|
|
1078
|
-
max: TEMPLATE_PREVIEW_DESCRIPTION_MAX
|
|
1079
|
-
}
|
|
1080
|
-
);
|
|
1063
|
+
const description = parseNonEmptyString(record.description, `${pathPrefix}.description`, {
|
|
1064
|
+
required: true,
|
|
1065
|
+
max: TEMPLATE_PREVIEW_DESCRIPTION_MAX
|
|
1066
|
+
});
|
|
1081
1067
|
const descriptionLineCount = description.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).length;
|
|
1082
1068
|
if (descriptionLineCount < TEMPLATE_PREVIEW_MIN_LINES || descriptionLineCount > TEMPLATE_PREVIEW_MAX_LINES) {
|
|
1083
1069
|
throw new Error(
|
|
@@ -1204,15 +1190,13 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1204
1190
|
const profileRaw = toolModule?.profile && typeof toolModule.profile === "object" ? toolModule.profile : null;
|
|
1205
1191
|
const schedule = profileRaw?.schedule ?? null;
|
|
1206
1192
|
const profileNotifyEmail = typeof profileRaw?.notifyEmail === "boolean" ? profileRaw.notifyEmail : void 0;
|
|
1207
|
-
const allowedProfileCategories = [
|
|
1208
|
-
"strategy",
|
|
1209
|
-
"tracker",
|
|
1210
|
-
"orchestrator"
|
|
1211
|
-
];
|
|
1193
|
+
const allowedProfileCategories = ["strategy", "tracker", "orchestrator"];
|
|
1212
1194
|
const profileCategoryCandidate = typeof profileRaw?.category === "string" ? profileRaw.category : void 0;
|
|
1213
1195
|
let profileCategoryRaw;
|
|
1214
1196
|
if (profileCategoryCandidate !== void 0) {
|
|
1215
|
-
const isAllowed = allowedProfileCategories.includes(
|
|
1197
|
+
const isAllowed = allowedProfileCategories.includes(
|
|
1198
|
+
profileCategoryCandidate
|
|
1199
|
+
);
|
|
1216
1200
|
if (!isAllowed) {
|
|
1217
1201
|
throw new Error(
|
|
1218
1202
|
`${file}: profile.category must be one of ${allowedProfileCategories.join(", ")}`
|
|
@@ -1227,22 +1211,16 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1227
1211
|
}
|
|
1228
1212
|
profileAssetsRaw.forEach((entry, index) => {
|
|
1229
1213
|
if (!entry || typeof entry !== "object") {
|
|
1230
|
-
throw new Error(
|
|
1231
|
-
`${file}: profile.assets[${index}] must be an object.`
|
|
1232
|
-
);
|
|
1214
|
+
throw new Error(`${file}: profile.assets[${index}] must be an object.`);
|
|
1233
1215
|
}
|
|
1234
1216
|
const record = entry;
|
|
1235
1217
|
const venue = typeof record.venue === "string" ? record.venue.trim() : "";
|
|
1236
1218
|
if (!venue) {
|
|
1237
|
-
throw new Error(
|
|
1238
|
-
`${file}: profile.assets[${index}].venue must be a non-empty string.`
|
|
1239
|
-
);
|
|
1219
|
+
throw new Error(`${file}: profile.assets[${index}].venue must be a non-empty string.`);
|
|
1240
1220
|
}
|
|
1241
1221
|
const chain = record.chain;
|
|
1242
1222
|
if (typeof chain !== "string" && typeof chain !== "number") {
|
|
1243
|
-
throw new Error(
|
|
1244
|
-
`${file}: profile.assets[${index}].chain must be a string or number.`
|
|
1245
|
-
);
|
|
1223
|
+
throw new Error(`${file}: profile.assets[${index}].chain must be a string or number.`);
|
|
1246
1224
|
}
|
|
1247
1225
|
const symbols = record.assetSymbols;
|
|
1248
1226
|
if (!Array.isArray(symbols) || symbols.length === 0) {
|
|
@@ -1336,14 +1314,14 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1336
1314
|
throw new Error(`${file}: POST tools must export a Zod schema as 'schema'`);
|
|
1337
1315
|
}
|
|
1338
1316
|
if (schedule && typeof schedule.cron === "string") {
|
|
1339
|
-
throw new Error(
|
|
1317
|
+
throw new Error(
|
|
1318
|
+
`${file}: POST tools must not define profile.schedule; use GET + cron for scheduled tasks.`
|
|
1319
|
+
);
|
|
1340
1320
|
}
|
|
1341
1321
|
}
|
|
1342
1322
|
const httpHandlers = [...httpHandlersRaw];
|
|
1343
1323
|
if (httpHandlers.length === 0) {
|
|
1344
|
-
throw new Error(
|
|
1345
|
-
`${file} must export at least one HTTP handler (e.g. POST)`
|
|
1346
|
-
);
|
|
1324
|
+
throw new Error(`${file} must export at least one HTTP handler (e.g. POST)`);
|
|
1347
1325
|
}
|
|
1348
1326
|
if (paymentExport) {
|
|
1349
1327
|
for (let index = 0; index < httpHandlers.length; index += 1) {
|
|
@@ -1369,7 +1347,7 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
1369
1347
|
...metadataOverrides,
|
|
1370
1348
|
payment: metadataOverrides.payment ?? paymentExport,
|
|
1371
1349
|
annotations: {
|
|
1372
|
-
...metadataOverrides.annotations
|
|
1350
|
+
...metadataOverrides.annotations,
|
|
1373
1351
|
requiresPayment: metadataOverrides.annotations?.requiresPayment ?? true
|
|
1374
1352
|
}
|
|
1375
1353
|
};
|
|
@@ -1831,19 +1809,12 @@ async function writeMcpServer(options) {
|
|
|
1831
1809
|
}
|
|
1832
1810
|
function writeToolsManifest(options) {
|
|
1833
1811
|
const manifestPath = path6.join(options.outputDir, "tools.json");
|
|
1834
|
-
const legacyManifestPath = path6.join(
|
|
1835
|
-
options.outputDir,
|
|
1836
|
-
".well-known",
|
|
1837
|
-
"opentool",
|
|
1838
|
-
"cron.json"
|
|
1839
|
-
);
|
|
1812
|
+
const legacyManifestPath = path6.join(options.outputDir, ".well-known", "opentool", "cron.json");
|
|
1840
1813
|
if (fs4.existsSync(legacyManifestPath)) {
|
|
1841
1814
|
fs4.rmSync(legacyManifestPath, { force: true });
|
|
1842
1815
|
}
|
|
1843
1816
|
const entries = options.tools.map((tool) => {
|
|
1844
|
-
const compiled = options.compiledTools.find(
|
|
1845
|
-
(artifact) => artifact.filename === tool.filename
|
|
1846
|
-
);
|
|
1817
|
+
const compiled = options.compiledTools.find((artifact) => artifact.filename === tool.filename);
|
|
1847
1818
|
if (!compiled) {
|
|
1848
1819
|
throw new Error(`Internal error: missing compiled artifact for ${tool.filename}`);
|
|
1849
1820
|
}
|
|
@@ -1947,10 +1918,8 @@ async function devCommand(options) {
|
|
|
1947
1918
|
return;
|
|
1948
1919
|
}
|
|
1949
1920
|
reloading = true;
|
|
1950
|
-
log(
|
|
1951
|
-
|
|
1952
|
-
Detected change in ${changedPath ?? "tools directory"}, reloading...${reset}`
|
|
1953
|
-
);
|
|
1921
|
+
log(`${dim}
|
|
1922
|
+
Detected change in ${changedPath ?? "tools directory"}, reloading...${reset}`);
|
|
1954
1923
|
try {
|
|
1955
1924
|
toolDefinitions = await loadToolDefinitions(toolsDir, projectRoot);
|
|
1956
1925
|
routes = expandRoutes(toolDefinitions);
|
|
@@ -1983,9 +1952,7 @@ Detected change in ${changedPath ?? "tools directory"}, reloading...${reset}`
|
|
|
1983
1952
|
log(`${dim}[request] ${method} ${routePath}${reset}`);
|
|
1984
1953
|
try {
|
|
1985
1954
|
await handleRequest({ req, res, port, routes });
|
|
1986
|
-
log(
|
|
1987
|
-
`${dim}[response] ${method} ${routePath} ${res.statusCode}${reset}`
|
|
1988
|
-
);
|
|
1955
|
+
log(`${dim}[response] ${method} ${routePath} ${res.statusCode}${reset}`);
|
|
1989
1956
|
} catch (error) {
|
|
1990
1957
|
console.error("Error handling request:", error);
|
|
1991
1958
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
@@ -1995,9 +1962,7 @@ Detected change in ${changedPath ?? "tools directory"}, reloading...${reset}`
|
|
|
1995
1962
|
});
|
|
1996
1963
|
server.listen(port, () => {
|
|
1997
1964
|
log(`${bold}${dim}> dev opentool${reset}`);
|
|
1998
|
-
log(
|
|
1999
|
-
` * ${bold}opentool${reset} ${cyan}v${packageJson.version}${reset}`
|
|
2000
|
-
);
|
|
1965
|
+
log(` * ${bold}opentool${reset} ${cyan}v${packageJson.version}${reset}`);
|
|
2001
1966
|
log(` * ${bold}HTTP:${reset} http://localhost:${port}`);
|
|
2002
1967
|
logStartup(toolDefinitions, enableStdio, log);
|
|
2003
1968
|
});
|
|
@@ -2050,9 +2015,7 @@ async function startMcpServer(getTools) {
|
|
|
2050
2015
|
throw new Error(`Tool ${request.params.name} not found`);
|
|
2051
2016
|
}
|
|
2052
2017
|
try {
|
|
2053
|
-
const validatedParams = tool.schema.parse(
|
|
2054
|
-
request.params.arguments
|
|
2055
|
-
);
|
|
2018
|
+
const validatedParams = tool.schema.parse(request.params.arguments);
|
|
2056
2019
|
const handler = tool.handler ?? createMcpAdapter({
|
|
2057
2020
|
name: tool.metadata?.name ?? tool.filename,
|
|
2058
2021
|
httpHandlers: toHttpHandlerMap2(tool.httpHandlers),
|
|
@@ -2136,10 +2099,7 @@ function printToolList(tools, log) {
|
|
|
2136
2099
|
async function handleRequest(params) {
|
|
2137
2100
|
const { req, res, port, routes } = params;
|
|
2138
2101
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2139
|
-
res.setHeader(
|
|
2140
|
-
"Access-Control-Allow-Methods",
|
|
2141
|
-
HTTP_METHODS.join(", ") + ", OPTIONS"
|
|
2142
|
-
);
|
|
2102
|
+
res.setHeader("Access-Control-Allow-Methods", HTTP_METHODS.join(", ") + ", OPTIONS");
|
|
2143
2103
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
2144
2104
|
if (req.method === "OPTIONS") {
|
|
2145
2105
|
res.writeHead(200);
|
|
@@ -2192,9 +2152,7 @@ function findRoute(toolName, method, routes) {
|
|
|
2192
2152
|
return direct;
|
|
2193
2153
|
}
|
|
2194
2154
|
if (method === "HEAD") {
|
|
2195
|
-
return routes.find(
|
|
2196
|
-
(route) => routeName(route.tool) === toolName && route.method === "GET"
|
|
2197
|
-
);
|
|
2155
|
+
return routes.find((route) => routeName(route.tool) === toolName && route.method === "GET");
|
|
2198
2156
|
}
|
|
2199
2157
|
return void 0;
|
|
2200
2158
|
}
|
|
@@ -2241,13 +2199,10 @@ function createWebRequest(params) {
|
|
|
2241
2199
|
return new Request(url, init);
|
|
2242
2200
|
}
|
|
2243
2201
|
function toHttpHandlerMap2(handlers) {
|
|
2244
|
-
return handlers.reduce(
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
},
|
|
2249
|
-
{}
|
|
2250
|
-
);
|
|
2202
|
+
return handlers.reduce((acc, handler) => {
|
|
2203
|
+
acc[handler.method.toUpperCase()] = handler.handler;
|
|
2204
|
+
return acc;
|
|
2205
|
+
}, {});
|
|
2251
2206
|
}
|
|
2252
2207
|
function isMcpEnabled(tool) {
|
|
2253
2208
|
return Boolean(tool.mcpConfig?.enabled);
|
|
@@ -2347,7 +2302,7 @@ async function updateMetadata(targetDir, name, description) {
|
|
|
2347
2302
|
const raw = await promises.readFile(filePath, "utf-8");
|
|
2348
2303
|
const displayName = toDisplayName(name);
|
|
2349
2304
|
const resolvedDescription = description || "OpenTool project";
|
|
2350
|
-
const updated = raw.replace(/name:\s
|
|
2305
|
+
const updated = raw.replace(/name:\s*".*?"/, `name: "${toPackageName(name)}"`).replace(/displayName:\s*".*?"/, `displayName: "${displayName}"`).replace(/description:\s*".*?"/, `description: "${resolvedDescription}"`);
|
|
2351
2306
|
await promises.writeFile(filePath, updated, "utf-8");
|
|
2352
2307
|
}
|
|
2353
2308
|
async function initCommand(options) {
|
|
@@ -2355,9 +2310,7 @@ async function initCommand(options) {
|
|
|
2355
2310
|
const templateDir = resolveTemplateDir();
|
|
2356
2311
|
const empty = await directoryIsEmpty(targetDir);
|
|
2357
2312
|
if (!empty && !options.force) {
|
|
2358
|
-
throw new Error(
|
|
2359
|
-
`Directory not empty: ${targetDir}. Use --force to overwrite.`
|
|
2360
|
-
);
|
|
2313
|
+
throw new Error(`Directory not empty: ${targetDir}. Use --force to overwrite.`);
|
|
2361
2314
|
}
|
|
2362
2315
|
await copyDir(templateDir, targetDir);
|
|
2363
2316
|
const projectName = options.name || path6__default.basename(targetDir);
|
|
@@ -2379,11 +2332,7 @@ program.command("dev").description("Start HTTP dev server (optional MCP stdio)")
|
|
|
2379
2332
|
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);
|
|
2380
2333
|
program.command("validate").description("Validate metadata for registry submission").option("-i, --input <dir>", "Input directory containing tools", "tools").action(validateCommand);
|
|
2381
2334
|
program.command("validate-full").description("Full validation of tools and metadata").option("-i, --input <dir>", "Input directory containing tools", "tools").action(validateFullCommand);
|
|
2382
|
-
program.command("metadata").description("Generate OpenTool metadata JSON without building").option("-i, --input <dir>", "Input directory containing tools", "tools").option(
|
|
2383
|
-
"-o, --output <file>",
|
|
2384
|
-
"Output file path for metadata.json",
|
|
2385
|
-
"metadata.json"
|
|
2386
|
-
).option("--name <name>", "Server name", "opentool-server").option("--version <version>", "Server version", "1.0.0").action(generateMetadataCommand);
|
|
2335
|
+
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);
|
|
2387
2336
|
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) => {
|
|
2388
2337
|
await initCommand({
|
|
2389
2338
|
dir: cmdOptions.dir,
|