hive-intelligence 1.5.1 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ import {
7
7
  getSupabaseAdmin,
8
8
  resolveEndpoint,
9
9
  secureLogger
10
- } from "./chunk-AGM2CIRL.js";
10
+ } from "./chunk-Y5XA3SFY.js";
11
11
 
12
12
  // src/services/wallet-service.ts
13
13
  async function consumeCredits(args) {
@@ -133,6 +133,7 @@ async function executeToolByName(toolName, args, options) {
133
133
  transport: "rest",
134
134
  requestId: options?.requestId,
135
135
  clients: getSharedClients(),
136
+ analytics: options?.analytics,
136
137
  beforeExecution: options?.beforeExecution
137
138
  });
138
139
  if (result.validationErrors) {
@@ -20827,7 +20827,7 @@ var require_websocket = __commonJS({
20827
20827
  var http = __require("http");
20828
20828
  var net2 = __require("net");
20829
20829
  var tls = __require("tls");
20830
- var { randomBytes: randomBytes4, createHash: createHash8 } = __require("crypto");
20830
+ var { randomBytes: randomBytes4, createHash: createHash9 } = __require("crypto");
20831
20831
  var { Duplex, Readable } = __require("stream");
20832
20832
  var { URL: URL2 } = __require("url");
20833
20833
  var PerMessageDeflate = require_permessage_deflate();
@@ -21495,7 +21495,7 @@ var require_websocket = __commonJS({
21495
21495
  abortHandshake(websocket, socket, "Invalid Upgrade header");
21496
21496
  return;
21497
21497
  }
21498
- const digest2 = createHash8("sha1").update(key + GUID).digest("base64");
21498
+ const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
21499
21499
  if (res.headers["sec-websocket-accept"] !== digest2) {
21500
21500
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
21501
21501
  return;
@@ -21864,7 +21864,7 @@ var require_websocket_server = __commonJS({
21864
21864
  var EventEmitter = __require("events");
21865
21865
  var http = __require("http");
21866
21866
  var { Duplex } = __require("stream");
21867
- var { createHash: createHash8 } = __require("crypto");
21867
+ var { createHash: createHash9 } = __require("crypto");
21868
21868
  var extension = require_extension();
21869
21869
  var PerMessageDeflate = require_permessage_deflate();
21870
21870
  var subprotocol = require_subprotocol();
@@ -22171,7 +22171,7 @@ var require_websocket_server = __commonJS({
22171
22171
  );
22172
22172
  }
22173
22173
  if (this._state > RUNNING) return abortHandshake(socket, 503);
22174
- const digest2 = createHash8("sha1").update(key + GUID).digest("base64");
22174
+ const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
22175
22175
  const headers = [
22176
22176
  "HTTP/1.1 101 Switching Protocols",
22177
22177
  "Upgrade: websocket",
@@ -62904,11 +62904,30 @@ function getCircuitBreaker(serviceName) {
62904
62904
  state: "CLOSED" /* CLOSED */,
62905
62905
  failures: 0,
62906
62906
  lastFailureTime: 0,
62907
+ lastErrorMessage: null,
62907
62908
  serviceName
62908
62909
  });
62909
62910
  }
62910
62911
  return circuitBreakers.get(serviceName);
62911
62912
  }
62913
+ function failureMessage(error) {
62914
+ let message = "";
62915
+ if (error instanceof AxiosError) {
62916
+ const data = error.response?.data;
62917
+ const fromBody = [
62918
+ data?.message,
62919
+ data?.error,
62920
+ data?.status?.error_message
62921
+ ].find((value) => typeof value === "string" && value.trim());
62922
+ message = typeof fromBody === "string" ? fromBody : error.message;
62923
+ } else if (error instanceof Error) {
62924
+ message = error.message;
62925
+ } else if (error) {
62926
+ message = String(error);
62927
+ }
62928
+ const compact = message.replace(/\s+/g, " ").trim();
62929
+ return compact ? compact.slice(0, 240) : null;
62930
+ }
62912
62931
  function isRetryableError(error) {
62913
62932
  if (!error.response) {
62914
62933
  const retryableCodes = [
@@ -63004,7 +63023,7 @@ var ResilientHttpClient = class {
63004
63023
  );
63005
63024
  } else {
63006
63025
  throw new Error(
63007
- `Circuit breaker OPEN for ${this.config.serviceName}. Service has failed ${breaker.failures} consecutive times. Will retry in ${Math.ceil((this.config.circuitBreakerResetTimeout - (now - breaker.lastFailureTime)) / 1e3)}s`
63026
+ `Circuit breaker OPEN for ${this.config.serviceName}. Service has failed ${breaker.failures} consecutive times. Will retry in ${Math.ceil((this.config.circuitBreakerResetTimeout - (now - breaker.lastFailureTime)) / 1e3)}s` + (breaker.lastErrorMessage ? `. Last error: ${breaker.lastErrorMessage}` : "")
63008
63027
  );
63009
63028
  }
63010
63029
  break;
@@ -63034,11 +63053,13 @@ var ResilientHttpClient = class {
63034
63053
  /**
63035
63054
  * Record a failed request (may open circuit breaker)
63036
63055
  */
63037
- recordFailure() {
63056
+ recordFailure(error) {
63038
63057
  if (!this.config.enableCircuitBreaker) return;
63039
63058
  const breaker = this.circuitBreaker;
63040
63059
  breaker.failures++;
63041
63060
  breaker.lastFailureTime = Date.now();
63061
+ const message = failureMessage(error);
63062
+ if (message) breaker.lastErrorMessage = message;
63042
63063
  if (breaker.state === "HALF_OPEN" /* HALF_OPEN */) {
63043
63064
  breaker.state = "OPEN" /* OPEN */;
63044
63065
  secureLogger.warn(
@@ -63068,7 +63089,7 @@ var ResilientHttpClient = class {
63068
63089
  } catch (error) {
63069
63090
  lastError = error;
63070
63091
  if (error instanceof AxiosError && isRetryableError(error)) {
63071
- this.recordFailure();
63092
+ this.recordFailure(error);
63072
63093
  if (attempt < maxRetries) {
63073
63094
  const delay2 = calculateBackoffDelay(
63074
63095
  attempt,
@@ -63091,7 +63112,7 @@ var ResilientHttpClient = class {
63091
63112
  if (error instanceof AxiosError) {
63092
63113
  const status = error.response?.status ?? 0;
63093
63114
  if (!status || status >= 500 || status === 429) {
63094
- this.recordFailure();
63115
+ this.recordFailure(error);
63095
63116
  }
63096
63117
  }
63097
63118
  }
@@ -84857,7 +84878,8 @@ var ERROR_SUGGESTIONS = {
84857
84878
  };
84858
84879
  function createErrorResponse7(code, message, additionalContext) {
84859
84880
  const suggestion = ERROR_SUGGESTIONS[code] || ERROR_SUGGESTIONS.API_ERROR;
84860
- let errorText = `**Error:** ${message}
84881
+ const bareMessage = message.replace(/^(?:\s*\*\*Error:\*\*\s*)+/, "");
84882
+ let errorText = `**Error:** ${bareMessage}
84861
84883
 
84862
84884
  **Code:** ${code}
84863
84885
 
@@ -85678,6 +85700,147 @@ function getAnalyticsWriter() {
85678
85700
  return defaultWriter;
85679
85701
  }
85680
85702
 
85703
+ // src/services/posthog-sink.ts
85704
+ import { createHash as createHash5 } from "crypto";
85705
+ var POSTHOG_DISTINCT_ID_DOMAIN = "hive-posthog-principal-v1";
85706
+ var MAX_QUEUE_SIZE2 = 500;
85707
+ var FLUSH_INTERVAL_MS2 = 5e3;
85708
+ var FLUSH_BATCH_SIZE2 = 50;
85709
+ var DROP_LOG_INTERVAL_MS2 = 6e4;
85710
+ var CAPTURE_TIMEOUT_MS = 1e4;
85711
+ function posthogDistinctId(raw) {
85712
+ return createHash5("sha256").update(`${POSTHOG_DISTINCT_ID_DOMAIN}\0${raw}`).digest("hex");
85713
+ }
85714
+ async function defaultPostBatch(url, body) {
85715
+ const response = await fetch(url, {
85716
+ method: "POST",
85717
+ headers: { "Content-Type": "application/json" },
85718
+ body: JSON.stringify(body),
85719
+ signal: AbortSignal.timeout(CAPTURE_TIMEOUT_MS)
85720
+ });
85721
+ return { ok: response.ok, status: response.status };
85722
+ }
85723
+ function defaultDependencies2() {
85724
+ return {
85725
+ projectToken: () => getEnvVar("POSTHOG_PROJECT_TOKEN"),
85726
+ host: () => getEnvVar("POSTHOG_HOST"),
85727
+ postBatch: defaultPostBatch,
85728
+ maxQueueSize: MAX_QUEUE_SIZE2,
85729
+ flushIntervalMs: FLUSH_INTERVAL_MS2,
85730
+ flushBatchSize: FLUSH_BATCH_SIZE2
85731
+ };
85732
+ }
85733
+ function createPosthogSink(overrides = {}) {
85734
+ const deps = {
85735
+ ...defaultDependencies2(),
85736
+ ...overrides
85737
+ };
85738
+ const queue = [];
85739
+ let dropped = 0;
85740
+ let lastDropLoggedAt = 0;
85741
+ let timer = null;
85742
+ let flushing = null;
85743
+ function ensureTimer() {
85744
+ if (timer) return;
85745
+ timer = setInterval(() => {
85746
+ void flush();
85747
+ }, deps.flushIntervalMs);
85748
+ timer.unref?.();
85749
+ }
85750
+ async function drain() {
85751
+ const token = deps.projectToken();
85752
+ const host = deps.host();
85753
+ if (!token || !host) return;
85754
+ const batch = queue.splice(0, queue.length);
85755
+ if (batch.length === 0) return;
85756
+ try {
85757
+ const { ok, status } = await deps.postBatch(
85758
+ `${host.replace(/\/$/, "")}/batch/`,
85759
+ { api_key: token, batch }
85760
+ );
85761
+ if (!ok) {
85762
+ dropped += batch.length;
85763
+ secureLogger.warn("PostHog batch capture failed", {
85764
+ status,
85765
+ eventCount: batch.length,
85766
+ droppedTotal: dropped
85767
+ });
85768
+ }
85769
+ } catch (error) {
85770
+ dropped += batch.length;
85771
+ secureLogger.warn("PostHog batch capture threw", {
85772
+ eventCount: batch.length,
85773
+ droppedTotal: dropped,
85774
+ errorMessage: error instanceof Error ? error.message : "unknown"
85775
+ });
85776
+ }
85777
+ }
85778
+ function flush() {
85779
+ if (flushing) return flushing;
85780
+ flushing = drain().catch(() => void 0).finally(() => {
85781
+ flushing = null;
85782
+ });
85783
+ return flushing;
85784
+ }
85785
+ return {
85786
+ enqueueToolCall(event) {
85787
+ try {
85788
+ if (!deps.projectToken() || !deps.host()) return false;
85789
+ if (!event.isMaterial || event.isInternal) return false;
85790
+ if (!event.principalRaw || event.authLane === "anonymous") return false;
85791
+ if (queue.length >= deps.maxQueueSize) {
85792
+ dropped += 1;
85793
+ const now = Date.now();
85794
+ if (now - lastDropLoggedAt >= DROP_LOG_INTERVAL_MS2) {
85795
+ lastDropLoggedAt = now;
85796
+ secureLogger.warn(
85797
+ "PostHog queue is full \u2014 mirror events are being dropped",
85798
+ { queueSize: queue.length, droppedTotal: dropped }
85799
+ );
85800
+ }
85801
+ return false;
85802
+ }
85803
+ queue.push({
85804
+ event: "mcp_tool_call",
85805
+ distinct_id: posthogDistinctId(event.principalRaw),
85806
+ timestamp: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
85807
+ properties: {
85808
+ source: "mcp",
85809
+ tool_name: event.toolName,
85810
+ success: event.success,
85811
+ duration_ms: Math.max(0, Math.round(event.durationMs)),
85812
+ transport: event.transport,
85813
+ provider: event.provider ?? null,
85814
+ category: event.category ?? null,
85815
+ auth_lane: event.authLane ?? null,
85816
+ client: event.clientProfile ?? null
85817
+ }
85818
+ });
85819
+ ensureTimer();
85820
+ if (queue.length >= deps.flushBatchSize) void flush();
85821
+ return true;
85822
+ } catch {
85823
+ return false;
85824
+ }
85825
+ },
85826
+ flush,
85827
+ stop() {
85828
+ if (timer) {
85829
+ clearInterval(timer);
85830
+ timer = null;
85831
+ }
85832
+ },
85833
+ getStats() {
85834
+ return { queued: queue.length, dropped };
85835
+ }
85836
+ };
85837
+ }
85838
+ var defaultSink = null;
85839
+ function getPosthogSink() {
85840
+ if (!defaultSink) defaultSink = createPosthogSink();
85841
+ return defaultSink;
85842
+ }
85843
+
85681
85844
  // src/services/client-profile.ts
85682
85845
  var MCP_REMOTE_PATTERN = /^(.*?) \(via mcp-remote ([\d.]+)\)$/;
85683
85846
  var MAX_NAME_LENGTH = 256;
@@ -86081,6 +86244,22 @@ function logToolCall(endpoint, context, hive, success, durationMs, args, extra =
86081
86244
  });
86082
86245
  } catch {
86083
86246
  }
86247
+ try {
86248
+ getPosthogSink().enqueueToolCall({
86249
+ toolName: endpoint.tool.name,
86250
+ success,
86251
+ durationMs,
86252
+ transport: context.transport,
86253
+ provider: getProviderNameForTool(endpoint),
86254
+ category: getCategoryNameForTool(endpoint.tool.name),
86255
+ principalRaw: context.analytics?.principalRaw ?? null,
86256
+ authLane: context.analytics?.authLane ?? null,
86257
+ clientProfile: clientProfileFromName(context.analytics?.clientName),
86258
+ isMaterial: getMcpCreditCost(endpoint.tool.name) > 0,
86259
+ isInternal: context.analytics?.isInternal === true || context.transport === "health"
86260
+ });
86261
+ } catch {
86262
+ }
86084
86263
  }
86085
86264
  function validationErrorResult(endpoint, validationErrors, durationMs, args) {
86086
86265
  const errorCopy = agentErrorCopy("invalid_input", {
@@ -86502,6 +86681,14 @@ function isSolanaChain(chain, address) {
86502
86681
  if (chain) return SOLANA_CHAIN_NAMES.has(normalizeChain(chain));
86503
86682
  return !address.trim().toLowerCase().startsWith("0x");
86504
86683
  }
86684
+ function looksLikeNameService(address) {
86685
+ return /\.[a-z]{2,}$/i.test(address.trim());
86686
+ }
86687
+ function nameServiceError(address) {
86688
+ return errorResult3(
86689
+ `"${address}" looks like an ENS or name-service name, which isn't supported yet. Pass a 0x address (EVM) or a base58 address (Solana).`
86690
+ );
86691
+ }
86505
86692
  function errorResult3(message) {
86506
86693
  return {
86507
86694
  content: [{ type: "text", text: JSON.stringify({ error: message }) }],
@@ -86592,7 +86779,12 @@ function heroTools(endpoints, options = {}) {
86592
86779
  change_24h_percent: value[`${vsCurrency}_24h_change`] ?? null
86593
86780
  };
86594
86781
  }
86595
- return { token: query, vs_currency: vsCurrency, ...payload };
86782
+ const tokenExists = Object.keys(payload).some((key) => key !== "_hive");
86783
+ return {
86784
+ token: query,
86785
+ vs_currency: vsCurrency,
86786
+ note: tokenExists ? `No ${vsCurrency} price available for "${query}". The quote currency may be unsupported; try vs_currency "usd".` : `No price found for "${query}". Verify the CoinGecko id or symbol, or pass chain + address for a contract token.`
86787
+ };
86596
86788
  };
86597
86789
  const trimOnchainPrice = (address) => (payload) => {
86598
86790
  const data = payload.data;
@@ -86608,7 +86800,10 @@ function heroTools(endpoints, options = {}) {
86608
86800
  };
86609
86801
  }
86610
86802
  }
86611
- return { address, ...payload };
86803
+ return {
86804
+ address,
86805
+ note: `No onchain price found for ${address} on this network. Verify the contract address and chain.`
86806
+ };
86612
86807
  };
86613
86808
  const getTokenPrice = {
86614
86809
  metadata: {
@@ -86635,6 +86830,7 @@ function heroTools(endpoints, options = {}) {
86635
86830
  const vsCurrency = (parsed.data.vs_currency ?? "usd").toLowerCase();
86636
86831
  const format = parsed.data.response_format ?? "concise";
86637
86832
  if (address) {
86833
+ if (looksLikeNameService(address)) return nameServiceError(address);
86638
86834
  const network = GECKO_NETWORKS[normalizeChain(chain)] ?? normalizeChain(chain);
86639
86835
  const result3 = await executeUnderlying("get_onchain_token_price", {
86640
86836
  network,
@@ -86734,6 +86930,7 @@ function heroTools(endpoints, options = {}) {
86734
86930
  }
86735
86931
  const { address, chain } = parsed.data;
86736
86932
  const format = parsed.data.response_format ?? "concise";
86933
+ if (looksLikeNameService(address)) return nameServiceError(address);
86737
86934
  if (isSolanaChain(chain, address)) {
86738
86935
  const result3 = await executeUnderlying("get_solana_token_security", {
86739
86936
  contract_address: address
@@ -86882,6 +87079,7 @@ function heroTools(endpoints, options = {}) {
86882
87079
  }
86883
87080
  const { address, chain } = parsed.data;
86884
87081
  const format = parsed.data.response_format ?? "concise";
87082
+ if (looksLikeNameService(address)) return nameServiceError(address);
86885
87083
  if (isSolanaChain(chain, address)) {
86886
87084
  const result3 = await executeUnderlying("helius_get_wallet_balances", {
86887
87085
  wallet: address
@@ -91138,7 +91336,7 @@ async function runMcpProtocolHealth(options = {}) {
91138
91336
  }
91139
91337
 
91140
91338
  // src/health/oauthLifecycle.ts
91141
- import { createHash as createHash6, randomBytes as randomBytes3 } from "crypto";
91339
+ import { createHash as createHash7, randomBytes as randomBytes3 } from "crypto";
91142
91340
 
91143
91341
  // src/auth/oauth/provider.ts
91144
91342
  import { randomBytes as randomBytes2 } from "crypto";
@@ -91514,10 +91712,10 @@ function isHiveOAuthAccessToken(token) {
91514
91712
  }
91515
91713
 
91516
91714
  // src/auth/oauth/store.ts
91517
- import { createHash as createHash5 } from "crypto";
91715
+ import { createHash as createHash6 } from "crypto";
91518
91716
  var REVOKED_FAMILY_TTL_SECONDS = 7776e3;
91519
91717
  function digest(value) {
91520
- return createHash5("sha256").update(value).digest("hex");
91718
+ return createHash6("sha256").update(value).digest("hex");
91521
91719
  }
91522
91720
  function parseJson(raw) {
91523
91721
  if (!raw) return void 0;
@@ -91969,7 +92167,7 @@ async function operationRejects(operation) {
91969
92167
  }
91970
92168
  async function issueCanaryFamily(args) {
91971
92169
  const verifier = randomBytes3(48).toString("base64url");
91972
- const challenge = createHash6("sha256").update(verifier).digest("base64url");
92170
+ const challenge = createHash7("sha256").update(verifier).digest("base64url");
91973
92171
  let consentLocation;
91974
92172
  const response = {
91975
92173
  redirect(status, location) {
@@ -92281,7 +92479,7 @@ async function runOAuthLifecycleHealth(overrides = {}) {
92281
92479
  import Coingecko2 from "@coingecko/coingecko-typescript";
92282
92480
 
92283
92481
  // src/tools/goplus/goplusClient.ts
92284
- import { createHash as createHash7 } from "crypto";
92482
+ import { createHash as createHash8 } from "crypto";
92285
92483
  function parsePositiveInteger(value, fallback) {
92286
92484
  const parsed = Number.parseInt(value || "", 10);
92287
92485
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
@@ -92375,7 +92573,7 @@ var GoPlusClient = class {
92375
92573
  const time = Math.floor(Date.now() / 1e3);
92376
92574
  const timeStr = time.toString();
92377
92575
  const signInput = this.appKey + timeStr + this.appSecret;
92378
- const sign = createHash7("sha1").update(signInput).digest("hex");
92576
+ const sign = createHash8("sha1").update(signInput).digest("hex");
92379
92577
  secureLogger.info("GoPlus: requesting access token", {
92380
92578
  appKeyLength: this.appKey.length,
92381
92579
  appSecretLength: this.appSecret.length,
@@ -97380,8 +97578,9 @@ var PROVIDER_AVAILABILITY_TTL_MS = 6e4;
97380
97578
  var AVAILABILITY_SEVERITY = {
97381
97579
  ok: 0,
97382
97580
  degraded: 1,
97383
- missing_key: 2,
97384
- failing: 3
97581
+ plan_required: 2,
97582
+ missing_key: 3,
97583
+ failing: 4
97385
97584
  };
97386
97585
  function availabilityFromRuntimeStatus(status) {
97387
97586
  switch (status) {
@@ -97392,7 +97591,11 @@ function availabilityFromRuntimeStatus(status) {
97392
97591
  return "ok";
97393
97592
  case "missing_key":
97394
97593
  return "missing_key";
97594
+ // A lapsed or exhausted upstream plan fails deterministically until the
97595
+ // account changes, unlike a transient rate limit or wobble, so it demotes
97596
+ // like a missing key instead of staying ranked as merely degraded.
97395
97597
  case "plan_required":
97598
+ return "plan_required";
97396
97599
  case "rate_limited":
97397
97600
  case "degraded":
97398
97601
  return "degraded";
@@ -97401,7 +97604,7 @@ function availabilityFromRuntimeStatus(status) {
97401
97604
  }
97402
97605
  }
97403
97606
  function isUnavailable(availability) {
97404
- return availability === "missing_key" || availability === "failing";
97607
+ return availability === "missing_key" || availability === "plan_required" || availability === "failing";
97405
97608
  }
97406
97609
  function worseOf(left, right) {
97407
97610
  return AVAILABILITY_SEVERITY[right] > AVAILABILITY_SEVERITY[left] ? right : left;
@@ -98165,7 +98368,8 @@ function singularizeToken(token) {
98165
98368
  return token;
98166
98369
  }
98167
98370
  function parseSearchTokens(query) {
98168
- return query.toLowerCase().replace(/0x[a-f0-9]{20,}/g, " ").replace(/[1-9A-HJ-NP-Za-km-z]{32,}/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[\?¿!¡"'`()\[\]{}:;|/\\]+/g, " ").replace(/[-_]+/g, " ").split(/[\s,]+/).map(normalizeSearchToken).filter((token) => token.length > 1).filter((token) => !SEARCH_STOPWORDS.has(token)).map(singularizeToken);
98371
+ const tokens = query.toLowerCase().replace(/0x[a-f0-9]{20,}/g, " ").replace(/[1-9A-HJ-NP-Za-km-z]{32,}/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[\?¿!¡"'`()\[\]{}:;|/\\]+/g, " ").replace(/[-_]+/g, " ").split(/[\s,]+/).map(normalizeSearchToken).filter((token) => token.length > 1).filter((token) => !SEARCH_STOPWORDS.has(token)).map(singularizeToken);
98372
+ return [...new Set(tokens)];
98169
98373
  }
98170
98374
  function searchTokenVariants(token) {
98171
98375
  const normalized = singularizeToken(normalizeSearchToken(token));
@@ -98202,9 +98406,12 @@ function queryMatchScore(entry, query) {
98202
98406
  entry.provider,
98203
98407
  entry.summary
98204
98408
  ].join(" ").toLowerCase();
98409
+ const nameTitleTokenSet = new Set(parseSearchTokens(nameTitleText));
98410
+ const coreTextTokenSet = new Set(parseSearchTokens(coreText));
98205
98411
  const score = tokens.reduce((total, token) => {
98206
- if (exactTextMatchesSearchToken(nameTitleText, token)) return total + 24;
98207
- if (exactTextMatchesSearchToken(coreText, token)) return total + 14;
98412
+ const exactToken = singularizeToken(normalizeSearchToken(token));
98413
+ if (nameTitleTokenSet.has(exactToken)) return total + 24;
98414
+ if (coreTextTokenSet.has(exactToken)) return total + 14;
98208
98415
  if (textMatchesSearchToken(nameTitleText, token)) return total + 12;
98209
98416
  if (textMatchesSearchToken(entry.summary, token)) return total + 6;
98210
98417
  if (textMatchesSearchToken(coreText, token)) return total + 4;
@@ -98446,13 +98653,13 @@ function dynamicTools(endpoints, options = {}) {
98446
98653
  (toolset) => toolsetCatalogEntry(toolset, providerByToolName)
98447
98654
  );
98448
98655
  const searchToolsSchema = z17.object({
98449
- query: z17.string().optional().describe(
98656
+ query: z17.string().max(512).optional().describe(
98450
98657
  "Search text matched against tool name, title, category, provider, and summary."
98451
98658
  ),
98452
- provider: z17.string().optional().describe(
98659
+ provider: z17.string().max(128).optional().describe(
98453
98660
  "Optional provider filter such as CoinGecko, Moralis, Tenderly, Helius, GoPlus, CCXT, Codex, Alchemy, DeFiLlama, Hyperliquid, or Open Data Fetch."
98454
98661
  ),
98455
- category: z17.string().optional().describe("Optional category filter, for example Portfolio & Wallet."),
98662
+ category: z17.string().max(128).optional().describe("Optional category filter, for example Portfolio & Wallet."),
98456
98663
  limit: z17.number().int().min(1).max(MAX_SEARCH_LIMIT).optional().describe(`Maximum tools to return. Default ${DEFAULT_SEARCH_LIMIT}.`),
98457
98664
  cursor: z17.string().optional().describe("Pagination cursor from the previous response."),
98458
98665
  toolset_id: z17.string().max(100).optional().describe(
@@ -99352,7 +99559,7 @@ function buildServerInstructions(scope) {
99352
99559
  `Hive serves live crypto market data to AI agents over a compact ${ROOT_META_TOOL_COUNT}-tool root. Loop: search_tools -> get_api_endpoint_schema -> ${READ_ENDPOINT_INVOKER} for reads (${STATEFUL_WRITE_ENDPOINT_INVOKER} only after explicit user approval; validate_task_result before structured answers). Every material response carries a _hive receipt (provider, fetched_at, runtime_status, _hive.receipt_id); cite it when answering.`,
99353
99560
  `For the three dominant intents call the hero tools directly: get_token_price, check_token_safety, get_wallet_portfolio (response_format "concise" default, "detailed" available).`,
99354
99561
  `Degraded providers are reported, not hidden: search_tools marks each tool's availability, and unavailable tools return runtime_status with cause and next_action instead of data. Follow next_action; never retry an unchanged failing call in a loop.`,
99355
- `Discovery is free and cheap: resources hive://toolsets, hive://providers, hive://tools; the ${UNDERLYING_TOOL_COUNT}-tool catalog stays reachable through search_tools or scoped category endpoints. Use limit/page/per_page to keep responses small; a material execution costs 1 credit on the hosted service.`
99562
+ `Discovery is free and cheap: resources hive://toolsets, hive://providers, hive://tools; the ${UNDERLYING_TOOL_COUNT}-tool catalog stays reachable through search_tools or scoped category endpoints. Use limit and cursor on search_tools, and limit/page/per_page/offset on data endpoints, to keep responses small; a material execution costs 1 credit on the hosted service.`
99356
99563
  ].join(" ");
99357
99564
  }
99358
99565
  function compactCanaryRun(run) {
@@ -99696,7 +99903,11 @@ var HiveMCPServer = class {
99696
99903
  }
99697
99904
  }
99698
99905
  getProviderStatusCatalog() {
99699
- return getProviderStatusCatalog();
99906
+ const snapshot = getProviderAvailabilitySnapshot();
99907
+ return getProviderStatusCatalog().map((provider) => {
99908
+ const observed = snapshot.byProviderName[provider.name];
99909
+ return provider.status === "ok" && observed && observed !== "ok" ? { ...provider, status: observed } : provider;
99910
+ });
99700
99911
  }
99701
99912
  setupHandlers() {
99702
99913
  this.server.server.oninitialized = () => {
@@ -99807,6 +100018,8 @@ var HiveMCPServer = class {
99807
100018
  note: `Root /mcp exposes ${ROOT_META_TOOL_COUNT} meta-tools optimized for LLM agents. Use category endpoints (/hive_*/mcp) only for specialized integrations requiring direct tool access.`,
99808
100019
  runtimeStatuses: TASK_TOOLSET_RUNTIME_STATUSES,
99809
100020
  runtimeStatusSemantics: RUNTIME_STATUS_SEMANTICS,
100021
+ availability_source: getProviderAvailabilitySnapshot().source,
100022
+ canary_observed_at: getProviderAvailabilitySnapshot().canaryObservedAt,
99810
100023
  providers
99811
100024
  },
99812
100025
  null,
package/build/cli.js CHANGED
@@ -3440,7 +3440,7 @@ program2.hook("preAction", (thisCommand) => {
3440
3440
  setCliFlags({ apiKey: opts.apiKey, noRetry: opts.retry === false });
3441
3441
  });
3442
3442
  program2.action(async () => {
3443
- const { startStdio } = await import("./serve-PWMT5IRU.js");
3443
+ const { startStdio } = await import("./serve-NCMFZSMB.js");
3444
3444
  await startStdio(program2.opts().envFile);
3445
3445
  });
3446
3446
  program2.command("serve").description("Start the MCP server").option("--http", "Start HTTP server instead of stdio").option("--port <number>", "HTTP server port", "8080").action(async (opts) => {
@@ -3453,10 +3453,10 @@ program2.command("serve").description("Start the MCP server").option("--http", "
3453
3453
  );
3454
3454
  process.exit(ExitCode.INVALID_ARGS);
3455
3455
  }
3456
- const { startHttp } = await import("./serve-PWMT5IRU.js");
3456
+ const { startHttp } = await import("./serve-NCMFZSMB.js");
3457
3457
  await startHttp(port, program2.opts().envFile);
3458
3458
  } else {
3459
- const { startStdio } = await import("./serve-PWMT5IRU.js");
3459
+ const { startStdio } = await import("./serve-NCMFZSMB.js");
3460
3460
  await startStdio(program2.opts().envFile);
3461
3461
  }
3462
3462
  });
@@ -3666,7 +3666,7 @@ program2.command("uninstall").description(
3666
3666
  if (exitCode !== 0) process.exit(exitCode);
3667
3667
  });
3668
3668
  program2.command("doctor").description("Diagnose environment and server connectivity").option("--probe", "Run live API probes (slower)").action(async (opts) => {
3669
- const { runDoctor } = await import("./doctor-XG5IQCXK.js");
3669
+ const { runDoctor } = await import("./doctor-VRZYKQGL.js");
3670
3670
  await runDoctor(opts);
3671
3671
  });
3672
3672
  program2.command("upgrade").description("Update Hive to the latest published version").action(async () => {
@@ -3714,7 +3714,7 @@ program2.command("usage").description("Show your API usage and plan limits").act
3714
3714
  await runUsage();
3715
3715
  });
3716
3716
  program2.command("status").description("Quick health and version check").action(async () => {
3717
- const { runStatus } = await import("./doctor-XG5IQCXK.js");
3717
+ const { runStatus } = await import("./doctor-VRZYKQGL.js");
3718
3718
  await runStatus();
3719
3719
  });
3720
3720
  program2.command("open [target]").description("Open Hive dashboard, docs, status, or GitHub in browser").action(async (target) => {
@@ -204,7 +204,7 @@ ${fails === 0 ? "All checks passed" : `${fails} issues found`}${warns ? ` (${war
204
204
  if (fails > 0) process.exit(1);
205
205
  }
206
206
  async function runStatus() {
207
- const { SERVER_VERSION } = await import("./mcpServer-XHIN5JER.js");
207
+ const { SERVER_VERSION } = await import("./mcpServer-DARSGHUH.js");
208
208
  const { resolveApiKey, resolveApiUrl } = await import("./config-dir-5IH7MOOT.js");
209
209
  const { getActiveProfile, maskKey } = await import("./auth-Y4GXW376.js");
210
210
  const apiUrl = resolveApiUrl();
@@ -9,7 +9,7 @@ import {
9
9
  getToolsForScope,
10
10
  memoizedJsonSchemaToZodInputSchema,
11
11
  memoizedJsonSchemaToZodOutputSchema
12
- } from "./chunk-AGM2CIRL.js";
12
+ } from "./chunk-Y5XA3SFY.js";
13
13
  import "./chunk-L326MQZP.js";
14
14
  import "./chunk-EPF36Q3Z.js";
15
15
  import {
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module'; const require = createRequire(impor
2
2
  import {
3
3
  consumeCredits,
4
4
  executeToolByName
5
- } from "./chunk-XQPEFCSY.js";
5
+ } from "./chunk-VZBDTSWA.js";
6
6
  import {
7
7
  HyperliquidAPI,
8
8
  MIN_MONITOR_CADENCE_MS,
@@ -15,7 +15,7 @@ import {
15
15
  monitorCadenceIntervalMs,
16
16
  runScheduledHealthCanaries,
17
17
  secureLogger
18
- } from "./chunk-AGM2CIRL.js";
18
+ } from "./chunk-Y5XA3SFY.js";
19
19
  import "./chunk-L326MQZP.js";
20
20
  import "./chunk-EPF36Q3Z.js";
21
21
  import "./chunk-ZXKFJQDE.js";
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "package": "hive-intelligence",
3
- "version": "1.5.1",
4
- "buildSha": "ab8276f834ef8b08bda9d320387e4390e9ab55b6",
5
- "imageDigest": "sha256:9ef23428cc9d7da797e21152f4823f021ee8f0d3f3db94cf28410c8e1a72a124",
3
+ "version": "1.5.3",
4
+ "buildSha": "0adb32f0c05315fa9381d143b9f2d0e89514ce63",
5
+ "imageDigest": "sha256:4ab4777877e1be050153bca1c1be9d72b5a7fe7d68e5439d7aabcccaa63c9806",
6
6
  "deployedUrl": "https://mcp.hiveintelligence.xyz",
7
- "manifest": "https://raw.githubusercontent.com/hive-intel/hive-sdk/v1.5.1/releases/v1.5.1.json"
7
+ "manifest": "https://raw.githubusercontent.com/hive-intel/hive-sdk/v1.5.3/releases/v1.5.3.json"
8
8
  }
@@ -7,7 +7,7 @@ async function startStdio(envFile) {
7
7
  dotenv.config({ path: envFile || ".env", quiet: true });
8
8
  console.log = (...args) => console.error("[LOG]", ...args);
9
9
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
10
- const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-XHIN5JER.js");
10
+ const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-DARSGHUH.js");
11
11
  const { getPendingUpdateVersion } = await import("./update-check-IEXPOYYR.js");
12
12
  const transport = new StdioServerTransport();
13
13
  const pendingUpdate = getPendingUpdateVersion();
package/build/server.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  ensureWallet,
7
7
  executeToolByName,
8
8
  getWalletStatus
9
- } from "./chunk-XQPEFCSY.js";
9
+ } from "./chunk-VZBDTSWA.js";
10
10
  import {
11
11
  CategoryEndpoints,
12
12
  HERO_TOOL_NAMES,
@@ -95,7 +95,7 @@ import {
95
95
  validateEndpointArgs,
96
96
  verifyApiKey,
97
97
  waitForRedisAvailability
98
- } from "./chunk-AGM2CIRL.js";
98
+ } from "./chunk-Y5XA3SFY.js";
99
99
  import {
100
100
  HIVE_AGENT_SKILLS
101
101
  } from "./chunk-L326MQZP.js";
@@ -8202,6 +8202,13 @@ app.post(
8202
8202
  authReq.hiveSubjectContext,
8203
8203
  () => executeToolByName(executionToolName, endpointArgs, {
8204
8204
  requestId: req.requestId,
8205
+ // Same identity context the hero branch passes — without it every
8206
+ // non-hero keyed REST call wrote a NULL-principal analytics row.
8207
+ analytics: {
8208
+ principalRaw: authReq.userId,
8209
+ authLane: "api_key",
8210
+ isInternal: isMonitorSecretRequest(req)
8211
+ },
8205
8212
  beforeExecution: keyedBeforeExecution
8206
8213
  })
8207
8214
  );
package/build/stdio.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  createHiveMcpServer,
8
8
  secureLogger
9
- } from "./chunk-AGM2CIRL.js";
9
+ } from "./chunk-Y5XA3SFY.js";
10
10
  import "./chunk-L326MQZP.js";
11
11
  import "./chunk-EPF36Q3Z.js";
12
12
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hive-intelligence",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "Evidence-backed crypto due diligence for AI agents, with sources, freshness, and a runtime receipt on every call.",
5
5
  "mcpName": "xyz.hiveintelligence/mcp",
6
6
  "type": "module",
@@ -169,10 +169,10 @@
169
169
  "express-rate-limit": "8.5.2"
170
170
  },
171
171
  "esbuild": "0.28.1",
172
- "fast-uri": "3.1.5",
172
+ "fast-uri": "3.1.7",
173
173
  "hono": "4.12.34",
174
174
  "ip-address": "10.5.0",
175
- "qs": "6.15.3"
175
+ "qs": "6.16.0"
176
176
  },
177
177
  "devDependencies": {
178
178
  "@types/cors": "^2.8.19",