opentool 0.10.5 → 0.12.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/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
- import * as fs4 from 'fs';
5
- import * as path5 from 'path';
6
- import { fileURLToPath, pathToFileURL } from 'url';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ import { fileURLToPath } from 'url';
7
7
  import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
8
8
  import { z } from 'zod';
9
9
  import { zeroAddress, createWalletClient, http, createPublicClient, parseUnits, encodeFunctionData, erc20Abi } from 'viem';
@@ -15,9 +15,6 @@ import { encode } from '@msgpack/msgpack';
15
15
  import { keccak_256 } from '@noble/hashes/sha3';
16
16
  import { hexToBytes, concatBytes, bytesToHex } from '@noble/hashes/utils';
17
17
  import { createHmac, randomBytes } from 'crypto';
18
- import { tmpdir } from 'os';
19
- import { build } from 'esbuild';
20
- import { createRequire } from 'module';
21
18
 
22
19
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
23
20
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -699,16 +696,16 @@ function buildAdapters(tools) {
699
696
  }
700
697
  async function loadToolsFromDirectory(metadataMap) {
701
698
  const tools = [];
702
- const toolsDir = path5.join(process.cwd(), "tools");
703
- if (!fs4.existsSync(toolsDir)) {
699
+ const toolsDir = path.join(process.cwd(), "tools");
700
+ if (!fs.existsSync(toolsDir)) {
704
701
  return tools;
705
702
  }
706
- const files = fs4.readdirSync(toolsDir);
703
+ const files = fs.readdirSync(toolsDir);
707
704
  for (const file of files) {
708
705
  if (!isSupportedToolFile(file)) {
709
706
  continue;
710
707
  }
711
- const toolPath = path5.join(toolsDir, file);
708
+ const toolPath = path.join(toolsDir, file);
712
709
  try {
713
710
  const exportsObject = __require(toolPath);
714
711
  const candidate = resolveModuleCandidate(exportsObject);
@@ -772,12 +769,12 @@ async function loadToolsFromDirectory(metadataMap) {
772
769
  return tools;
773
770
  }
774
771
  function loadMetadata() {
775
- const metadataPath = path5.join(process.cwd(), "metadata.json");
776
- if (!fs4.existsSync(metadataPath)) {
772
+ const metadataPath = path.join(process.cwd(), "metadata.json");
773
+ if (!fs.existsSync(metadataPath)) {
777
774
  return null;
778
775
  }
779
776
  try {
780
- const contents = fs4.readFileSync(metadataPath, "utf8");
777
+ const contents = fs.readFileSync(metadataPath, "utf8");
781
778
  return JSON.parse(contents);
782
779
  } catch (error) {
783
780
  console.warn(`Failed to parse metadata.json: ${error}`);
@@ -894,7 +891,7 @@ function resolveRuntimePath(value) {
894
891
  if (value.startsWith("file://")) {
895
892
  return fileURLToPath(value);
896
893
  }
897
- return path5.resolve(value);
894
+ return path.resolve(value);
898
895
  }
899
896
 
900
897
  // src/types/index.ts
@@ -1724,8 +1721,8 @@ async function store(input, options) {
1724
1721
  );
1725
1722
  }
1726
1723
  const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
1727
- const path7 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
1728
- const url = `${baseUrl}${path7}`;
1724
+ const path2 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
1725
+ const url = `${baseUrl}${path2}`;
1729
1726
  let response;
1730
1727
  try {
1731
1728
  response = await fetchFn(url, {
@@ -1765,8 +1762,8 @@ async function store(input, options) {
1765
1762
  async function retrieve(params, options) {
1766
1763
  const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
1767
1764
  const mode = params?.mode ?? "live";
1768
- const path7 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
1769
- const url = new URL(`${baseUrl}${path7}`);
1765
+ const path2 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
1766
+ const url = new URL(`${baseUrl}${path2}`);
1770
1767
  if (params?.source) url.searchParams.set("source", params.source);
1771
1768
  if (params?.walletAddress) url.searchParams.set("walletAddress", params.walletAddress);
1772
1769
  if (params?.symbol) url.searchParams.set("symbol", params.symbol);
@@ -5113,19 +5110,19 @@ function parseOptionalDate(value) {
5113
5110
  return null;
5114
5111
  }
5115
5112
  function buildHmacSignature(args) {
5116
- const timestamp2 = args.timestamp.toString();
5113
+ const timestamp = args.timestamp.toString();
5117
5114
  const method = args.method.toUpperCase();
5118
- const path7 = args.path;
5115
+ const path2 = args.path;
5119
5116
  const body = args.body == null ? "" : typeof args.body === "string" ? args.body : JSON.stringify(args.body);
5120
- const payload = `${timestamp2}${method}${path7}${body}`;
5117
+ const payload = `${timestamp}${method}${path2}${body}`;
5121
5118
  const key = Buffer.from(args.secret, "base64");
5122
5119
  return createHmac("sha256", key).update(payload).digest("hex");
5123
5120
  }
5124
5121
  function buildL2Headers(args) {
5125
- const timestamp2 = args.timestamp ?? Math.floor(Date.now() / 1e3);
5122
+ const timestamp = args.timestamp ?? Math.floor(Date.now() / 1e3);
5126
5123
  const signature = buildHmacSignature({
5127
5124
  secret: args.credentials.secret,
5128
- timestamp: timestamp2,
5125
+ timestamp,
5129
5126
  method: args.method,
5130
5127
  path: args.path,
5131
5128
  body: args.body ?? null
@@ -5134,13 +5131,13 @@ function buildL2Headers(args) {
5134
5131
  POLY_ADDRESS: args.address,
5135
5132
  POLY_API_KEY: args.credentials.apiKey,
5136
5133
  POLY_PASSPHRASE: args.credentials.passphrase,
5137
- POLY_TIMESTAMP: timestamp2.toString(),
5134
+ POLY_TIMESTAMP: timestamp.toString(),
5138
5135
  POLY_SIGNATURE: signature
5139
5136
  };
5140
5137
  }
5141
5138
  async function buildL1Headers(args) {
5142
5139
  assertWalletSigner(args.wallet);
5143
- const timestamp2 = args.timestamp ?? Math.floor(Date.now() / 1e3);
5140
+ const timestamp = args.timestamp ?? Math.floor(Date.now() / 1e3);
5144
5141
  const nonce = args.nonce ?? Date.now();
5145
5142
  const chainId = POLYMARKET_CHAIN_ID[args.environment ?? "mainnet"];
5146
5143
  const address = args.wallet.address;
@@ -5162,14 +5159,14 @@ async function buildL1Headers(args) {
5162
5159
  primaryType: "ClobAuth",
5163
5160
  message: {
5164
5161
  address,
5165
- timestamp: timestamp2.toString(),
5162
+ timestamp: timestamp.toString(),
5166
5163
  nonce: BigInt(nonce),
5167
5164
  message
5168
5165
  }
5169
5166
  });
5170
5167
  return {
5171
5168
  POLY_ADDRESS: address,
5172
- POLY_TIMESTAMP: timestamp2.toString(),
5169
+ POLY_TIMESTAMP: timestamp.toString(),
5173
5170
  POLY_NONCE: nonce.toString(),
5174
5171
  POLY_SIGNATURE: signature
5175
5172
  };
@@ -6410,8 +6407,8 @@ async function streamText(options, clientConfig = {}) {
6410
6407
  const handlers = options.handlers ?? {};
6411
6408
  let finishedResolve;
6412
6409
  let finishedReject;
6413
- const finished = new Promise((resolve4, reject) => {
6414
- finishedResolve = resolve4;
6410
+ const finished = new Promise((resolve2, reject) => {
6411
+ finishedResolve = resolve2;
6415
6412
  finishedReject = reject;
6416
6413
  });
6417
6414
  let settled = false;
@@ -6640,9 +6637,9 @@ function assignIfDefined(target, key, value) {
6640
6637
  target[key] = value;
6641
6638
  }
6642
6639
  }
6643
- function buildUrl(baseUrl, path7) {
6640
+ function buildUrl(baseUrl, path2) {
6644
6641
  const sanitizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
6645
- return `${sanitizedBase}${path7}`;
6642
+ return `${sanitizedBase}${path2}`;
6646
6643
  }
6647
6644
  function createAbortBundle(upstreamSignal, timeoutMs) {
6648
6645
  const controller = new AbortController();
@@ -6846,1085 +6843,7 @@ function buildBacktestDecisionSeriesInput(request) {
6846
6843
  ...accountValueUsd != null ? { accountValueUsd } : {}
6847
6844
  };
6848
6845
  }
6849
- var METADATA_SPEC_VERSION = "1.1.0";
6850
- var McpAnnotationsSchema = z.object({
6851
- title: z.string().optional(),
6852
- readOnlyHint: z.boolean().optional(),
6853
- destructiveHint: z.boolean().optional(),
6854
- idempotentHint: z.boolean().optional(),
6855
- openWorldHint: z.boolean().optional(),
6856
- requiresPayment: z.boolean().optional()
6857
- }).strict();
6858
- var X402PaymentSchema = z.object({
6859
- definition: z.object({
6860
- amount: z.string(),
6861
- currency: z.object({
6862
- code: z.string(),
6863
- symbol: z.string(),
6864
- decimals: z.number()
6865
- }),
6866
- asset: z.object({
6867
- symbol: z.string(),
6868
- network: z.string(),
6869
- address: z.string(),
6870
- decimals: z.number()
6871
- }),
6872
- payTo: z.string(),
6873
- resource: z.string().optional(),
6874
- description: z.string().optional(),
6875
- scheme: z.string(),
6876
- network: z.string(),
6877
- facilitator: z.object({
6878
- url: z.string(),
6879
- verifyPath: z.string().optional(),
6880
- settlePath: z.string().optional(),
6881
- apiKeyHeader: z.string().optional()
6882
- }),
6883
- metadata: z.record(z.string(), z.unknown()).optional()
6884
- }),
6885
- metadata: z.record(z.string(), z.unknown()).optional()
6886
- }).passthrough();
6887
- var PaymentConfigSchema = z.union([X402PaymentSchema, z.record(z.string(), z.unknown())]);
6888
- var DiscoveryMetadataSchema = z.object({
6889
- keywords: z.array(z.string()).optional(),
6890
- category: z.string().optional(),
6891
- useCases: z.array(z.string()).optional(),
6892
- capabilities: z.array(z.string()).optional(),
6893
- requirements: z.record(z.string(), z.any()).optional(),
6894
- compatibility: z.record(z.string(), z.any()).optional(),
6895
- documentation: z.union([z.string(), z.array(z.string())]).optional()
6896
- }).catchall(z.any());
6897
- var ToolCategorySchema = z.enum(["strategy", "tracker", "orchestrator"]);
6898
- var ToolMetadataOverridesSchema = z.object({
6899
- name: z.string().optional(),
6900
- description: z.string().optional(),
6901
- annotations: McpAnnotationsSchema.optional(),
6902
- payment: PaymentConfigSchema.optional(),
6903
- discovery: DiscoveryMetadataSchema.optional(),
6904
- chains: z.array(z.union([z.string(), z.number()])).optional()
6905
- }).catchall(z.any());
6906
- var ToolSchema = z.object({
6907
- name: z.string(),
6908
- description: z.string(),
6909
- inputSchema: z.any(),
6910
- annotations: McpAnnotationsSchema.optional(),
6911
- payment: PaymentConfigSchema.optional(),
6912
- discovery: DiscoveryMetadataSchema.optional(),
6913
- chains: z.array(z.union([z.string(), z.number()])).optional(),
6914
- notifyEmail: z.boolean().optional(),
6915
- category: ToolCategorySchema.optional()
6916
- }).strict();
6917
- var MetadataSchema = z.object({
6918
- metadataSpecVersion: z.string().optional(),
6919
- name: z.string().optional(),
6920
- displayName: z.string().optional(),
6921
- version: z.string().optional(),
6922
- description: z.string().optional(),
6923
- author: z.string().optional(),
6924
- repository: z.string().optional(),
6925
- website: z.string().optional(),
6926
- category: z.string().optional(),
6927
- categories: z.array(z.string()).optional(),
6928
- termsOfService: z.string().optional(),
6929
- mcpUrl: z.string().optional(),
6930
- payment: PaymentConfigSchema.optional(),
6931
- discovery: DiscoveryMetadataSchema.optional(),
6932
- promptExamples: z.array(z.string()).optional(),
6933
- iconPath: z.string().optional(),
6934
- videoPath: z.string().optional(),
6935
- image: z.string().optional(),
6936
- animation_url: z.string().optional(),
6937
- keywords: z.array(z.string()).optional(),
6938
- useCases: z.array(z.string()).optional(),
6939
- capabilities: z.array(z.string()).optional(),
6940
- requirements: z.record(z.string(), z.any()).optional(),
6941
- compatibility: z.record(z.string(), z.any()).optional(),
6942
- chains: z.array(z.union([z.string(), z.number()])).optional()
6943
- }).catchall(z.any());
6944
- var BuildMetadataSchema = z.object({
6945
- metadataSpecVersion: z.string().default(METADATA_SPEC_VERSION),
6946
- name: z.string(),
6947
- displayName: z.string(),
6948
- version: z.string(),
6949
- description: z.string().optional(),
6950
- author: z.string().optional(),
6951
- repository: z.string().optional(),
6952
- website: z.string().optional(),
6953
- category: z.string(),
6954
- termsOfService: z.string().optional(),
6955
- mcpUrl: z.string().optional(),
6956
- payment: PaymentConfigSchema.optional(),
6957
- tools: z.array(ToolSchema).min(1),
6958
- discovery: DiscoveryMetadataSchema.optional(),
6959
- promptExamples: z.array(z.string()).optional(),
6960
- iconPath: z.string().optional(),
6961
- videoPath: z.string().optional(),
6962
- image: z.string().optional(),
6963
- animation_url: z.string().optional(),
6964
- chains: z.array(z.union([z.string(), z.number()])).optional()
6965
- }).strict();
6966
- function resolveTsconfig(projectRoot) {
6967
- const candidate = path5.join(projectRoot, "tsconfig.json");
6968
- if (fs4.existsSync(candidate)) {
6969
- return candidate;
6970
- }
6971
- return void 0;
6972
- }
6973
- async function transpileWithEsbuild(options) {
6974
- if (options.entryPoints.length === 0) {
6975
- throw new Error("No entry points provided for esbuild transpilation");
6976
- }
6977
- const projectRoot = options.projectRoot;
6978
- const tempBase = options.outDir ?? fs4.mkdtempSync(path5.join(tmpdir(), "opentool-"));
6979
- if (!fs4.existsSync(tempBase)) {
6980
- fs4.mkdirSync(tempBase, { recursive: true });
6981
- }
6982
- const tsconfig = resolveTsconfig(projectRoot);
6983
- const buildOptions = {
6984
- entryPoints: options.entryPoints,
6985
- outdir: tempBase,
6986
- bundle: options.bundle ?? false,
6987
- format: options.format,
6988
- platform: "node",
6989
- target: "node20",
6990
- logLevel: options.logLevel ?? "warning",
6991
- sourcesContent: false,
6992
- sourcemap: false,
6993
- loader: {
6994
- ".ts": "ts",
6995
- ".tsx": "tsx",
6996
- ".cts": "ts",
6997
- ".mts": "ts",
6998
- ".js": "js",
6999
- ".jsx": "jsx",
7000
- ".mjs": "js",
7001
- ".cjs": "js",
7002
- ".json": "json"
7003
- },
7004
- metafile: options.metafile ?? false,
7005
- allowOverwrite: true,
7006
- absWorkingDir: projectRoot
7007
- };
7008
- if (options.external && options.external.length > 0) {
7009
- buildOptions.external = options.external;
7010
- }
7011
- if (options.nodePaths && options.nodePaths.length > 0) {
7012
- buildOptions.nodePaths = options.nodePaths;
7013
- }
7014
- if (options.outBase) {
7015
- buildOptions.outbase = options.outBase;
7016
- }
7017
- if (!buildOptions.bundle) {
7018
- buildOptions.packages = "external";
7019
- }
7020
- if (tsconfig) {
7021
- buildOptions.tsconfig = tsconfig;
7022
- }
7023
- await build(buildOptions);
7024
- if (options.format === "esm") {
7025
- const packageJsonPath = path5.join(tempBase, "package.json");
7026
- if (!fs4.existsSync(packageJsonPath)) {
7027
- fs4.writeFileSync(packageJsonPath, JSON.stringify({ type: "module" }), "utf8");
7028
- }
7029
- }
7030
- const cleanup = () => {
7031
- if (options.outDir) {
7032
- return;
7033
- }
7034
- fs4.rmSync(tempBase, { recursive: true, force: true });
7035
- };
7036
- return { outDir: tempBase, cleanup };
7037
- }
7038
- createRequire(
7039
- typeof __filename !== "undefined" ? __filename : import.meta.url
7040
- );
7041
- function resolveCompiledPath(outDir, originalFile, extension = ".js") {
7042
- const baseName = path5.basename(originalFile).replace(/\.[^.]+$/, "");
7043
- return path5.join(outDir, `${baseName}${extension}`);
7044
- }
7045
- async function importFresh(modulePath) {
7046
- const fileUrl = pathToFileURL(modulePath).href;
7047
- const cacheBuster = `t=${Date.now()}-${Math.random()}`;
7048
- const separator = fileUrl.includes("?") ? "&" : "?";
7049
- return import(`${fileUrl}${separator}${cacheBuster}`);
7050
- }
7051
-
7052
- // src/cli/shared/metadata.ts
7053
- var METADATA_ENTRY = "metadata.ts";
7054
- async function loadMetadata2(projectRoot) {
7055
- const absPath = path5.join(projectRoot, METADATA_ENTRY);
7056
- if (!fs4.existsSync(absPath)) {
7057
- return {
7058
- metadata: MetadataSchema.parse({}),
7059
- sourcePath: "smart defaults (metadata.ts missing)"
7060
- };
7061
- }
7062
- const tempDir = path5.join(projectRoot, ".opentool-temp");
7063
- if (fs4.existsSync(tempDir)) {
7064
- fs4.rmSync(tempDir, { recursive: true, force: true });
7065
- }
7066
- const { outDir, cleanup } = await transpileWithEsbuild({
7067
- entryPoints: [absPath],
7068
- projectRoot,
7069
- format: "esm",
7070
- outDir: tempDir
7071
- });
7072
- try {
7073
- const compiledPath = resolveCompiledPath(outDir, METADATA_ENTRY);
7074
- const moduleExports = await importFresh(compiledPath);
7075
- const metadataExport = extractMetadataExport(moduleExports);
7076
- const parsed = MetadataSchema.parse(metadataExport);
7077
- return { metadata: parsed, sourcePath: absPath };
7078
- } finally {
7079
- cleanup();
7080
- if (fs4.existsSync(tempDir)) {
7081
- fs4.rmSync(tempDir, { recursive: true, force: true });
7082
- }
7083
- }
7084
- }
7085
- function extractMetadataExport(moduleExports) {
7086
- if (!moduleExports || typeof moduleExports !== "object") {
7087
- throw new Error("metadata.ts must export a metadata object");
7088
- }
7089
- const exportsObject = moduleExports;
7090
- if (exportsObject.metadata) {
7091
- return exportsObject.metadata;
7092
- }
7093
- if (exportsObject.default && typeof exportsObject.default === "object") {
7094
- const defaultExport = exportsObject.default;
7095
- if (defaultExport.metadata) {
7096
- return defaultExport.metadata;
7097
- }
7098
- return defaultExport;
7099
- }
7100
- return moduleExports;
7101
- }
7102
- function readPackageJson(projectRoot) {
7103
- const packagePath = path5.join(projectRoot, "package.json");
7104
- if (!fs4.existsSync(packagePath)) {
7105
- return {};
7106
- }
7107
- try {
7108
- const content = fs4.readFileSync(packagePath, "utf8");
7109
- return JSON.parse(content);
7110
- } catch (error) {
7111
- throw new Error(`Failed to read package.json: ${error}`);
7112
- }
7113
- }
7114
- async function buildMetadataArtifact(options) {
7115
- const projectRoot = options.projectRoot;
7116
- const packageInfo = readPackageJson(projectRoot);
7117
- const { metadata: authored, sourcePath } = await loadMetadata2(projectRoot);
7118
- const defaultsApplied = [];
7119
- const folderName = path5.basename(projectRoot);
7120
- const name = resolveField(
7121
- "name",
7122
- authored.name,
7123
- () => packageInfo.name ?? folderName,
7124
- defaultsApplied,
7125
- "package.json name"
7126
- );
7127
- const displayName = resolveField(
7128
- "displayName",
7129
- authored.displayName,
7130
- () => {
7131
- const source = packageInfo.name ?? folderName;
7132
- return source.split(/[-_]/).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join(" ");
7133
- },
7134
- defaultsApplied,
7135
- "package.json name"
7136
- );
7137
- const versionRaw = resolveField(
7138
- "version",
7139
- authored.version,
7140
- () => packageInfo.version ?? "0.1.0",
7141
- defaultsApplied,
7142
- "package.json version"
7143
- );
7144
- const version = typeof versionRaw === "number" ? String(versionRaw) : versionRaw;
7145
- const category = determineCategory(authored, defaultsApplied);
7146
- const description = authored.description ?? packageInfo.description;
7147
- if (!authored.description && packageInfo.description) {
7148
- defaultsApplied.push("description \u2192 package.json description");
7149
- }
7150
- const author = authored.author ?? packageInfo.author;
7151
- if (!authored.author && packageInfo.author) {
7152
- defaultsApplied.push("author \u2192 package.json author");
7153
- }
7154
- const repository = authored.repository ?? extractRepository(packageInfo.repository);
7155
- if (!authored.repository && repository) {
7156
- defaultsApplied.push("repository \u2192 package.json repository");
7157
- }
7158
- const website = authored.website ?? packageInfo.homepage;
7159
- if (!authored.website && packageInfo.homepage) {
7160
- defaultsApplied.push("website \u2192 package.json homepage");
7161
- }
7162
- const payment = resolvePayment(authored);
7163
- const baseImage = authored.image ?? authored.iconPath;
7164
- const animation = authored.animation_url ?? authored.videoPath;
7165
- const discovery = buildDiscovery(authored);
7166
- const metadataTools = options.tools.map((tool) => {
7167
- const overrides = tool.metadata ? ToolMetadataOverridesSchema.parse(tool.metadata) : {};
7168
- const toolName = overrides.name ?? tool.filename;
7169
- const toolDescription = overrides.description ?? `${toolName} tool`;
7170
- const toolPayment = overrides.payment ?? payment ?? void 0;
7171
- if (!overrides.payment && toolPayment && payment && toolPayment === payment) {
7172
- defaultsApplied.push(`tool ${toolName} payment \u2192 agent payment`);
7173
- }
7174
- const toolDiscovery = overrides.discovery ?? void 0;
7175
- const toolChains = overrides.chains ?? authored.chains ?? void 0;
7176
- const toolCategory = tool.profileCategory ?? "tracker";
7177
- if (!tool.profileCategory) {
7178
- defaultsApplied.push(`tool ${toolName} category \u2192 tracker (default)`);
7179
- }
7180
- const toolDefinition = {
7181
- name: toolName,
7182
- description: toolDescription,
7183
- inputSchema: tool.inputSchema
7184
- };
7185
- if (overrides.annotations) {
7186
- toolDefinition.annotations = overrides.annotations;
7187
- }
7188
- if (toolPayment) {
7189
- toolDefinition.payment = toolPayment;
7190
- }
7191
- if (toolDiscovery) {
7192
- toolDefinition.discovery = toolDiscovery;
7193
- }
7194
- if (toolChains) {
7195
- toolDefinition.chains = toolChains;
7196
- }
7197
- toolDefinition.category = toolCategory;
7198
- const notifyEmail = tool.notifyEmail ?? tool.schedule?.notifyEmail;
7199
- if (notifyEmail !== void 0) {
7200
- toolDefinition.notifyEmail = notifyEmail;
7201
- }
7202
- if (tool.profileCategory) {
7203
- toolDefinition.category = tool.profileCategory;
7204
- }
7205
- return toolDefinition;
7206
- });
7207
- const metadata = BuildMetadataSchema.parse({
7208
- metadataSpecVersion: authored.metadataSpecVersion ?? METADATA_SPEC_VERSION,
7209
- name,
7210
- displayName,
7211
- version,
7212
- description,
7213
- author,
7214
- repository,
7215
- website,
7216
- category,
7217
- termsOfService: authored.termsOfService,
7218
- mcpUrl: authored.mcpUrl,
7219
- payment: payment ?? void 0,
7220
- tools: metadataTools,
7221
- discovery,
7222
- promptExamples: authored.promptExamples,
7223
- iconPath: authored.iconPath,
7224
- videoPath: authored.videoPath,
7225
- image: baseImage,
7226
- animation_url: animation,
7227
- chains: authored.chains
7228
- });
7229
- return {
7230
- metadata,
7231
- defaultsApplied,
7232
- sourceMetadataPath: sourcePath
7233
- };
7234
- }
7235
- function resolveField(field, value, fallback, defaultsApplied, fallbackLabel) {
7236
- if (value !== void 0 && value !== null && value !== "") {
7237
- return value;
7238
- }
7239
- const resolved = fallback();
7240
- defaultsApplied.push(`${field} \u2192 ${fallbackLabel}`);
7241
- return resolved;
7242
- }
7243
- function determineCategory(authored, defaultsApplied) {
7244
- if (authored.category) {
7245
- return authored.category;
7246
- }
7247
- if (Array.isArray(authored.categories) && authored.categories.length > 0) {
7248
- defaultsApplied.push("category \u2192 metadata.categories[0]");
7249
- return authored.categories[0];
7250
- }
7251
- defaultsApplied.push("category \u2192 default category");
7252
- return "utility";
7253
- }
7254
- function extractRepository(repository) {
7255
- if (!repository) {
7256
- return void 0;
7257
- }
7258
- if (typeof repository === "string") {
7259
- return repository;
7260
- }
7261
- return repository.url;
7262
- }
7263
- function resolvePayment(authored, _defaults) {
7264
- return authored.payment ?? void 0;
7265
- }
7266
- function buildDiscovery(authored) {
7267
- const legacyDiscovery = {};
7268
- if (Array.isArray(authored.keywords) && authored.keywords.length > 0) {
7269
- legacyDiscovery.keywords = authored.keywords;
7270
- }
7271
- if (Array.isArray(authored.useCases) && authored.useCases.length > 0) {
7272
- legacyDiscovery.useCases = authored.useCases;
7273
- }
7274
- if (Array.isArray(authored.capabilities) && authored.capabilities.length > 0) {
7275
- legacyDiscovery.capabilities = authored.capabilities;
7276
- }
7277
- if (authored.requirements) {
7278
- legacyDiscovery.requirements = authored.requirements;
7279
- }
7280
- if (authored.compatibility) {
7281
- legacyDiscovery.compatibility = authored.compatibility;
7282
- }
7283
- if (Array.isArray(authored.categories) && authored.categories.length > 0) {
7284
- legacyDiscovery.category = authored.categories[0];
7285
- }
7286
- const merged = {
7287
- ...legacyDiscovery,
7288
- ...authored.discovery
7289
- };
7290
- return Object.keys(merged).length > 0 ? merged : void 0;
7291
- }
7292
-
7293
- // src/utils/schedule.ts
7294
- var CRON_WRAPPED_REGEX = /^cron\((.*)\)$/i;
7295
- var CRON_TOKEN_REGEX = /^[A-Za-z0-9*?/,\-#L]+$/;
7296
- function normalizeScheduleExpression(raw, context) {
7297
- const value = raw?.trim();
7298
- if (!value) {
7299
- throw new Error(`${context}: profile.schedule.cron must be a non-empty string`);
7300
- }
7301
- const cronBody = extractCronBody(value);
7302
- const cronFields = cronBody.trim().split(/\s+/).filter(Boolean);
7303
- if (cronFields.length !== 5 && cronFields.length !== 6) {
7304
- throw new Error(
7305
- `${context}: cron expression must have 5 or 6 fields (got ${cronFields.length})`
7306
- );
7307
- }
7308
- validateCronTokens(cronFields, context);
7309
- return {
7310
- type: "cron",
7311
- expression: cronFields.join(" ")
7312
- };
7313
- }
7314
- function extractCronBody(value) {
7315
- const cronMatch = CRON_WRAPPED_REGEX.exec(value);
7316
- if (cronMatch) {
7317
- return (cronMatch[1] ?? "").trim();
7318
- }
7319
- return value;
7320
- }
7321
- function validateCronTokens(fields, context) {
7322
- fields.forEach((token2, idx) => {
7323
- if (!CRON_TOKEN_REGEX.test(token2)) {
7324
- throw new Error(`${context}: invalid cron token "${token2}" at position ${idx + 1}`);
7325
- }
7326
- });
7327
- }
7328
-
7329
- // src/cli/validate.ts
7330
- var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
7331
- var OPENTOOL_ROOT = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "../..");
7332
- var OPENTOOL_NODE_MODULES = path5.join(OPENTOOL_ROOT, "node_modules");
7333
- var MIN_TEMPLATE_CONFIG_VERSION = 2;
7334
- var TEMPLATE_PREVIEW_TITLE_MAX = 80;
7335
- var TEMPLATE_PREVIEW_SUBTITLE_MAX = 120;
7336
- var TEMPLATE_PREVIEW_DESCRIPTION_MAX = 1200;
7337
- var TEMPLATE_PREVIEW_MIN_LINES = 3;
7338
- var TEMPLATE_PREVIEW_MAX_LINES = 8;
7339
- function normalizeTemplateConfigVersion(value) {
7340
- if (typeof value === "number" && Number.isFinite(value)) {
7341
- return value;
7342
- }
7343
- if (typeof value !== "string") {
7344
- return null;
7345
- }
7346
- const trimmed = value.trim();
7347
- if (!trimmed) {
7348
- return null;
7349
- }
7350
- if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
7351
- const numeric = Number.parseFloat(trimmed);
7352
- return Number.isFinite(numeric) ? numeric : null;
7353
- }
7354
- const majorMatch = /^v?(\d+)(?:\..*)?$/i.exec(trimmed);
7355
- if (!majorMatch) {
7356
- return null;
7357
- }
7358
- const major = Number.parseInt(majorMatch[1], 10);
7359
- return Number.isFinite(major) ? major : null;
7360
- }
7361
- function parseNonEmptyString(value, fieldPath, opts = {}) {
7362
- const { max, required = false } = opts;
7363
- if (value == null) {
7364
- if (required) {
7365
- throw new Error(`${fieldPath} is required and must be a non-empty string.`);
7366
- }
7367
- return null;
7368
- }
7369
- if (typeof value !== "string") {
7370
- throw new Error(`${fieldPath} must be a string.`);
7371
- }
7372
- const trimmed = value.trim();
7373
- if (!trimmed) {
7374
- throw new Error(`${fieldPath} must be a non-empty string.`);
7375
- }
7376
- if (typeof max === "number" && trimmed.length > max) {
7377
- throw new Error(`${fieldPath} must be <= ${max} characters.`);
7378
- }
7379
- return trimmed;
7380
- }
7381
- function normalizeTemplatePreview(value, file, toolName, requirePreview) {
7382
- const pathPrefix = `${file}: profile.templatePreview`;
7383
- if (value == null) {
7384
- if (requirePreview) {
7385
- throw new Error(
7386
- `${pathPrefix} is required for strategy tools and must define subtitle + description.`
7387
- );
7388
- }
7389
- return null;
7390
- }
7391
- if (!value || typeof value !== "object" || Array.isArray(value)) {
7392
- throw new Error(`${pathPrefix} must be an object.`);
7393
- }
7394
- const record = value;
7395
- const title = parseNonEmptyString(record.title, `${pathPrefix}.title`, {
7396
- max: TEMPLATE_PREVIEW_TITLE_MAX
7397
- }) ?? toolName;
7398
- const subtitle = parseNonEmptyString(record.subtitle, `${pathPrefix}.subtitle`, {
7399
- required: true,
7400
- max: TEMPLATE_PREVIEW_SUBTITLE_MAX
7401
- });
7402
- const description = parseNonEmptyString(record.description, `${pathPrefix}.description`, {
7403
- required: true,
7404
- max: TEMPLATE_PREVIEW_DESCRIPTION_MAX
7405
- });
7406
- const descriptionLineCount = description.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).length;
7407
- if (descriptionLineCount < TEMPLATE_PREVIEW_MIN_LINES || descriptionLineCount > TEMPLATE_PREVIEW_MAX_LINES) {
7408
- throw new Error(
7409
- `${pathPrefix}.description must contain ${TEMPLATE_PREVIEW_MIN_LINES}-${TEMPLATE_PREVIEW_MAX_LINES} non-empty lines (target ~5 lines).`
7410
- );
7411
- }
7412
- return {
7413
- title,
7414
- subtitle,
7415
- description
7416
- };
7417
- }
7418
- async function validateCommand(options) {
7419
- console.log("\u{1F50D} Validating OpenTool project...");
7420
- try {
7421
- const toolsDir = path5.resolve(options.input);
7422
- if (!fs4.existsSync(toolsDir)) {
7423
- throw new Error(`Tools directory not found: ${toolsDir}`);
7424
- }
7425
- const projectRoot = path5.dirname(toolsDir);
7426
- const tools = await loadAndValidateTools(toolsDir, { projectRoot });
7427
- if (tools.length === 0) {
7428
- throw new Error("No valid tools found - validation aborted");
7429
- }
7430
- const { metadata, defaultsApplied, sourceMetadataPath } = await buildMetadataArtifact({
7431
- projectRoot,
7432
- tools
7433
- });
7434
- logMetadataSummary(metadata, defaultsApplied, sourceMetadataPath);
7435
- console.log("\n\u2705 OpenTool validation passed!\n");
7436
- } catch (error) {
7437
- console.error("\u274C OpenTool validation failed:", error);
7438
- process.exit(1);
7439
- }
7440
- }
7441
- async function loadAndValidateTools(toolsDir, options = {}) {
7442
- const files = fs4.readdirSync(toolsDir).filter((file) => SUPPORTED_EXTENSIONS.includes(path5.extname(file)));
7443
- if (files.length === 0) {
7444
- return [];
7445
- }
7446
- const projectRoot = options.projectRoot ?? path5.dirname(toolsDir);
7447
- const tempDir = path5.join(toolsDir, ".opentool-temp");
7448
- if (fs4.existsSync(tempDir)) {
7449
- fs4.rmSync(tempDir, { recursive: true, force: true });
7450
- }
7451
- const kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z]+$/;
7452
- for (const f of files) {
7453
- if (!kebabCase.test(f)) {
7454
- throw new Error(`Tool filename must be kebab-case: ${f}`);
7455
- }
7456
- }
7457
- const entryPoints = files.map((file) => path5.join(toolsDir, file));
7458
- const fallbackNodePaths = [OPENTOOL_NODE_MODULES].filter((dir) => fs4.existsSync(dir));
7459
- const { outDir, cleanup } = await transpileWithEsbuild({
7460
- entryPoints,
7461
- projectRoot,
7462
- format: "esm",
7463
- outDir: tempDir,
7464
- bundle: true,
7465
- external: ["opentool", "opentool/*"],
7466
- ...fallbackNodePaths.length > 0 ? { nodePaths: fallbackNodePaths } : {}
7467
- });
7468
- const tools = [];
7469
- try {
7470
- ensureLocalRuntimeLinks(tempDir);
7471
- for (const file of files) {
7472
- const compiledPath = resolveCompiledPath(outDir, file);
7473
- if (!fs4.existsSync(compiledPath)) {
7474
- throw new Error(`Failed to compile ${file}`);
7475
- }
7476
- const moduleExports = await importFresh(compiledPath);
7477
- const toolModule = extractToolModule(moduleExports, file);
7478
- const schema = ensureZodSchema(toolModule.schema, file);
7479
- const paymentExport = toolModule.payment;
7480
- const toolName = toolModule.metadata?.name ?? toolModule.metadata?.title ?? toBaseName(file);
7481
- const inputSchemaRaw = schema ? toJsonSchema(toolName, schema) : void 0;
7482
- const inputSchema = normalizeInputSchema2(inputSchemaRaw);
7483
- const httpHandlersRaw = collectHttpHandlers2(toolModule, file);
7484
- const hasGET = typeof toolModule.GET === "function";
7485
- const hasPOST = typeof toolModule.POST === "function";
7486
- const otherMethods = HTTP_METHODS2.filter((m) => m !== "GET" && m !== "POST").filter(
7487
- (m) => typeof toolModule[m] === "function"
7488
- );
7489
- if (otherMethods.length > 0) {
7490
- throw new Error(
7491
- `${file} must not export ${otherMethods.join(", ")}. Only one of GET or POST is allowed.`
7492
- );
7493
- }
7494
- if (hasGET === hasPOST) {
7495
- throw new Error(`${file}: export exactly one of GET or POST`);
7496
- }
7497
- let normalizedSchedule = null;
7498
- const profileRaw = toolModule?.profile && typeof toolModule.profile === "object" ? toolModule.profile : null;
7499
- const schedule = profileRaw?.schedule ?? null;
7500
- const profileNotifyEmail = typeof profileRaw?.notifyEmail === "boolean" ? profileRaw.notifyEmail : void 0;
7501
- const allowedProfileCategories = ["strategy", "tracker", "orchestrator"];
7502
- const profileCategoryCandidate = typeof profileRaw?.category === "string" ? profileRaw.category : void 0;
7503
- let profileCategoryRaw;
7504
- if (profileCategoryCandidate !== void 0) {
7505
- const isAllowed = allowedProfileCategories.includes(
7506
- profileCategoryCandidate
7507
- );
7508
- if (!isAllowed) {
7509
- throw new Error(
7510
- `${file}: profile.category must be one of ${allowedProfileCategories.join(", ")}`
7511
- );
7512
- }
7513
- profileCategoryRaw = profileCategoryCandidate;
7514
- }
7515
- const profileAssetsRaw = profileRaw?.assets;
7516
- if (profileAssetsRaw !== void 0) {
7517
- if (!Array.isArray(profileAssetsRaw)) {
7518
- throw new Error(`${file}: profile.assets must be an array.`);
7519
- }
7520
- profileAssetsRaw.forEach((entry, index) => {
7521
- if (!entry || typeof entry !== "object") {
7522
- throw new Error(`${file}: profile.assets[${index}] must be an object.`);
7523
- }
7524
- const record = entry;
7525
- const venue = typeof record.venue === "string" ? record.venue.trim() : "";
7526
- if (!venue) {
7527
- throw new Error(`${file}: profile.assets[${index}].venue must be a non-empty string.`);
7528
- }
7529
- const chain = record.chain;
7530
- if (typeof chain !== "string" && typeof chain !== "number") {
7531
- throw new Error(`${file}: profile.assets[${index}].chain must be a string or number.`);
7532
- }
7533
- const symbols = record.assetSymbols;
7534
- if (!Array.isArray(symbols) || symbols.length === 0) {
7535
- throw new Error(
7536
- `${file}: profile.assets[${index}].assetSymbols must be a non-empty array.`
7537
- );
7538
- }
7539
- const invalidSymbol = symbols.find(
7540
- (symbol) => typeof symbol !== "string" || symbol.trim().length === 0
7541
- );
7542
- if (invalidSymbol !== void 0) {
7543
- throw new Error(
7544
- `${file}: profile.assets[${index}].assetSymbols must be non-empty strings.`
7545
- );
7546
- }
7547
- const walletAddress = record.walletAddress;
7548
- if (walletAddress !== void 0 && (typeof walletAddress !== "string" || walletAddress.trim().length === 0)) {
7549
- throw new Error(
7550
- `${file}: profile.assets[${index}].walletAddress must be a non-empty string when provided.`
7551
- );
7552
- }
7553
- const pair = record.pair;
7554
- if (pair !== void 0 && (typeof pair !== "string" || pair.trim().length === 0)) {
7555
- throw new Error(
7556
- `${file}: profile.assets[${index}].pair must be a non-empty string when provided.`
7557
- );
7558
- }
7559
- const leverage = record.leverage;
7560
- if (leverage !== void 0 && (typeof leverage !== "number" || !Number.isFinite(leverage) || leverage <= 0)) {
7561
- throw new Error(
7562
- `${file}: profile.assets[${index}].leverage must be a positive number when provided.`
7563
- );
7564
- }
7565
- });
7566
- }
7567
- const templateConfigRaw = profileRaw?.templateConfig;
7568
- if (templateConfigRaw !== void 0) {
7569
- if (!templateConfigRaw || typeof templateConfigRaw !== "object") {
7570
- throw new Error(`${file}: profile.templateConfig must be an object.`);
7571
- }
7572
- const record = templateConfigRaw;
7573
- const version = record.version;
7574
- const normalizedTemplateConfigVersion = normalizeTemplateConfigVersion(version);
7575
- if (normalizedTemplateConfigVersion === null) {
7576
- throw new Error(
7577
- `${file}: profile.templateConfig.version must be a numeric string or number.`
7578
- );
7579
- }
7580
- if (normalizedTemplateConfigVersion < MIN_TEMPLATE_CONFIG_VERSION) {
7581
- throw new Error(
7582
- `${file}: profile.templateConfig.version must be >= ${MIN_TEMPLATE_CONFIG_VERSION}.`
7583
- );
7584
- }
7585
- const schema2 = record.schema;
7586
- if (schema2 !== void 0 && (!schema2 || typeof schema2 !== "object" || Array.isArray(schema2))) {
7587
- throw new Error(
7588
- `${file}: profile.templateConfig.schema must be an object when provided.`
7589
- );
7590
- }
7591
- const defaults = record.defaults;
7592
- if (defaults !== void 0 && (!defaults || typeof defaults !== "object" || Array.isArray(defaults))) {
7593
- throw new Error(
7594
- `${file}: profile.templateConfig.defaults must be an object when provided.`
7595
- );
7596
- }
7597
- const envVar = record.envVar;
7598
- if (envVar !== void 0 && (typeof envVar !== "string" || envVar.trim().length === 0)) {
7599
- throw new Error(
7600
- `${file}: profile.templateConfig.envVar must be a non-empty string when provided.`
7601
- );
7602
- }
7603
- }
7604
- const normalizedTemplatePreview = normalizeTemplatePreview(
7605
- profileRaw?.templatePreview,
7606
- file,
7607
- toolName,
7608
- profileCategoryRaw === "strategy"
7609
- );
7610
- const normalizedProfile = profileRaw && normalizedTemplatePreview ? { ...profileRaw, templatePreview: normalizedTemplatePreview } : profileRaw;
7611
- if (hasGET && schedule && typeof schedule.cron === "string" && schedule.cron.trim().length > 0) {
7612
- normalizedSchedule = normalizeScheduleExpression(schedule.cron, file);
7613
- if (typeof schedule.enabled === "boolean") {
7614
- normalizedSchedule.authoredEnabled = schedule.enabled;
7615
- }
7616
- if (typeof schedule.notifyEmail === "boolean") {
7617
- normalizedSchedule.notifyEmail = schedule.notifyEmail;
7618
- }
7619
- }
7620
- if (hasPOST) {
7621
- if (!schema) {
7622
- throw new Error(`${file}: POST tools must export a Zod schema as 'schema'`);
7623
- }
7624
- }
7625
- const httpHandlers = [...httpHandlersRaw];
7626
- if (httpHandlers.length === 0) {
7627
- throw new Error(`${file} must export at least one HTTP handler (e.g. POST)`);
7628
- }
7629
- if (paymentExport) {
7630
- for (let index = 0; index < httpHandlers.length; index += 1) {
7631
- const entry = httpHandlers[index];
7632
- httpHandlers[index] = {
7633
- ...entry,
7634
- handler: withX402Payment(entry.handler, paymentExport)
7635
- };
7636
- }
7637
- }
7638
- const httpHandlerMap = toHttpHandlerMap2(httpHandlers);
7639
- const defaultMethod = typeof toolModule.mcp?.defaultMethod === "string" ? toolModule.mcp.defaultMethod : void 0;
7640
- const adapter = createMcpAdapter({
7641
- name: toolName,
7642
- httpHandlers: httpHandlerMap,
7643
- ...defaultMethod ? { defaultMethod } : {},
7644
- ...schema ? { schema } : {}
7645
- });
7646
- let metadataOverrides = toolModule.metadata ?? null;
7647
- if (paymentExport) {
7648
- if (metadataOverrides) {
7649
- metadataOverrides = {
7650
- ...metadataOverrides,
7651
- payment: metadataOverrides.payment ?? paymentExport,
7652
- annotations: {
7653
- ...metadataOverrides.annotations,
7654
- requiresPayment: metadataOverrides.annotations?.requiresPayment ?? true
7655
- }
7656
- };
7657
- } else {
7658
- metadataOverrides = {
7659
- payment: paymentExport,
7660
- annotations: { requiresPayment: true }
7661
- };
7662
- }
7663
- }
7664
- const tool = {
7665
- schema: schema ?? void 0,
7666
- inputSchema,
7667
- metadata: metadataOverrides,
7668
- httpHandlers,
7669
- mcpConfig: normalizeMcpConfig(toolModule.mcp, file),
7670
- filename: toBaseName(file),
7671
- sourcePath: path5.join(toolsDir, file),
7672
- handler: async (params) => adapter(params),
7673
- payment: paymentExport ?? null,
7674
- schedule: normalizedSchedule,
7675
- profile: normalizedProfile,
7676
- ...profileNotifyEmail !== void 0 ? { notifyEmail: profileNotifyEmail } : {},
7677
- profileDescription: typeof profileRaw?.description === "string" ? profileRaw.description : null,
7678
- ...profileCategoryRaw ? { profileCategory: profileCategoryRaw } : {}
7679
- };
7680
- tools.push(tool);
7681
- }
7682
- } finally {
7683
- cleanup();
7684
- if (fs4.existsSync(tempDir)) {
7685
- fs4.rmSync(tempDir, { recursive: true, force: true });
7686
- }
7687
- }
7688
- return tools;
7689
- }
7690
- function ensureLocalRuntimeLinks(tempDir) {
7691
- const nodeModulesDir = path5.join(tempDir, "node_modules");
7692
- fs4.mkdirSync(nodeModulesDir, { recursive: true });
7693
- const packageLinks = [
7694
- { name: "opentool", target: OPENTOOL_ROOT },
7695
- { name: "zod", target: path5.join(OPENTOOL_NODE_MODULES, "zod") }
7696
- ];
7697
- for (const { name, target } of packageLinks) {
7698
- if (!fs4.existsSync(target)) {
7699
- continue;
7700
- }
7701
- const linkPath = path5.join(nodeModulesDir, name);
7702
- if (fs4.existsSync(linkPath)) {
7703
- continue;
7704
- }
7705
- fs4.symlinkSync(target, linkPath, "junction");
7706
- }
7707
- }
7708
- function extractToolModule(exportsObject, filename) {
7709
- const candidates = [exportsObject, exportsObject?.default];
7710
- for (const candidate of candidates) {
7711
- if (candidate && typeof candidate === "object") {
7712
- const hasSchema = candidate.schema && typeof candidate.schema === "object";
7713
- const hasHttp = HTTP_METHODS2.some((method) => typeof candidate[method] === "function");
7714
- if (hasSchema || hasHttp) {
7715
- return candidate;
7716
- }
7717
- }
7718
- }
7719
- throw new Error(
7720
- `${filename} must export a tool definition. Expected a Zod schema plus HTTP handlers (export async function POST).`
7721
- );
7722
- }
7723
- function toJsonSchema(name, schema) {
7724
- if (!schema) {
7725
- return void 0;
7726
- }
7727
- try {
7728
- return zodToJsonSchema(schema, {
7729
- name: `${name}Schema`,
7730
- target: "jsonSchema7",
7731
- $refStrategy: "none"
7732
- });
7733
- } catch (error) {
7734
- throw new Error(`Failed to convert Zod schema for ${name}: ${error}`);
7735
- }
7736
- }
7737
- function toBaseName(file) {
7738
- return file.replace(/\.[^.]+$/, "");
7739
- }
7740
- function ensureZodSchema(schemaCandidate, filename) {
7741
- if (schemaCandidate == null) {
7742
- return void 0;
7743
- }
7744
- if (schemaCandidate instanceof z.ZodType) {
7745
- return schemaCandidate;
7746
- }
7747
- const schema = schemaCandidate;
7748
- if (typeof schema?.parse !== "function") {
7749
- throw new Error(`${filename} schema export must be a Zod schema (missing parse method)`);
7750
- }
7751
- return schema;
7752
- }
7753
- function collectHttpHandlers2(module, filename) {
7754
- const handlers = [];
7755
- for (const method of HTTP_METHODS2) {
7756
- const handler = module?.[method];
7757
- if (typeof handler === "function") {
7758
- handlers.push({
7759
- method,
7760
- handler: async (request) => handler.call(module, request)
7761
- });
7762
- }
7763
- }
7764
- handlers.sort((a, b) => HTTP_METHODS2.indexOf(a.method) - HTTP_METHODS2.indexOf(b.method));
7765
- const duplicates = findDuplicates(handlers.map((h) => h.method));
7766
- if (duplicates.length > 0) {
7767
- throw new Error(
7768
- `${filename} exports multiple handlers for HTTP method(s): ${duplicates.join(", ")}`
7769
- );
7770
- }
7771
- return handlers;
7772
- }
7773
- function toHttpHandlerMap2(handlers) {
7774
- return handlers.reduce((acc, handler) => {
7775
- acc[handler.method.toUpperCase()] = handler.handler;
7776
- return acc;
7777
- }, {});
7778
- }
7779
- function normalizeInputSchema2(schema) {
7780
- if (!schema || typeof schema !== "object") {
7781
- return schema;
7782
- }
7783
- const clone = JSON.parse(JSON.stringify(schema));
7784
- if (typeof clone.$ref === "string" && clone.$ref.startsWith("#/definitions/")) {
7785
- const refName = clone.$ref.replace("#/definitions/", "");
7786
- const definitions = clone.definitions;
7787
- if (definitions && typeof definitions[refName] === "object") {
7788
- return normalizeInputSchema2(definitions[refName]);
7789
- }
7790
- }
7791
- delete clone.$ref;
7792
- delete clone.definitions;
7793
- if (!("type" in clone)) {
7794
- clone.type = "object";
7795
- }
7796
- return clone;
7797
- }
7798
- function normalizeMcpConfig(rawConfig, filename) {
7799
- if (rawConfig == null) {
7800
- return null;
7801
- }
7802
- if (rawConfig === false) {
7803
- return null;
7804
- }
7805
- if (rawConfig === true) {
7806
- return { enabled: true };
7807
- }
7808
- if (!isPlainObject2(rawConfig)) {
7809
- throw new Error(`${filename} export \\"mcp\\" must be an object with an enabled flag`);
7810
- }
7811
- const enabledRaw = rawConfig.enabled;
7812
- if (enabledRaw === false) {
7813
- return null;
7814
- }
7815
- if (enabledRaw !== true) {
7816
- throw new Error(`${filename} mcp.enabled must be explicitly set to true to opt-in to MCP`);
7817
- }
7818
- const modeRaw = rawConfig.mode;
7819
- let mode;
7820
- if (typeof modeRaw === "string") {
7821
- const normalized = modeRaw.toLowerCase();
7822
- if (["stdio", "lambda", "dual"].includes(normalized)) {
7823
- mode = normalized;
7824
- } else {
7825
- throw new Error(
7826
- `${filename} mcp.mode must be one of "stdio", "lambda", or "dual" if specified`
7827
- );
7828
- }
7829
- }
7830
- const defaultMethodRaw = rawConfig.defaultMethod;
7831
- const defaultMethod = typeof defaultMethodRaw === "string" ? defaultMethodRaw.toUpperCase() : void 0;
7832
- const overridesRaw = rawConfig.metadataOverrides;
7833
- const metadataOverrides = isPlainObject2(overridesRaw) ? overridesRaw : void 0;
7834
- const config = {
7835
- enabled: true
7836
- };
7837
- if (mode) {
7838
- config.mode = mode;
7839
- }
7840
- if (defaultMethod) {
7841
- config.defaultMethod = defaultMethod;
7842
- }
7843
- if (metadataOverrides) {
7844
- config.metadataOverrides = metadataOverrides;
7845
- }
7846
- return config;
7847
- }
7848
- function isPlainObject2(value) {
7849
- return typeof value === "object" && value !== null && !Array.isArray(value);
7850
- }
7851
- function findDuplicates(values) {
7852
- const seen = /* @__PURE__ */ new Map();
7853
- const duplicates = /* @__PURE__ */ new Set();
7854
- values.forEach((value) => {
7855
- const count = seen.get(value) ?? 0;
7856
- seen.set(value, count + 1);
7857
- if (count >= 1) {
7858
- duplicates.add(value);
7859
- }
7860
- });
7861
- return Array.from(duplicates.values());
7862
- }
7863
- function logMetadataSummary(metadata, defaultsApplied, sourceMetadataPath) {
7864
- console.log(`\u{1F4C4} metadata loaded from ${sourceMetadataPath}`);
7865
- console.log("\n\u{1F4CA} Metadata Summary:");
7866
- console.log(` \u2022 Name: ${metadata.name}`);
7867
- console.log(` \u2022 Display Name: ${metadata.displayName}`);
7868
- console.log(` \u2022 Version: ${metadata.version}`);
7869
- console.log(` \u2022 Category: ${metadata.category}`);
7870
- console.log(` \u2022 Tools: ${metadata.tools.length}`);
7871
- console.log(` \u2022 Spec Version: ${metadata.metadataSpecVersion}`);
7872
- if (metadata.payment) {
7873
- console.log(` \u2022 Payment: $${metadata.payment.amountUSDC} USDC`);
7874
- }
7875
- if (defaultsApplied.length > 0) {
7876
- console.log("\nDefaults applied during metadata synthesis:");
7877
- defaultsApplied.forEach((entry) => console.log(` \u2022 ${entry}`));
7878
- }
7879
- }
7880
-
7881
- // src/cli/generate-metadata.ts
7882
- async function generateMetadataCommand(options) {
7883
- const startTimestamp = timestamp();
7884
- console.log(`[${startTimestamp}] Generating OpenTool metadata...`);
7885
- try {
7886
- const result = await generateMetadata(options);
7887
- const endTimestamp = timestamp();
7888
- console.log(`[${endTimestamp}] Metadata generation completed successfully!`);
7889
- console.log(`Output file: ${result.outputPath}`);
7890
- console.log(`Spec version: ${result.metadata.metadataSpecVersion}`);
7891
- console.log(`Tools included: ${result.tools.length}`);
7892
- if (result.defaultsApplied.length > 0) {
7893
- console.log("Applied defaults:");
7894
- for (const entry of result.defaultsApplied) {
7895
- console.log(` \u2022 ${entry}`);
7896
- }
7897
- }
7898
- } catch (error) {
7899
- const endTimestamp = timestamp();
7900
- console.error(`[${endTimestamp}] Metadata generation failed:`, error);
7901
- process.exit(1);
7902
- }
7903
- }
7904
- async function generateMetadata(options) {
7905
- const toolsDir = path5.resolve(options.input);
7906
- if (!fs4.existsSync(toolsDir)) {
7907
- throw new Error(`Tools directory not found: ${toolsDir}`);
7908
- }
7909
- const projectRoot = path5.dirname(toolsDir);
7910
- const tools = await loadAndValidateTools(toolsDir, { projectRoot });
7911
- const { metadata, defaultsApplied } = await buildMetadataArtifact({
7912
- projectRoot,
7913
- tools
7914
- });
7915
- const outputPath = options.output ? path5.resolve(options.output) : path5.join(projectRoot, "metadata.json");
7916
- fs4.writeFileSync(outputPath, JSON.stringify(metadata, null, 2));
7917
- return {
7918
- metadata,
7919
- defaultsApplied,
7920
- tools,
7921
- outputPath
7922
- };
7923
- }
7924
- function timestamp() {
7925
- return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
7926
- }
7927
6846
 
7928
- export { AIAbortError, AIError, AIFetchError, AIResponseError, BACKTEST_DECISION_MODE, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_CADENCE_CRON, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_OPENPOND_GATEWAY_URL2 as DEFAULT_OPENPOND_GATEWAY_URL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, NewsSignalClient, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, __hyperliquidMarketDataInternals, approveHyperliquidBuilderFee, backtestDecisionRequestSchema, batchModifyHyperliquidOrders, buildBacktestDecisionSeriesInput, buildHmacSignature, buildHyperliquidMarketIdentity, buildHyperliquidProfileAssets, buildHyperliquidSpotUsdPriceMap, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, clampHyperliquidAbs, clampHyperliquidFloat, clampHyperliquidInt, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, estimateCountBack, evaluateNewsContinuationGate, executeTool, extractHyperliquidDex, extractHyperliquidOrderIds, fetchHyperliquidAllMids, fetchHyperliquidAssetCtxs, fetchHyperliquidBars, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPerpMarketInfo, fetchHyperliquidPreTransferCheck, fetchHyperliquidSizeDecimals, fetchHyperliquidSpotAccountValue, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMarketInfo, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidSpotTickSize, fetchHyperliquidSpotUsdPriceMap, fetchHyperliquidTickSize, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchNewsEventSignal, fetchNewsPropositionSignal, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, formatHyperliquidPrice, formatHyperliquidSize, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isHyperliquidSpotSymbol, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeHyperliquidBaseSymbol, normalizeHyperliquidDcaEntries, normalizeHyperliquidIndicatorBars, normalizeHyperliquidMetaSymbol, normalizeModelName, normalizeNumberArrayish, normalizeSpotTokenName2 as normalizeSpotTokenName, normalizeStringArrayish, parseHyperliquidJson, parseSpotPairSymbol, parseTimeToSeconds, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, planHyperliquidTrade, postAgentDigest, readHyperliquidAccountValue, readHyperliquidNumber, readHyperliquidPerpPosition, readHyperliquidPerpPositionSize, readHyperliquidSpotAccountValue, readHyperliquidSpotBalance, readHyperliquidSpotBalanceSize, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolutionToSeconds, resolveBacktestAccountValueUsd, resolveBacktestMode, resolveBacktestWindow, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolveHyperliquidBudgetUsd, resolveHyperliquidCadenceCron, resolveHyperliquidCadenceFromResolution, resolveHyperliquidChain, resolveHyperliquidChainConfig, resolveHyperliquidDcaSymbolEntries, resolveHyperliquidErrorDetail, resolveHyperliquidHourlyInterval, resolveHyperliquidIntervalCron, resolveHyperliquidLeverageMode, resolveHyperliquidMaxPerRunUsd, resolveHyperliquidOrderRef, resolveHyperliquidOrderSymbol, resolveHyperliquidPair, resolveHyperliquidPerpSymbol, resolveHyperliquidProfileChain, resolveHyperliquidRpcEnvVar, resolveHyperliquidScheduleEvery, resolveHyperliquidScheduleUnit, resolveHyperliquidSpotSymbol, resolveHyperliquidStoreNetwork, resolveHyperliquidSymbol, resolveHyperliquidTargetSize, resolveNewsGatewayBase, resolvePolymarketBaseUrl, resolveRuntimePath, resolveSpotMidCandidates, resolveSpotTokenCandidates, resolveToolset, responseToToolResponse, retrieve, roundHyperliquidPriceToTick, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
6847
+ export { AIAbortError, AIError, AIFetchError, AIResponseError, BACKTEST_DECISION_MODE, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_CADENCE_CRON, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_OPENPOND_GATEWAY_URL2 as DEFAULT_OPENPOND_GATEWAY_URL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, NewsSignalClient, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, __hyperliquidMarketDataInternals, approveHyperliquidBuilderFee, backtestDecisionRequestSchema, batchModifyHyperliquidOrders, buildBacktestDecisionSeriesInput, buildHmacSignature, buildHyperliquidMarketIdentity, buildHyperliquidProfileAssets, buildHyperliquidSpotUsdPriceMap, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, clampHyperliquidAbs, clampHyperliquidFloat, clampHyperliquidInt, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, estimateCountBack, evaluateNewsContinuationGate, executeTool, extractHyperliquidDex, extractHyperliquidOrderIds, fetchHyperliquidAllMids, fetchHyperliquidAssetCtxs, fetchHyperliquidBars, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPerpMarketInfo, fetchHyperliquidPreTransferCheck, fetchHyperliquidSizeDecimals, fetchHyperliquidSpotAccountValue, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMarketInfo, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidSpotTickSize, fetchHyperliquidSpotUsdPriceMap, fetchHyperliquidTickSize, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchNewsEventSignal, fetchNewsPropositionSignal, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, formatHyperliquidPrice, formatHyperliquidSize, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isHyperliquidSpotSymbol, isStreamingSupported, isToolCallingSupported, listModels, modifyHyperliquidOrder, normalizeHyperliquidBaseSymbol, normalizeHyperliquidDcaEntries, normalizeHyperliquidIndicatorBars, normalizeHyperliquidMetaSymbol, normalizeModelName, normalizeNumberArrayish, normalizeSpotTokenName2 as normalizeSpotTokenName, normalizeStringArrayish, parseHyperliquidJson, parseSpotPairSymbol, parseTimeToSeconds, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, planHyperliquidTrade, postAgentDigest, readHyperliquidAccountValue, readHyperliquidNumber, readHyperliquidPerpPosition, readHyperliquidPerpPositionSize, readHyperliquidSpotAccountValue, readHyperliquidSpotBalance, readHyperliquidSpotBalanceSize, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolutionToSeconds, resolveBacktestAccountValueUsd, resolveBacktestMode, resolveBacktestWindow, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolveHyperliquidBudgetUsd, resolveHyperliquidCadenceCron, resolveHyperliquidCadenceFromResolution, resolveHyperliquidChain, resolveHyperliquidChainConfig, resolveHyperliquidDcaSymbolEntries, resolveHyperliquidErrorDetail, resolveHyperliquidHourlyInterval, resolveHyperliquidIntervalCron, resolveHyperliquidLeverageMode, resolveHyperliquidMaxPerRunUsd, resolveHyperliquidOrderRef, resolveHyperliquidOrderSymbol, resolveHyperliquidPair, resolveHyperliquidPerpSymbol, resolveHyperliquidProfileChain, resolveHyperliquidRpcEnvVar, resolveHyperliquidScheduleEvery, resolveHyperliquidScheduleUnit, resolveHyperliquidSpotSymbol, resolveHyperliquidStoreNetwork, resolveHyperliquidSymbol, resolveHyperliquidTargetSize, resolveNewsGatewayBase, resolvePolymarketBaseUrl, resolveRuntimePath, resolveSpotMidCandidates, resolveSpotTokenCandidates, resolveToolset, responseToToolResponse, retrieve, roundHyperliquidPriceToTick, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
7929
6848
  //# sourceMappingURL=index.js.map
7930
6849
  //# sourceMappingURL=index.js.map