hive-intelligence 1.16.1 → 1.17.1

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.
@@ -14579,7 +14579,7 @@ var handlers = {
14579
14579
  getApprovalSecurity: createHandler("getApprovalSecurity", {
14580
14580
  suggestion: "Verify the chain ID and spender contract address. Use this before approving tokens to a contract.",
14581
14581
  alternatives: [
14582
- "get_user_approvals - List existing approvals",
14582
+ "get_wallet_approvals - List existing approvals",
14583
14583
  "get_token_security - Analyze token contract"
14584
14584
  ],
14585
14585
  example: {
@@ -14601,7 +14601,7 @@ var handlers = {
14601
14601
  getDappSecurity: createHandler("getDappSecurity", {
14602
14602
  suggestion: "Provide a complete URL including https://. For comprehensive dApp analysis use this tool.",
14603
14603
  alternatives: [
14604
- "detect_phishing_site - Quick phishing check",
14604
+ "check_phishing_site - Quick phishing check",
14605
14605
  "check_malicious_address - Check associated addresses"
14606
14606
  ],
14607
14607
  example: { url: "https://app.uniswap.org" }
@@ -14630,7 +14630,7 @@ var handlers = {
14630
14630
  suggestion: "Provide chain_id, from, to, and data fields. Use hex-encoded calldata starting with 0x.",
14631
14631
  alternatives: [
14632
14632
  "get_solana_token_security - For Solana token analysis",
14633
- "decode_abi_data - To decode transaction data"
14633
+ "decode_abi - To decode transaction data"
14634
14634
  ],
14635
14635
  example: {
14636
14636
  chain_id: "1",
@@ -18594,10 +18594,10 @@ var wrapper = {
18594
18594
  // src/utils/fetchClient.ts
18595
18595
  var HttpError = class extends Error {
18596
18596
  config;
18597
- constructor(message, config2, code, response) {
18597
+ constructor(message, config, code, response) {
18598
18598
  super(message);
18599
18599
  this.name = "HttpError";
18600
- this.config = config2;
18600
+ this.config = config;
18601
18601
  if (code) this.code = code;
18602
18602
  if (response) this.response = response;
18603
18603
  }
@@ -18634,16 +18634,16 @@ var UNDICI_CODES = {
18634
18634
  UND_ERR_BODY_TIMEOUT: "ETIMEDOUT",
18635
18635
  UND_ERR_SOCKET: "ECONNRESET"
18636
18636
  };
18637
- function networkError(error, timedOut, timeout, config2) {
18637
+ function networkError(error, timedOut, timeout, config) {
18638
18638
  if (timedOut) {
18639
- return new HttpError(`timeout of ${timeout}ms exceeded`, config2, "ECONNABORTED");
18639
+ return new HttpError(`timeout of ${timeout}ms exceeded`, config, "ECONNABORTED");
18640
18640
  }
18641
18641
  const cause = error?.cause;
18642
18642
  const rawCode = cause?.code;
18643
18643
  const code = (rawCode && UNDICI_CODES[rawCode]) ?? rawCode ?? "ERR_NETWORK";
18644
- return new HttpError(cause?.message || rawCode || "Network Error", config2, code);
18644
+ return new HttpError(cause?.message || rawCode || "Network Error", config, code);
18645
18645
  }
18646
- async function readBody(response, maxContentLength, config2, onChunk) {
18646
+ async function readBody(response, maxContentLength, config, onChunk) {
18647
18647
  if (!response.body) return "";
18648
18648
  const reader = response.body.getReader();
18649
18649
  const chunks = [];
@@ -18657,7 +18657,7 @@ async function readBody(response, maxContentLength, config2, onChunk) {
18657
18657
  await reader.cancel();
18658
18658
  throw new HttpError(
18659
18659
  `maxContentLength size of ${maxContentLength} exceeded`,
18660
- config2,
18660
+ config,
18661
18661
  "ERR_BAD_RESPONSE"
18662
18662
  );
18663
18663
  }
@@ -18674,9 +18674,9 @@ function parseBody(text) {
18674
18674
  }
18675
18675
  }
18676
18676
  function createFetchClient(options = {}) {
18677
- async function request(method, url, data, config2 = {}) {
18677
+ async function request(method, url, data, config = {}) {
18678
18678
  const info = { method, url };
18679
- const timeout = config2.timeout ?? options.timeout ?? 0;
18679
+ const timeout = config.timeout ?? options.timeout ?? 0;
18680
18680
  const controller = new AbortController();
18681
18681
  let timedOut = false;
18682
18682
  let timer;
@@ -18694,7 +18694,7 @@ function createFetchClient(options = {}) {
18694
18694
  const headers = {
18695
18695
  Accept: "application/json, text/plain, */*",
18696
18696
  ...options.headers,
18697
- ...config2.headers
18697
+ ...config.headers
18698
18698
  };
18699
18699
  let body;
18700
18700
  if (data !== void 0) {
@@ -18707,7 +18707,7 @@ function createFetchClient(options = {}) {
18707
18707
  let text;
18708
18708
  let res;
18709
18709
  try {
18710
- res = await fetch(buildUrl(options.baseURL, url, config2.params), {
18710
+ res = await fetch(buildUrl(options.baseURL, url, config.params), {
18711
18711
  method: method.toUpperCase(),
18712
18712
  headers,
18713
18713
  body,
@@ -18741,10 +18741,10 @@ function createFetchClient(options = {}) {
18741
18741
  }
18742
18742
  }
18743
18743
  return {
18744
- get: (url, config2) => request("get", url, void 0, config2),
18745
- post: (url, data, config2) => request("post", url, data, config2),
18746
- put: (url, data, config2) => request("put", url, data, config2),
18747
- delete: (url, config2) => request("delete", url, void 0, config2)
18744
+ get: (url, config) => request("get", url, void 0, config),
18745
+ post: (url, data, config) => request("post", url, data, config),
18746
+ put: (url, data, config) => request("put", url, data, config),
18747
+ delete: (url, config) => request("delete", url, void 0, config)
18748
18748
  };
18749
18749
  }
18750
18750
 
@@ -31592,8 +31592,7 @@ function isRetryableError(error) {
31592
31592
  "ECONNRESET",
31593
31593
  "ETIMEDOUT",
31594
31594
  "ECONNREFUSED",
31595
- "ENOTFOUND",
31596
- "ECONNABORTED"
31595
+ "ENOTFOUND"
31597
31596
  ];
31598
31597
  return retryableCodes.includes(error.code || "");
31599
31598
  }
@@ -31612,23 +31611,23 @@ var ResilientHttpClient = class {
31612
31611
  http;
31613
31612
  config;
31614
31613
  circuitBreaker;
31615
- constructor(config2) {
31614
+ constructor(config) {
31616
31615
  this.config = {
31617
- baseURL: config2.baseURL,
31618
- timeout: config2.timeout ?? 3e4,
31616
+ baseURL: config.baseURL,
31617
+ timeout: config.timeout ?? 3e4,
31619
31618
  // 30 seconds default
31620
- headers: config2.headers,
31621
- serviceName: config2.serviceName,
31622
- maxRetries: config2.maxRetries ?? 3,
31623
- retryBaseDelay: config2.retryBaseDelay ?? 1e3,
31624
- enableCircuitBreaker: config2.enableCircuitBreaker ?? true,
31625
- circuitBreakerThreshold: config2.circuitBreakerThreshold ?? 5,
31626
- circuitBreakerResetTimeout: config2.circuitBreakerResetTimeout ?? 3e4
31619
+ headers: config.headers,
31620
+ serviceName: config.serviceName,
31621
+ maxRetries: config.maxRetries ?? 3,
31622
+ retryBaseDelay: config.retryBaseDelay ?? 1e3,
31623
+ enableCircuitBreaker: config.enableCircuitBreaker ?? true,
31624
+ circuitBreakerThreshold: config.circuitBreakerThreshold ?? 5,
31625
+ circuitBreakerResetTimeout: config.circuitBreakerResetTimeout ?? 3e4
31627
31626
  };
31628
31627
  this.http = createFetchClient({
31629
31628
  baseURL: this.config.baseURL,
31630
31629
  timeout: this.config.timeout,
31631
- maxContentLength: config2.maxContentLength,
31630
+ maxContentLength: config.maxContentLength,
31632
31631
  headers: {
31633
31632
  "Content-Type": "application/json",
31634
31633
  Accept: "application/json",
@@ -31647,12 +31646,12 @@ var ResilientHttpClient = class {
31647
31646
  url: endpoint,
31648
31647
  params: options.params
31649
31648
  });
31650
- const config2 = {
31649
+ const config = {
31651
31650
  params: options.params,
31652
31651
  timeout: options.timeout ?? this.config.timeout,
31653
31652
  headers: options.headers
31654
31653
  };
31655
- const response = method === "get" || method === "delete" ? await this.http[method](endpoint, config2) : await this.http[method](endpoint, options.body, config2);
31654
+ const response = method === "get" || method === "delete" ? await this.http[method](endpoint, config) : await this.http[method](endpoint, options.body, config);
31656
31655
  secureLogger.debug(`[${this.config.serviceName}] Response`, {
31657
31656
  status: response.status,
31658
31657
  url: endpoint
@@ -31844,8 +31843,8 @@ var ResilientHttpClient = class {
31844
31843
  );
31845
31844
  }
31846
31845
  };
31847
- function createHttpClient(config2) {
31848
- return new ResilientHttpClient(config2);
31846
+ function createHttpClient(config) {
31847
+ return new ResilientHttpClient(config);
31849
31848
  }
31850
31849
 
31851
31850
  // src/tools/tenderly/tenderlyClient.ts
@@ -35981,15 +35980,15 @@ var getTransactionHandler = makeHandler(
35981
35980
  },
35982
35981
  (client2, args) => {
35983
35982
  const signature = String(args.signature ?? "");
35984
- const config2 = {};
35983
+ const config = {};
35985
35984
  for (const key of [
35986
35985
  "encoding",
35987
35986
  "commitment",
35988
35987
  "maxSupportedTransactionVersion"
35989
35988
  ]) {
35990
- if (args[key] !== void 0) config2[key] = args[key];
35989
+ if (args[key] !== void 0) config[key] = args[key];
35991
35990
  }
35992
- return client2.request("getTransaction", [signature, config2]);
35991
+ return client2.request("getTransaction", [signature, config]);
35993
35992
  }
35994
35993
  );
35995
35994
  var getTransactionsForAddressHandler = makeHandler(
@@ -36004,7 +36003,7 @@ var getTransactionsForAddressHandler = makeHandler(
36004
36003
  1,
36005
36004
  Math.min(transactionDetails === "full" ? 100 : 1e3, requestedLimit)
36006
36005
  );
36007
- const config2 = { transactionDetails, limit };
36006
+ const config = { transactionDetails, limit };
36008
36007
  for (const key of [
36009
36008
  "sortOrder",
36010
36009
  "commitment",
@@ -36014,11 +36013,11 @@ var getTransactionsForAddressHandler = makeHandler(
36014
36013
  "maxSupportedTransactionVersion",
36015
36014
  "filters"
36016
36015
  ]) {
36017
- if (args[key] !== void 0) config2[key] = args[key];
36016
+ if (args[key] !== void 0) config[key] = args[key];
36018
36017
  }
36019
36018
  return client2.request("getTransactionsForAddress", [
36020
36019
  String(args.address ?? ""),
36021
- config2
36020
+ config
36022
36021
  ]);
36023
36022
  }
36024
36023
  );
@@ -36029,7 +36028,7 @@ var getTransfersByAddressHandler = makeHandler(
36029
36028
  { address: EX_OWNER, limit: 50 },
36030
36029
  (client2, args) => {
36031
36030
  const requestedLimit = Number(args.limit ?? 100);
36032
- const config2 = {
36031
+ const config = {
36033
36032
  limit: Math.max(1, Math.min(100, requestedLimit))
36034
36033
  };
36035
36034
  for (const key of [
@@ -36043,11 +36042,11 @@ var getTransfersByAddressHandler = makeHandler(
36043
36042
  "minContextSlot",
36044
36043
  "sortOrder"
36045
36044
  ]) {
36046
- if (args[key] !== void 0) config2[key] = args[key];
36045
+ if (args[key] !== void 0) config[key] = args[key];
36047
36046
  }
36048
36047
  return client2.request("getTransfersByAddress", [
36049
36048
  String(args.address ?? ""),
36050
- config2
36049
+ config
36051
36050
  ]);
36052
36051
  }
36053
36052
  );
@@ -36332,7 +36331,7 @@ var getTokenAccountsByOwnerV2Handler = makeHandler(
36332
36331
  (client2, args) => {
36333
36332
  const owner = String(args.owner ?? "");
36334
36333
  const filter = args.mint !== void 0 ? { mint: String(args.mint) } : { programId: String(args.programId ?? TOKEN_PROGRAM_ID) };
36335
- const config2 = {
36334
+ const config = {
36336
36335
  encoding: args.encoding ?? "jsonParsed",
36337
36336
  limit: args.limit ?? 1e3
36338
36337
  };
@@ -36344,9 +36343,9 @@ var getTokenAccountsByOwnerV2Handler = makeHandler(
36344
36343
  "withContext",
36345
36344
  "commitment"
36346
36345
  ]) {
36347
- if (args[key] !== void 0) config2[key] = args[key];
36346
+ if (args[key] !== void 0) config[key] = args[key];
36348
36347
  }
36349
- return client2.request("getTokenAccountsByOwnerV2", [owner, filter, config2]);
36348
+ return client2.request("getTokenAccountsByOwnerV2", [owner, filter, config]);
36350
36349
  }
36351
36350
  );
36352
36351
  var getProgramAccountsV2Handler = makeHandler(
@@ -36355,7 +36354,7 @@ var getProgramAccountsV2Handler = makeHandler(
36355
36354
  ["helius_get_token_accounts_by_owner_v2"],
36356
36355
  { programId: TOKEN_PROGRAM_ID, encoding: "base64", limit: 10 },
36357
36356
  (client2, args) => {
36358
- const config2 = {
36357
+ const config = {
36359
36358
  encoding: args.encoding ?? "base64",
36360
36359
  limit: args.limit ?? 100
36361
36360
  };
@@ -36368,11 +36367,11 @@ var getProgramAccountsV2Handler = makeHandler(
36368
36367
  "withContext",
36369
36368
  "commitment"
36370
36369
  ]) {
36371
- if (args[key] !== void 0) config2[key] = args[key];
36370
+ if (args[key] !== void 0) config[key] = args[key];
36372
36371
  }
36373
36372
  return client2.request("getProgramAccountsV2", [
36374
36373
  String(args.programId ?? ""),
36375
- config2
36374
+ config
36376
36375
  ]);
36377
36376
  }
36378
36377
  );
@@ -36522,8 +36521,8 @@ var AlchemyClient = class {
36522
36521
  secureLogger.info("Alchemy client initialized");
36523
36522
  }
36524
36523
  getHttpClient(baseURL, serviceName) {
36525
- const cacheKey2 = `${serviceName}:${baseURL}`;
36526
- const existing = this.clients.get(cacheKey2);
36524
+ const cacheKey = `${serviceName}:${baseURL}`;
36525
+ const existing = this.clients.get(cacheKey);
36527
36526
  if (existing) return existing;
36528
36527
  const client2 = createHttpClient({
36529
36528
  baseURL,
@@ -36539,7 +36538,7 @@ var AlchemyClient = class {
36539
36538
  circuitBreakerThreshold: 5,
36540
36539
  circuitBreakerResetTimeout: 3e4
36541
36540
  });
36542
- this.clients.set(cacheKey2, client2);
36541
+ this.clients.set(cacheKey, client2);
36543
36542
  return client2;
36544
36543
  }
36545
36544
  apiPath(path) {
@@ -47582,7 +47581,7 @@ async function fetchWithTimeout(url, options, timeout) {
47582
47581
  }
47583
47582
  async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
47584
47583
  const startTime = Date.now();
47585
- const config2 = {
47584
+ const config = {
47586
47585
  timeout: resilientOptions.timeout ?? 3e4,
47587
47586
  maxRetries: resilientOptions.maxRetries ?? 3,
47588
47587
  retryBaseDelay: resilientOptions.retryBaseDelay ?? 1e3,
@@ -47591,21 +47590,21 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
47591
47590
  circuitBreakerThreshold: resilientOptions.circuitBreakerThreshold ?? 5,
47592
47591
  circuitBreakerResetTimeout: resilientOptions.circuitBreakerResetTimeout ?? 3e4
47593
47592
  };
47594
- const circuitBreaker = getCircuitBreaker2(config2.serviceName);
47595
- if (config2.enableCircuitBreaker) {
47596
- checkCircuitBreaker(circuitBreaker, config2);
47593
+ const circuitBreaker = getCircuitBreaker2(config.serviceName);
47594
+ if (config.enableCircuitBreaker) {
47595
+ checkCircuitBreaker(circuitBreaker, config);
47597
47596
  }
47598
47597
  let lastError = null;
47599
- for (let attempt = 0; attempt <= config2.maxRetries; attempt++) {
47598
+ for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
47600
47599
  try {
47601
- const response = await fetchWithTimeout(url, fetchOptions, config2.timeout);
47600
+ const response = await fetchWithTimeout(url, fetchOptions, config.timeout);
47602
47601
  if (!response.ok && isRetryableStatus(response.status)) {
47603
47602
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
47604
47603
  }
47605
- if (config2.enableCircuitBreaker) {
47604
+ if (config.enableCircuitBreaker) {
47606
47605
  recordSuccess(circuitBreaker);
47607
47606
  }
47608
- secureLogger.debug(`[${config2.serviceName}] Request succeeded`, {
47607
+ secureLogger.debug(`[${config.serviceName}] Request succeeded`, {
47609
47608
  url: sanitizeUrl(url),
47610
47609
  status: response.status,
47611
47610
  duration: Date.now() - startTime
@@ -47613,15 +47612,15 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
47613
47612
  return response;
47614
47613
  } catch (error) {
47615
47614
  lastError = error instanceof Error ? error : new Error(String(error));
47616
- if (config2.enableCircuitBreaker) {
47617
- recordFailure(circuitBreaker, config2);
47615
+ if (config.enableCircuitBreaker) {
47616
+ recordFailure(circuitBreaker, config);
47618
47617
  }
47619
- if (attempt < config2.maxRetries) {
47620
- const delay2 = calculateBackoffDelay2(attempt, config2.retryBaseDelay);
47621
- secureLogger.warn(`[${config2.serviceName}] Request failed, retrying`, {
47618
+ if (attempt < config.maxRetries) {
47619
+ const delay2 = calculateBackoffDelay2(attempt, config.retryBaseDelay);
47620
+ secureLogger.warn(`[${config.serviceName}] Request failed, retrying`, {
47622
47621
  url: sanitizeUrl(url),
47623
47622
  attempt: attempt + 1,
47624
- maxRetries: config2.maxRetries,
47623
+ maxRetries: config.maxRetries,
47625
47624
  delayMs: Math.round(delay2),
47626
47625
  error: lastError.message
47627
47626
  });
@@ -47630,28 +47629,28 @@ async function resilientFetch(url, fetchOptions = {}, resilientOptions = {}) {
47630
47629
  }
47631
47630
  }
47632
47631
  }
47633
- secureLogger.error(`[${config2.serviceName}] Request failed after all retries`, lastError, {
47632
+ secureLogger.error(`[${config.serviceName}] Request failed after all retries`, lastError, {
47634
47633
  url: sanitizeUrl(url),
47635
- attempts: config2.maxRetries + 1,
47634
+ attempts: config.maxRetries + 1,
47636
47635
  duration: Date.now() - startTime
47637
47636
  });
47638
47637
  throw lastError;
47639
47638
  }
47640
- function checkCircuitBreaker(breaker, config2) {
47639
+ function checkCircuitBreaker(breaker, config) {
47641
47640
  const now = Date.now();
47642
47641
  switch (breaker.state) {
47643
47642
  case "OPEN" /* OPEN */:
47644
- if (now - breaker.lastFailureTime > config2.circuitBreakerResetTimeout) {
47643
+ if (now - breaker.lastFailureTime > config.circuitBreakerResetTimeout) {
47645
47644
  breaker.state = "HALF_OPEN" /* HALF_OPEN */;
47646
- secureLogger.info(`[${config2.serviceName}] Circuit breaker HALF_OPEN, testing recovery`);
47645
+ secureLogger.info(`[${config.serviceName}] Circuit breaker HALF_OPEN, testing recovery`);
47647
47646
  } else {
47648
47647
  throw new Error(
47649
- `Circuit breaker OPEN for ${config2.serviceName}. Will retry in ${Math.ceil((config2.circuitBreakerResetTimeout - (now - breaker.lastFailureTime)) / 1e3)}s`
47648
+ `Circuit breaker OPEN for ${config.serviceName}. Will retry in ${Math.ceil((config.circuitBreakerResetTimeout - (now - breaker.lastFailureTime)) / 1e3)}s`
47650
47649
  );
47651
47650
  }
47652
47651
  break;
47653
47652
  case "HALF_OPEN" /* HALF_OPEN */:
47654
- secureLogger.debug(`[${config2.serviceName}] Testing recovery (HALF_OPEN)`);
47653
+ secureLogger.debug(`[${config.serviceName}] Testing recovery (HALF_OPEN)`);
47655
47654
  break;
47656
47655
  case "CLOSED" /* CLOSED */:
47657
47656
  break;
@@ -47664,15 +47663,15 @@ function recordSuccess(breaker) {
47664
47663
  breaker.state = "CLOSED" /* CLOSED */;
47665
47664
  breaker.failures = 0;
47666
47665
  }
47667
- function recordFailure(breaker, config2) {
47666
+ function recordFailure(breaker, config) {
47668
47667
  breaker.failures++;
47669
47668
  breaker.lastFailureTime = Date.now();
47670
47669
  if (breaker.state === "HALF_OPEN" /* HALF_OPEN */) {
47671
47670
  breaker.state = "OPEN" /* OPEN */;
47672
- secureLogger.warn(`[${config2.serviceName}] Recovery failed, circuit OPEN`);
47673
- } else if (breaker.failures >= config2.circuitBreakerThreshold) {
47671
+ secureLogger.warn(`[${config.serviceName}] Recovery failed, circuit OPEN`);
47672
+ } else if (breaker.failures >= config.circuitBreakerThreshold) {
47674
47673
  breaker.state = "OPEN" /* OPEN */;
47675
- secureLogger.warn(`[${config2.serviceName}] Circuit OPEN after ${breaker.failures} failures`);
47674
+ secureLogger.warn(`[${config.serviceName}] Circuit OPEN after ${breaker.failures} failures`);
47676
47675
  }
47677
47676
  }
47678
47677
  function extractServiceName(url) {
@@ -48917,243 +48916,6 @@ async function trackOAuthFirstMaterialReceipt(params) {
48917
48916
  ]);
48918
48917
  }
48919
48918
 
48920
- // src/wrapper/cache.ts
48921
- import crypto from "crypto";
48922
-
48923
- // src/utils/redis.ts
48924
- import Redis from "ioredis";
48925
- var client = null;
48926
- var available = false;
48927
- function logRedisInfo(message) {
48928
- process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO]: ${message}
48929
- `);
48930
- }
48931
- function getRedisClient() {
48932
- return client;
48933
- }
48934
- function isRedisAvailable() {
48935
- return available;
48936
- }
48937
- async function waitForRedisAvailability(timeoutMs = 1e4) {
48938
- if (!client) return false;
48939
- if (available) return true;
48940
- const boundedTimeoutMs = Math.max(1, Math.min(timeoutMs, 3e4));
48941
- const current = client;
48942
- return new Promise((resolve) => {
48943
- let settled = false;
48944
- const finish = (ready) => {
48945
- if (settled) return;
48946
- settled = true;
48947
- clearTimeout(timer);
48948
- current.off("ready", onReady);
48949
- current.off("end", onEnd);
48950
- resolve(ready);
48951
- };
48952
- const onReady = () => finish(true);
48953
- const onEnd = () => finish(false);
48954
- const timer = setTimeout(() => finish(available), boundedTimeoutMs);
48955
- current.once("ready", onReady);
48956
- current.once("end", onEnd);
48957
- if (available) finish(true);
48958
- });
48959
- }
48960
- async function closeRedisClient() {
48961
- if (!client) return;
48962
- const current = client;
48963
- client = null;
48964
- available = false;
48965
- try {
48966
- await Promise.race([
48967
- current.quit(),
48968
- new Promise(
48969
- (_, reject) => setTimeout(() => reject(new Error("Redis quit timed out")), 5e3)
48970
- )
48971
- ]);
48972
- logRedisInfo("[redis] Connection closed gracefully");
48973
- } catch (err) {
48974
- secureLogger.error(
48975
- "[redis] Error closing connection, forcing disconnect",
48976
- err,
48977
- {}
48978
- );
48979
- current.disconnect();
48980
- }
48981
- }
48982
- var DEGRADED_AFTER_ATTEMPTS = 3;
48983
- var MAX_RECONNECT_DELAY_MS = 3e3;
48984
- function redisRetryStrategy(times) {
48985
- if (times === DEGRADED_AFTER_ATTEMPTS) {
48986
- secureLogger.warn(
48987
- `[redis] Connection failed after ${DEGRADED_AFTER_ATTEMPTS} retries, falling back to in-memory while reconnection continues`,
48988
- {}
48989
- );
48990
- available = false;
48991
- }
48992
- return Math.min(times * 100, MAX_RECONNECT_DELAY_MS);
48993
- }
48994
- function redisClientOptions() {
48995
- return {
48996
- maxRetriesPerRequest: 3,
48997
- retryStrategy: redisRetryStrategy,
48998
- lazyConnect: true
48999
- };
49000
- }
49001
- var redisUrl = getEnvVar("REDIS_URL");
49002
- function isRedisConfigured() {
49003
- return Boolean(redisUrl);
49004
- }
49005
- if (redisUrl) {
49006
- try {
49007
- client = new Redis(redisUrl, redisClientOptions());
49008
- client.connect().then(() => {
49009
- available = true;
49010
- logRedisInfo("[redis] Connected successfully");
49011
- }).catch((err) => {
49012
- secureLogger.warn("[redis] Connection failed", {
49013
- error: err.message
49014
- });
49015
- available = false;
49016
- });
49017
- client.on("error", (err) => {
49018
- secureLogger.warn("[redis] Error", { error: err.message });
49019
- available = false;
49020
- });
49021
- client.on("ready", () => {
49022
- available = true;
49023
- });
49024
- const gracefulShutdown = async (signal) => {
49025
- logRedisInfo(`[redis] Received ${signal}, closing connection...`);
49026
- await closeRedisClient();
49027
- };
49028
- process.on("SIGINT", () => gracefulShutdown("SIGINT"));
49029
- process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
49030
- } catch (err) {
49031
- secureLogger.warn("[redis] Failed to initialise", {
49032
- error: String(err)
49033
- });
49034
- client = null;
49035
- }
49036
- } else {
49037
- logRedisInfo("[redis] No REDIS_URL provided, using in-memory fallbacks");
49038
- }
49039
-
49040
- // src/wrapper/cache.ts
49041
- var PREFIX = "mcp-cache:";
49042
- var CACHE_ENVELOPE_VERSION = 1;
49043
- var TTL_MARKET_S = 30;
49044
- var TTL_METADATA_S = 5 * 60;
49045
- var TTL_STATIC_S = 60 * 60;
49046
- var BUCKETS = [
49047
- {
49048
- // Static reference data — list of chains, supported currencies, asset
49049
- // platforms. Changes on the order of weeks/months.
49050
- patterns: [
49051
- /_get_(asset_platforms|networks|supported_currencies|categories_list|coins_list|new_coins_list|exchanges_list|exchange_rates)\b/,
49052
- /\bdefillama_get_chains\b/
49053
- ],
49054
- ttlS: TTL_STATIC_S
49055
- },
49056
- {
49057
- // Live market data — prices, volume, OHLC, market caps. Refreshes on
49058
- // 30s-1m boundaries upstream.
49059
- patterns: [
49060
- /_get_(price|prices|coins_market_data_browser|coins_markets|simple_price|token_price|historical_token_prices|ohlc|funding_rate|open_interest|ticker|tickers)\b/,
49061
- /\bmarket_data\b/,
49062
- /\bvolume\b/,
49063
- /\bderivatives\b/
49064
- ],
49065
- ttlS: TTL_MARKET_S
49066
- },
49067
- {
49068
- // Token / coin metadata — descriptions, contract addresses, holder
49069
- // breakdowns, top-N rankings. Refreshes slowly.
49070
- patterns: [
49071
- /_get_(coin_by_id|token_holders|top_holders|onchain_token_top_holders|token_data|protocol_tvl|protocols|categories|trending|nft_collection)\b/
49072
- ],
49073
- ttlS: TTL_METADATA_S
49074
- }
49075
- ];
49076
- function ttlForTool(toolName) {
49077
- for (const b of BUCKETS) {
49078
- if (b.patterns.some((rx) => rx.test(toolName))) return b.ttlS;
49079
- }
49080
- return 0;
49081
- }
49082
- function hashArgs(args) {
49083
- return crypto.createHash("sha256").update(stableStringify(args)).digest("hex").slice(0, 32);
49084
- }
49085
- function stableStringify(value) {
49086
- if (value === null || typeof value !== "object") {
49087
- return JSON.stringify(value);
49088
- }
49089
- if (Array.isArray(value)) {
49090
- return `[${value.map(stableStringify).join(",")}]`;
49091
- }
49092
- const obj = value;
49093
- const keys = Object.keys(obj).sort();
49094
- return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`).join(",")}}`;
49095
- }
49096
- function cacheKey(toolName, args) {
49097
- return `${PREFIX}${toolName}:${hashArgs(args)}`;
49098
- }
49099
- async function getCached(toolName, args) {
49100
- const redis = getRedisClient();
49101
- if (!redis || !isRedisAvailable()) return null;
49102
- if (ttlForTool(toolName) === 0) return null;
49103
- try {
49104
- const raw = await redis.get(cacheKey(toolName, args));
49105
- if (!raw) return null;
49106
- try {
49107
- const parsed = JSON.parse(raw);
49108
- if (parsed._hive_cache_version === CACHE_ENVELOPE_VERSION && typeof parsed.observed_at === "string" && typeof parsed.payload === "string") {
49109
- const observedMs = Date.parse(parsed.observed_at);
49110
- return {
49111
- payload: parsed.payload,
49112
- observedAt: parsed.observed_at,
49113
- ageMs: Number.isFinite(observedMs) ? Math.max(0, Date.now() - observedMs) : null,
49114
- originSource: parsed.origin_source === "live" || parsed.origin_source === "fallback" ? parsed.origin_source : null
49115
- };
49116
- }
49117
- } catch {
49118
- }
49119
- return {
49120
- payload: raw,
49121
- observedAt: null,
49122
- ageMs: null,
49123
- originSource: null
49124
- };
49125
- } catch (err) {
49126
- secureLogger.warn("[mcp-cache] get failed", {
49127
- error: err instanceof Error ? err.message : String(err)
49128
- });
49129
- return null;
49130
- }
49131
- }
49132
- async function setCached(toolName, args, payload, originSource = "live") {
49133
- const redis = getRedisClient();
49134
- if (!redis || !isRedisAvailable()) return;
49135
- const ttlS = ttlForTool(toolName);
49136
- if (ttlS === 0) return;
49137
- try {
49138
- const envelope = {
49139
- _hive_cache_version: CACHE_ENVELOPE_VERSION,
49140
- observed_at: (/* @__PURE__ */ new Date()).toISOString(),
49141
- origin_source: originSource,
49142
- payload
49143
- };
49144
- await redis.set(
49145
- cacheKey(toolName, args),
49146
- JSON.stringify(envelope),
49147
- "EX",
49148
- ttlS
49149
- );
49150
- } catch (err) {
49151
- secureLogger.warn("[mcp-cache] set failed", {
49152
- error: err instanceof Error ? err.message : String(err)
49153
- });
49154
- }
49155
- }
49156
-
49157
48919
  // src/providers/catalog.ts
49158
48920
  var UNKNOWN_PROVIDER_DESCRIPTOR = {
49159
48921
  id: "unknown",
@@ -50412,31 +50174,6 @@ function createSafeHandler(handler100, metadata103, toolName, inputSchema) {
50412
50174
  }
50413
50175
  const { response_format: responseFormat, ...safeArgs } = args ?? {};
50414
50176
  const wantsMarkdown = responseFormat === "markdown";
50415
- const cacheableTtlS = ttlForTool(toolName);
50416
- if (cacheableTtlS > 0 && !wantsMarkdown) {
50417
- const cached = await getCached(toolName, safeArgs);
50418
- if (cached) {
50419
- trackToolCall({
50420
- toolName,
50421
- success: true,
50422
- durationMs: Date.now() - t0,
50423
- category: "cache_hit"
50424
- });
50425
- return withContentAnnotations(
50426
- withExecMarker(
50427
- { content: [{ type: "text", text: cached.payload }] },
50428
- {
50429
- source: "cached",
50430
- originSource: cached.originSource,
50431
- cacheStatus: "hit",
50432
- observedAt: cached.observedAt,
50433
- cacheAgeMs: cached.ageMs
50434
- }
50435
- ),
50436
- false
50437
- );
50438
- }
50439
- }
50440
50177
  let result2 = await handler100(effectiveClient, safeArgs);
50441
50178
  const observedAt = (/* @__PURE__ */ new Date()).toISOString();
50442
50179
  if (result2._hiveExec?.source === "fallback") usedFallback = true;
@@ -50562,23 +50299,14 @@ function createSafeHandler(handler100, metadata103, toolName, inputSchema) {
50562
50299
  true
50563
50300
  );
50564
50301
  }
50565
- if (cacheableTtlS > 0 && !wantsMarkdown) {
50566
- setCached(
50567
- toolName,
50568
- safeArgs,
50569
- text,
50570
- usedFallback ? "fallback" : "live"
50571
- ).catch(() => {
50572
- });
50573
- }
50574
50302
  trackToolCall({
50575
50303
  toolName,
50576
50304
  success: !result2.isError,
50577
50305
  durationMs: Date.now() - t0,
50578
- category: cacheableTtlS > 0 ? "live_cacheable" : "live_uncached"
50306
+ category: "live_uncached"
50579
50307
  });
50580
50308
  const successMarker = {
50581
- cacheStatus: cacheableTtlS > 0 && !wantsMarkdown ? "miss" : "bypass",
50309
+ cacheStatus: "bypass",
50582
50310
  observedAt,
50583
50311
  cacheAgeMs: 0,
50584
50312
  originSource: usedFallback ? "fallback" : "live",
@@ -51922,290 +51650,6 @@ function buildToolCatalogEntry(endpoint) {
51922
51650
  };
51923
51651
  }
51924
51652
 
51925
- // src/config/toolNameMappings.ts
51926
- var TOOL_NAME_MAPPINGS = {
51927
- // ============================================
51928
- // Category 1: Market Data and Price (43 tools)
51929
- // ============================================
51930
- // CoinGecko endpoints
51931
- coins_index: "get_coins_index",
51932
- coins_market_data_browser: "get_coins_market_data",
51933
- coins_history_browser: "get_coin_history",
51934
- range_coins_market_chart_browser: "get_coin_market_chart_range",
51935
- range_coins_ohlc_browser: "get_coin_ohlc_range",
51936
- simple_price_browser: "get_price",
51937
- gainers_losers_browser: "get_gainers_losers",
51938
- contract_coins_browser: "get_contract_coin",
51939
- range_contract_coins_market_chart_browser: "get_contract_market_chart_range",
51940
- id_simple_token_price_browser: "get_token_price_by_contract",
51941
- global_browser: "get_global_stats",
51942
- simple_supported_vs_currencies_browser: "get_supported_currencies",
51943
- // Codex endpoints
51944
- retrieve_token_pricing: "codex_get_token_price",
51945
- fetch_price_chart_data: "get_token_chart_data",
51946
- fetch_token_mini_charts: "get_token_sparklines",
51947
- fetch_token_chart_urls: "get_token_chart_urls",
51948
- // CoinGecko additional
51949
- coin_tickers_data: "get_coin_tickers",
51950
- coin_historical_chart: "get_coin_historical_chart",
51951
- btc_exchange_rates: "get_btc_exchange_rates",
51952
- global_market_cap_chart: "get_global_market_cap_chart",
51953
- companies_crypto_treasury: "get_companies_treasury",
51954
- // Stablecoins (DeFiLlama)
51955
- stablecoins_list: "get_stablecoins",
51956
- stablecoin_chains_list: "get_stablecoin_chains",
51957
- stablecoin_charts_global: "get_stablecoin_charts_global",
51958
- stablecoin_charts_by_chain: "get_stablecoin_charts_by_chain",
51959
- stablecoin_prices_current: "get_stablecoin_prices",
51960
- // CCXT
51961
- trading_pair_ticker_data: "get_ticker",
51962
- multiple_tickers_data: "get_tickers",
51963
- trading_pair_orderbook_data: "get_orderbook",
51964
- trading_pair_recent_trades: "get_recent_trades",
51965
- trading_pair_candlestick_data: "get_ohlcv",
51966
- multiple_pairs_best_prices: "get_best_bid_ask",
51967
- level2_orderbook_data: "get_l2_orderbook",
51968
- derivatives_index_candlestick: "get_index_ohlcv",
51969
- derivatives_mark_candlestick: "get_mark_ohlcv",
51970
- perpetual_premium_index_data: "get_premium_index_ohlcv",
51971
- perpetual_funding_rate_current: "get_funding_rate",
51972
- perpetual_funding_rate_history: "get_funding_rate_history",
51973
- perpetual_funding_rates_all: "get_funding_rates",
51974
- // ============================================
51975
- // Category 2: On-Chain DEX & Pool Analytics (50 tools)
51976
- // ============================================
51977
- // GeckoTerminal (CoinGecko OnChain)
51978
- onchain_categories_browser: "get_onchain_categories",
51979
- pools_onchain_categories_browser: "get_pools_by_category",
51980
- networks_onchain_new_pools_browser: "get_new_pools",
51981
- network_networks_onchain_new_pools_browser: "get_new_pools_by_network",
51982
- networks_onchain_trending_pools_browser: "get_trending_pools",
51983
- network_networks_onchain_trending_pools_browser: "get_trending_pools_by_network",
51984
- networks_onchain_dexes_browser: "get_dexes",
51985
- pools_networks_onchain_dexes_browser: "get_pools_by_dex",
51986
- networks_onchain_pools_browser: "get_pools",
51987
- address_networks_onchain_pools_browser: "get_pools_by_address",
51988
- pools_networks_onchain_info_browser: "get_pool_info",
51989
- timeframe_pools_networks_onchain_ohlcv_browser: "get_pool_ohlcv",
51990
- pools_networks_onchain_trades_browser: "get_pool_trades",
51991
- timeframe_tokens_networks_onchain_ohlcv_browser: "get_token_ohlcv",
51992
- tokens_networks_onchain_pools_browser: "get_token_pools",
51993
- tokens_networks_onchain_trades_browser: "get_token_trades",
51994
- pools_onchain_megafilter_browser: "filter_pools",
51995
- pools_onchain_trending_search_browser: "search_trending_pools",
51996
- search_onchain_pools_browser: "search_pools",
51997
- addresses_networks_simple_onchain_token_price_browser: "get_onchain_token_price",
51998
- // Codex
51999
- retrieve_token_transactions: "get_token_transactions",
52000
- fetch_trading_pair_metrics: "get_pair_stats",
52001
- fetch_multiple_pairs_metrics: "get_pairs_stats",
52002
- search_filter_pairs: "filter_pairs",
52003
- fetch_pair_information: "get_pair_info",
52004
- list_token_pairs: "get_token_pairs",
52005
- fetch_token_pairs_details: "get_token_pairs_metadata",
52006
- retrieve_liquidity_information: "get_liquidity_info",
52007
- fetch_liquidity_lock_details: "get_liquidity_locks",
52008
- search_exchange_platforms: "filter_exchanges",
52009
- describe_onchain_transaction: "explain_transaction",
52010
- // CoinGecko Exchanges
52011
- exchanges_data: "get_exchanges",
52012
- exchange_details: "get_exchange",
52013
- exchange_tickers_data: "get_exchange_tickers",
52014
- exchange_volume_chart: "get_exchange_volume_chart",
52015
- exchange_volume_chart_range: "get_exchange_volume_chart_range",
52016
- derivatives_tickers_data: "get_derivatives_tickers",
52017
- derivatives_exchanges_data: "get_derivatives_exchanges",
52018
- derivative_exchange_details: "get_derivatives_exchange",
52019
- // Additional
52020
- network_trending_pools: "get_network_trending_pools",
52021
- multi_pools_data: "get_multi_pools",
52022
- network_exchanges_list: "get_network_dexes",
52023
- pair_chart_metadata: "get_pair_chart_metadata",
52024
- token_liquidity_metadata: "get_token_liquidity_metadata",
52025
- // DeFiLlama DEX
52026
- dex_volumes_overview: "get_dex_volumes",
52027
- dex_volume_specific: "get_dex_volume",
52028
- dex_volumes_chain_specific: "get_dex_volumes_by_chain",
52029
- options_trading_overview: "get_options_overview",
52030
- options_trading_by_chain: "get_options_by_chain",
52031
- options_protocol_summary: "get_options_protocol",
52032
- // ============================================
52033
- // Category 3: Portfolio & Wallet (14 tools)
52034
- // ============================================
52035
- // Codex
52036
- fetch_wallet_balances: "get_wallet_balances",
52037
- fetch_wallet_token_activity: "get_wallet_token_events",
52038
- wallets_search_filter: "filter_wallets",
52039
- token_wallets_filter: "filter_token_wallets",
52040
- wallet_detailed_stats: "get_wallet_stats",
52041
- wallet_chart_data: "get_wallet_chart",
52042
- // ============================================
52043
- // Category 4: Token & Contract Data (15 tools)
52044
- // ============================================
52045
- // GeckoTerminal
52046
- address_networks_onchain_tokens_browser: "get_tokens_by_address",
52047
- tokens_networks_onchain_info_browser: "get_token_info",
52048
- tokens_networks_onchain_top_holders_browser: "get_token_top_holders",
52049
- tokens_networks_onchain_holders_chart_browser: "get_token_holders_chart",
52050
- // Codex
52051
- retrieve_token_details: "get_token_details",
52052
- fetch_multiple_tokens: "get_tokens",
52053
- search_tokens_by_criteria: "filter_tokens",
52054
- list_token_holders: "get_token_holders",
52055
- calculate_top_holders_percentage: "get_top_holders_percentage",
52056
- list_newest_token_contracts: "get_new_tokens",
52057
- multi_tokens_data: "get_multi_tokens",
52058
- tokens_recent_updates: "get_recently_updated_tokens",
52059
- token_top_traders_stats: "get_token_top_traders",
52060
- fetch_coin_metadata: "get_coin_metadata",
52061
- // ============================================
52062
- // Category 5: DeFi Protocol Analytics
52063
- // ============================================
52064
- // CoinGecko
52065
- global_defi_data: "get_global_defi",
52066
- // DeFiLlama
52067
- defi_protocols_list: "get_defi_protocols",
52068
- defi_protocol_details: "get_defi_protocol",
52069
- protocol_tvl_current: "get_protocol_tvl",
52070
- protocol_fees_data: "get_protocol_fees",
52071
- blockchain_chains_list: "get_chains",
52072
- chain_tvl_history: "get_chain_tvl_history",
52073
- chains_tvl_historical_all: "get_chains_tvl_history",
52074
- yield_pools_list: "get_yield_pools",
52075
- yield_pool_details: "get_yield_pool_chart",
52076
- yield_pool_chart_history: "get_yield_pool_chart",
52077
- protocol_fees_overview: "get_fees_overview",
52078
- chain_fees_overview: "get_chain_fees",
52079
- // ============================================
52080
- // Category 6: NFT Analytics (30 tools)
52081
- // ============================================
52082
- // CoinGecko NFTs
52083
- id_nfts_browser: "get_nft",
52084
- list_nfts_browser: "get_nfts",
52085
- nfts_market_chart_browser: "get_nft_market_chart",
52086
- // ============================================
52087
- // Category 7: Security & Risk Analysis (8 tools)
52088
- // ============================================
52089
- // GoPlus (mostly compliant)
52090
- get_token_security: "get_token_security",
52091
- // Already compliant
52092
- get_nft_security: "get_nft_security",
52093
- // Already compliant
52094
- check_malicious_address: "check_malicious_address",
52095
- // Already compliant
52096
- check_approval_security: "check_approval_security",
52097
- // Already compliant
52098
- get_user_approvals: "get_wallet_approvals",
52099
- check_dapp_security: "check_dapp_security",
52100
- // Already compliant
52101
- detect_phishing_site: "check_phishing_site",
52102
- decode_abi_data: "decode_abi",
52103
- // ============================================
52104
- // Category 8: Network & Infrastructure (12 tools)
52105
- // ============================================
52106
- // GeckoTerminal
52107
- onchain_networks_browser: "get_networks",
52108
- // Codex
52109
- list_blockchain_networks: "get_networks_list",
52110
- check_network_health: "get_network_status",
52111
- fetch_network_metrics: "get_network_stats",
52112
- // CoinGecko
52113
- asset_platforms_browser: "get_asset_platforms",
52114
- // Codex
52115
- community_notes_data: "get_community_notes",
52116
- monitor_system_updates: "get_system_changes",
52117
- // CCXT
52118
- exchange_system_status: "get_exchange_status",
52119
- exchange_server_time: "get_exchange_time",
52120
- exchange_markets_browser: "get_exchange_markets",
52121
- exchange_currencies_browser: "get_exchange_currencies",
52122
- // ============================================
52123
- // Category 9: Search & Discovery (9 tools)
52124
- // ============================================
52125
- // CoinGecko
52126
- search_browser: "search_all",
52127
- search_trending_browser: "get_trending",
52128
- coins_categories_browser: "get_categories",
52129
- coins_list_browser: "get_coins_list",
52130
- new_coins_list_browser: "get_new_coins",
52131
- coins_categories_market_data: "get_categories_market_data",
52132
- exchanges_list_simple: "get_exchanges_list",
52133
- derivatives_exchanges_list: "get_derivatives_exchanges_list",
52134
- // Codex
52135
- event_labels_list: "get_event_labels"
52136
- };
52137
- var REVERSE_TOOL_NAME_MAPPINGS = Object.entries(TOOL_NAME_MAPPINGS).reduce(
52138
- (acc, [legacy, standard]) => {
52139
- acc[standard] = legacy;
52140
- return acc;
52141
- },
52142
- {}
52143
- );
52144
- var COMPLIANT_TOOLS = [
52145
- "get_token_security",
52146
- "get_nft_security",
52147
- "check_malicious_address",
52148
- "check_approval_security",
52149
- "check_dapp_security"
52150
- ];
52151
- function getStandardName(legacyName) {
52152
- return TOOL_NAME_MAPPINGS[legacyName] || legacyName;
52153
- }
52154
- function isLegacyName(name) {
52155
- return name in TOOL_NAME_MAPPINGS && TOOL_NAME_MAPPINGS[name] !== name;
52156
- }
52157
-
52158
- // src/config/toolAliasSystem.ts
52159
- var defaultConfig = {
52160
- enableWarnings: true,
52161
- enableTracking: true,
52162
- strictMode: false
52163
- };
52164
- var config = { ...defaultConfig };
52165
- var usageStats = {
52166
- legacyUsage: {},
52167
- standardUsage: {},
52168
- lastUpdated: /* @__PURE__ */ new Date()
52169
- };
52170
- function logDeprecationWarning(legacyName, standardName) {
52171
- if (!config.enableWarnings) return;
52172
- const message = `[DEPRECATED] Tool "${legacyName}" is deprecated. Use "${standardName}" instead.`;
52173
- if (config.warningHandler) {
52174
- config.warningHandler(message, legacyName, standardName);
52175
- } else {
52176
- console.warn(`\x1B[33m${message}\x1B[0m`);
52177
- }
52178
- }
52179
- function trackUsage(toolName, isLegacy) {
52180
- if (!config.enableTracking) return;
52181
- usageStats.lastUpdated = /* @__PURE__ */ new Date();
52182
- if (isLegacy) {
52183
- usageStats.legacyUsage[toolName] = (usageStats.legacyUsage[toolName] || 0) + 1;
52184
- } else {
52185
- usageStats.standardUsage[toolName] = (usageStats.standardUsage[toolName] || 0) + 1;
52186
- }
52187
- }
52188
- function resolveToolName(requestedName) {
52189
- if (isLegacyName(requestedName)) {
52190
- const standardName = getStandardName(requestedName);
52191
- logDeprecationWarning(requestedName, standardName);
52192
- trackUsage(requestedName, true);
52193
- return standardName;
52194
- }
52195
- if (requestedName in REVERSE_TOOL_NAME_MAPPINGS) {
52196
- trackUsage(requestedName, false);
52197
- return requestedName;
52198
- }
52199
- if (COMPLIANT_TOOLS.includes(requestedName)) {
52200
- trackUsage(requestedName, false);
52201
- return requestedName;
52202
- }
52203
- if (config.strictMode) {
52204
- throw new Error(`Unknown tool: "${requestedName}"`);
52205
- }
52206
- return requestedName;
52207
- }
52208
-
52209
51653
  // src/utils/errorCodes.ts
52210
51654
  var ERROR_DOC_BASE = "https://www.hiveintelligence.xyz/errors";
52211
51655
  function entry(code, transports, meaning, nextAction, retryable = false) {
@@ -53018,7 +52462,7 @@ function isRecord2(value) {
53018
52462
  }
53019
52463
  function resolveEndpoint(endpoints, toolName) {
53020
52464
  const requestedToolName = toolName ?? "";
53021
- const resolvedToolName = requestedToolName ? resolveToolName(requestedToolName) : "";
52465
+ const resolvedToolName = requestedToolName;
53022
52466
  const endpoint = endpoints.find(
53023
52467
  (item) => item.tool.name === resolvedToolName
53024
52468
  );
@@ -53035,7 +52479,7 @@ function normalizeInvokeArgs(args) {
53035
52479
  message: "No endpoint provided. Pass 'endpoint_name' (or 'endpoint') and optionally 'args'."
53036
52480
  };
53037
52481
  }
53038
- const resolvedToolName = resolveToolName(requestedToolName);
52482
+ const resolvedToolName = requestedToolName;
53039
52483
  let nestedArgs = args?.args;
53040
52484
  if (typeof nestedArgs === "string") {
53041
52485
  try {
@@ -53151,9 +52595,9 @@ function createHiveExecutionMetadata(endpoint, durationMs, runtimeStatus, source
53151
52595
  observed_at: observedAt,
53152
52596
  cache_age_ms: cacheAgeMs,
53153
52597
  duration_ms: durationMs,
53154
- // Markers from createSafeHandler (cache hit, fallback client, truncation)
53155
- // take precedence over the caller-supplied defaults so the agent sees
53156
- // whether data is live, cached, or fallback-tier.
52598
+ // Markers from createSafeHandler (fallback client, truncation) take
52599
+ // precedence over the caller-supplied defaults so the agent sees whether
52600
+ // data is live or fallback-tier.
53157
52601
  cache_status: exec?.cacheStatus ?? "unknown",
53158
52602
  source: effectiveSource,
53159
52603
  origin_source: originSource,
@@ -54426,7 +53870,7 @@ function heroTools(endpoints, options = {}) {
54426
53870
  'Chain name, for example "eth", "base", "arbitrum", or "solana". Defaults to eth for 0x addresses; Solana is auto-detected.'
54427
53871
  ),
54428
53872
  include_spam: z.boolean().optional().describe(
54429
- "Show likely spam airdrops (tokens with a URL or claim lure in the name, and on EVM chains tokens with no market price). Default false; the response says how many were hidden."
53873
+ "Show likely spam airdrops (tokens with a URL or claim lure in the name, and on EVM chains tokens with no market price or not listed on CoinGecko). Default false; the response says how many were hidden."
54430
53874
  ),
54431
53875
  response_format: RESPONSE_FORMAT
54432
53876
  });
@@ -54512,15 +53956,21 @@ function heroTools(endpoints, options = {}) {
54512
53956
  address: tokenAddress,
54513
53957
  balance,
54514
53958
  usd_value: token.totalValueUsd ?? token.valueUsd ?? token.usd_value ?? (typeof token.totalValueUsdCents === "number" ? token.totalValueUsdCents / 100 : usdFromPrices(token, balance)),
54515
- ...token.h24_change_pct != null ? { h24_change_pct: token.h24_change_pct } : {}
53959
+ ...token.h24_change_pct != null ? { h24_change_pct: token.h24_change_pct } : {},
53960
+ ...token.coingecko_listed === false ? { coingecko_listed: false } : {}
54516
53961
  };
54517
53962
  });
54518
53963
  const nonZero = summarized.filter(
54519
53964
  (token) => !isRecord3(token) || token.balance !== "0"
54520
53965
  );
54521
- const isSpam = (token) => isRecord3(token) && token.address != null && (SPAM_LURE.test(`${token.name ?? ""} ${token.symbol ?? ""}`) || priced && token.usd_value == null);
53966
+ const isSpam = (token) => isRecord3(token) && token.address != null && (SPAM_LURE.test(`${token.name ?? ""} ${token.symbol ?? ""}`) || priced && token.usd_value == null || token.coingecko_listed === false);
54522
53967
  const held = includeSpam ? nonZero : nonZero.filter((t) => !isSpam(t));
54523
53968
  const hidden = nonZero.length - held.length;
53969
+ const total = payload.total_value_usd;
53970
+ const hiddenUsd = nonZero.filter((t) => !held.includes(t)).reduce(
53971
+ (sum, t) => sum + (isRecord3(t) && typeof t.usd_value === "number" ? t.usd_value : 0),
53972
+ 0
53973
+ );
54524
53974
  return {
54525
53975
  address,
54526
53976
  chain: chainLabel,
@@ -54528,7 +53978,7 @@ function heroTools(endpoints, options = {}) {
54528
53978
  ...hidden > 0 ? {
54529
53979
  spam_hidden: {
54530
53980
  count: hidden,
54531
- reason: priced ? "no market price, or a URL/claim lure in the name" : "a URL/claim lure in the name",
53981
+ reason: priced ? "no market price, not listed on CoinGecko, or a URL/claim lure in the name" : "a URL/claim lure in the name",
54532
53982
  note: "Likely spam airdrops; pass include_spam=true to show them."
54533
53983
  }
54534
53984
  } : {},
@@ -54537,7 +53987,8 @@ function heroTools(endpoints, options = {}) {
54537
53987
  note: `Showing the first ${MAX_CONCISE_TOKENS} of ${held.length} held tokens (zero balances omitted). Use response_format=detailed for the full provider payload.`
54538
53988
  } : summarized.length > nonZero.length ? {
54539
53989
  note: `${summarized.length - nonZero.length} zero-balance tokens omitted. Use response_format=detailed for the full provider payload.`
54540
- } : {}
53990
+ } : {},
53991
+ ...typeof total === "number" ? { total_value_usd: Math.round((total - hiddenUsd) * 100) / 100 } : {}
54541
53992
  };
54542
53993
  };
54543
53994
  const coingeckoBalances = (payload) => {
@@ -54553,7 +54004,9 @@ function heroTools(endpoints, options = {}) {
54553
54004
  balance: row.balance ?? null,
54554
54005
  decimals: 0,
54555
54006
  usd_value: toNumber(row.value_usd),
54556
- h24_change_pct: toNumber(row.h24_price_change_percentage)
54007
+ h24_change_pct: toNumber(row.h24_price_change_percentage),
54008
+ // Only an explicit null means unlisted; a missing field fails open.
54009
+ coingecko_listed: row.coingecko_coin_id !== null
54557
54010
  }))
54558
54011
  };
54559
54012
  };
@@ -54606,13 +54059,13 @@ function heroTools(endpoints, options = {}) {
54606
54059
  per_page: 100
54607
54060
  }, "get_wallet_portfolio");
54608
54061
  if (!network || "hive" in result3 && result3.ok) {
54609
- return respond(result3, format, (payload) => {
54610
- const balances = coingeckoBalances(payload);
54611
- return {
54612
- ...trimWalletPortfolio(address, normalized, includeSpam, true)(balances),
54613
- total_value_usd: balances.total_value_usd
54614
- };
54615
- });
54062
+ return respond(
54063
+ result3,
54064
+ format,
54065
+ (payload) => trimWalletPortfolio(address, normalized, includeSpam, true)(
54066
+ coingeckoBalances(payload)
54067
+ )
54068
+ );
54616
54069
  }
54617
54070
  fallbackNote = "CoinGecko wallet balances failed for this call; served from Alchemy.";
54618
54071
  }
@@ -57301,6 +56754,123 @@ async function executeEndpointWithRouteFallback(endpoints, endpoint, args, conte
57301
56754
  // src/health/scheduledCanaries.ts
57302
56755
  import { randomUUID as randomUUID5 } from "crypto";
57303
56756
 
56757
+ // src/utils/redis.ts
56758
+ import Redis from "ioredis";
56759
+ var client = null;
56760
+ var available = false;
56761
+ function logRedisInfo(message) {
56762
+ process.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} [INFO]: ${message}
56763
+ `);
56764
+ }
56765
+ function getRedisClient() {
56766
+ return client;
56767
+ }
56768
+ function isRedisAvailable() {
56769
+ return available;
56770
+ }
56771
+ async function waitForRedisAvailability(timeoutMs = 1e4) {
56772
+ if (!client) return false;
56773
+ if (available) return true;
56774
+ const boundedTimeoutMs = Math.max(1, Math.min(timeoutMs, 3e4));
56775
+ const current = client;
56776
+ return new Promise((resolve) => {
56777
+ let settled = false;
56778
+ const finish = (ready) => {
56779
+ if (settled) return;
56780
+ settled = true;
56781
+ clearTimeout(timer);
56782
+ current.off("ready", onReady);
56783
+ current.off("end", onEnd);
56784
+ resolve(ready);
56785
+ };
56786
+ const onReady = () => finish(true);
56787
+ const onEnd = () => finish(false);
56788
+ const timer = setTimeout(() => finish(available), boundedTimeoutMs);
56789
+ current.once("ready", onReady);
56790
+ current.once("end", onEnd);
56791
+ if (available) finish(true);
56792
+ });
56793
+ }
56794
+ async function closeRedisClient() {
56795
+ if (!client) return;
56796
+ const current = client;
56797
+ client = null;
56798
+ available = false;
56799
+ try {
56800
+ await Promise.race([
56801
+ current.quit(),
56802
+ new Promise(
56803
+ (_, reject) => setTimeout(() => reject(new Error("Redis quit timed out")), 5e3)
56804
+ )
56805
+ ]);
56806
+ logRedisInfo("[redis] Connection closed gracefully");
56807
+ } catch (err) {
56808
+ secureLogger.error(
56809
+ "[redis] Error closing connection, forcing disconnect",
56810
+ err,
56811
+ {}
56812
+ );
56813
+ current.disconnect();
56814
+ }
56815
+ }
56816
+ var DEGRADED_AFTER_ATTEMPTS = 3;
56817
+ var MAX_RECONNECT_DELAY_MS = 3e3;
56818
+ function redisRetryStrategy(times) {
56819
+ if (times === DEGRADED_AFTER_ATTEMPTS) {
56820
+ secureLogger.warn(
56821
+ `[redis] Connection failed after ${DEGRADED_AFTER_ATTEMPTS} retries, falling back to in-memory while reconnection continues`,
56822
+ {}
56823
+ );
56824
+ available = false;
56825
+ }
56826
+ return Math.min(times * 100, MAX_RECONNECT_DELAY_MS);
56827
+ }
56828
+ function redisClientOptions() {
56829
+ return {
56830
+ maxRetriesPerRequest: 3,
56831
+ retryStrategy: redisRetryStrategy,
56832
+ lazyConnect: true
56833
+ };
56834
+ }
56835
+ var redisUrl = getEnvVar("REDIS_URL");
56836
+ function isRedisConfigured() {
56837
+ return Boolean(redisUrl);
56838
+ }
56839
+ if (redisUrl) {
56840
+ try {
56841
+ client = new Redis(redisUrl, redisClientOptions());
56842
+ client.connect().then(() => {
56843
+ available = true;
56844
+ logRedisInfo("[redis] Connected successfully");
56845
+ }).catch((err) => {
56846
+ secureLogger.warn("[redis] Connection failed", {
56847
+ error: err.message
56848
+ });
56849
+ available = false;
56850
+ });
56851
+ client.on("error", (err) => {
56852
+ secureLogger.warn("[redis] Error", { error: err.message });
56853
+ available = false;
56854
+ });
56855
+ client.on("ready", () => {
56856
+ available = true;
56857
+ });
56858
+ const gracefulShutdown = async (signal) => {
56859
+ logRedisInfo(`[redis] Received ${signal}, closing connection...`);
56860
+ await closeRedisClient();
56861
+ };
56862
+ process.on("SIGINT", () => gracefulShutdown("SIGINT"));
56863
+ process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
56864
+ } catch (err) {
56865
+ secureLogger.warn("[redis] Failed to initialise", {
56866
+ error: String(err)
56867
+ });
56868
+ client = null;
56869
+ }
56870
+ } else {
56871
+ logRedisInfo("[redis] No REDIS_URL provided, using in-memory fallbacks");
56872
+ }
56873
+
57304
56874
  // src/health/canaryHistory.ts
57305
56875
  var HEALTH_EVIDENCE_STATUSES = [
57306
56876
  "unknown",
@@ -58987,16 +58557,16 @@ function sameScopes(left, right) {
58987
58557
  return left.length === right.length && right.every((scope) => left.includes(scope));
58988
58558
  }
58989
58559
  var HiveOAuthProvider = class {
58990
- constructor(config2, storage2, options = {}) {
58991
- this.config = config2;
58560
+ constructor(config, storage2, options = {}) {
58561
+ this.config = config;
58992
58562
  this.storage = storage2;
58993
- if (!config2.configured || !config2.issuerUrl || !config2.resourceUrl || !config2.consentUrl) {
58563
+ if (!config.configured || !config.issuerUrl || !config.resourceUrl || !config.consentUrl) {
58994
58564
  throw new Error("Cannot construct OAuth provider from incomplete configuration.");
58995
58565
  }
58996
58566
  this.clientsStore = new HiveOAuthClientsStore({
58997
58567
  storage: storage2,
58998
- dcrClientTtlSeconds: config2.dcrClientTtlSeconds,
58999
- cimdAllowedHosts: config2.cimdAllowedHosts,
58568
+ dcrClientTtlSeconds: config.dcrClientTtlSeconds,
58569
+ cimdAllowedHosts: config.cimdAllowedHosts,
59000
58570
  fetcher: options.fetcher
59001
58571
  });
59002
58572
  }
@@ -59745,11 +59315,11 @@ function elapsed(started) {
59745
59315
  function check(name, status, started, detail) {
59746
59316
  return { name, status, duration: elapsed(started), detail };
59747
59317
  }
59748
- function healthResult(started, status, config2, persistentStorage, checks) {
59318
+ function healthResult(started, status, config, persistentStorage, checks) {
59749
59319
  return {
59750
59320
  status,
59751
- enabled: config2.enabled,
59752
- configured: config2.configured,
59321
+ enabled: config.enabled,
59322
+ configured: config.configured,
59753
59323
  persistentStorage,
59754
59324
  checks,
59755
59325
  passed: checks.filter((entry2) => entry2.status === "passed").length,
@@ -60101,6 +59671,7 @@ function parsePositiveInteger(value, fallback) {
60101
59671
  function sleep4(ms) {
60102
59672
  return new Promise((resolve) => setTimeout(resolve, ms));
60103
59673
  }
59674
+ var GOPLUS_CALL_BUDGET_MS = 45e3;
60104
59675
  function chainIdPathSegment(value) {
60105
59676
  return assertDecimalPathSegment(value, "chainId");
60106
59677
  }
@@ -60247,6 +59818,27 @@ var GoPlusClient = class {
60247
59818
  * @internal
60248
59819
  */
60249
59820
  async request(endpoint, params, method = "GET") {
59821
+ let timer;
59822
+ const budget = new Promise((_, reject) => {
59823
+ timer = setTimeout(
59824
+ () => reject(
59825
+ new Error(
59826
+ `GoPlus ${endpoint} timed out after ${GOPLUS_CALL_BUDGET_MS / 1e3}s; nothing was returned.`
59827
+ )
59828
+ ),
59829
+ GOPLUS_CALL_BUDGET_MS
59830
+ );
59831
+ });
59832
+ try {
59833
+ return await Promise.race([
59834
+ this.send(endpoint, params, method),
59835
+ budget
59836
+ ]);
59837
+ } finally {
59838
+ clearTimeout(timer);
59839
+ }
59840
+ }
59841
+ async send(endpoint, params, method) {
60250
59842
  const startTime = Date.now();
60251
59843
  try {
60252
59844
  let url = endpoint;
@@ -60851,9 +60443,9 @@ var CCXTClient = class {
60851
60443
  throw new Error("Exchange ID is required");
60852
60444
  }
60853
60445
  const ccxt = await loadCcxt();
60854
- const cacheKey2 = `${exchangeId}`;
60855
- if (this.exchanges.has(cacheKey2)) {
60856
- return this.exchanges.get(cacheKey2);
60446
+ const cacheKey = `${exchangeId}`;
60447
+ if (this.exchanges.has(cacheKey)) {
60448
+ return this.exchanges.get(cacheKey);
60857
60449
  }
60858
60450
  if (REMOVED_CCXT_EXCHANGES.has(exchangeId.toLowerCase())) {
60859
60451
  throw new Error(removedVenueMessage(exchangeId));
@@ -60869,7 +60461,7 @@ var CCXTClient = class {
60869
60461
  // Prevent API rate limit violations
60870
60462
  ...options
60871
60463
  });
60872
- this.exchanges.set(cacheKey2, exchange);
60464
+ this.exchanges.set(cacheKey, exchange);
60873
60465
  secureLogger.debug("Exchange initialized", {
60874
60466
  exchangeId,
60875
60467
  hasRateLimit: true
@@ -63053,14 +62645,14 @@ function firstString(value, keys) {
63053
62645
  }
63054
62646
  return void 0;
63055
62647
  }
63056
- function getCachedDynamicArgs(cacheKey2, resolver) {
63057
- const cached = dynamicProbeArgCache.get(cacheKey2);
62648
+ function getCachedDynamicArgs(cacheKey, resolver) {
62649
+ const cached = dynamicProbeArgCache.get(cacheKey);
63058
62650
  if (cached) return cached;
63059
62651
  const promise = resolver().catch((err) => {
63060
- dynamicProbeArgCache.delete(cacheKey2);
62652
+ dynamicProbeArgCache.delete(cacheKey);
63061
62653
  throw err;
63062
62654
  });
63063
- dynamicProbeArgCache.set(cacheKey2, promise);
62655
+ dynamicProbeArgCache.set(cacheKey, promise);
63064
62656
  return promise;
63065
62657
  }
63066
62658
  var hiveCanarySubjectContextPromise;
@@ -64996,7 +64588,7 @@ var refreshing = null;
64996
64588
  var testOverrides = null;
64997
64589
  async function refreshWithCanary() {
64998
64590
  const now = Date.now();
64999
- const config2 = buildConfigSnapshot(now);
64591
+ const config = buildConfigSnapshot(now);
65000
64592
  try {
65001
64593
  const history = await getProviderCanaryHistory(1);
65002
64594
  const latest = history.evidence.state === "present" ? history.latest : null;
@@ -65009,20 +64601,20 @@ async function refreshWithCanary() {
65009
64601
  const observed = availabilityFromRuntimeStatus(
65010
64602
  api.runtimeStatus ?? (api.status === "passed" ? "ok" : api.status === "inactive" ? "degraded" : "failing")
65011
64603
  );
65012
- config2.byProviderName[descriptor.name] = worseOf(
65013
- config2.byProviderName[descriptor.name] ?? "ok",
64604
+ config.byProviderName[descriptor.name] = worseOf(
64605
+ config.byProviderName[descriptor.name] ?? "ok",
65014
64606
  observed
65015
64607
  );
65016
64608
  }
65017
- config2.source = "config+canary";
65018
- config2.canaryObservedAt = latest.observedAt ?? latest.timestamp ?? null;
64609
+ config.source = "config+canary";
64610
+ config.canaryObservedAt = latest.observedAt ?? latest.timestamp ?? null;
65019
64611
  }
65020
64612
  } catch (error) {
65021
64613
  secureLogger.warn("Provider availability canary overlay failed", {
65022
64614
  error: error instanceof Error ? error.message : String(error)
65023
64615
  });
65024
64616
  }
65025
- cachedSnapshot = config2;
64617
+ cachedSnapshot = config;
65026
64618
  }
65027
64619
  function kickRefresh() {
65028
64620
  if (refreshing) return;
@@ -67867,11 +67459,6 @@ export {
67867
67459
  trackServerEvent,
67868
67460
  trackCliCommand,
67869
67461
  trackOAuthFirstMaterialReceipt,
67870
- getRedisClient,
67871
- isRedisAvailable,
67872
- waitForRedisAvailability,
67873
- closeRedisClient,
67874
- isRedisConfigured,
67875
67462
  PROVIDER_CATALOG,
67876
67463
  getProviderRuntimeStatus,
67877
67464
  READ_ENDPOINT_INVOKER,
@@ -67896,6 +67483,11 @@ export {
67896
67483
  HERO_TOOL_NAMES,
67897
67484
  heroTools,
67898
67485
  TASK_TOOLSETS,
67486
+ getRedisClient,
67487
+ isRedisAvailable,
67488
+ waitForRedisAvailability,
67489
+ closeRedisClient,
67490
+ isRedisConfigured,
67899
67491
  OAUTH_SCOPES,
67900
67492
  MCP_BASIC_SCOPES,
67901
67493
  MCP_RESOURCE_SCOPES,