{"version":3,"file":"capabilities-GuF58uDa.mjs","names":[],"sources":["../src/mcp/capabilities.ts"],"sourcesContent":["import type { InvestigatorConfig } from '../config/schema.js'\nimport { applyMcpAuthHeaders, resolveGraphMcpEndpoint } from './client.js'\n\nexport interface NetworkTopologyLayer {\n  enabled: boolean\n  coverage?: {\n    from_block?: number\n    to_block?: number\n    from_timestamp?: string\n    to_timestamp?: string\n    chain_tip_block?: number\n    blocks_behind_tip?: number\n  }\n}\n\nexport interface NetworkLayerCapability {\n  enabled: boolean\n  live?: NetworkTopologyLayer\n  archive?: NetworkTopologyLayer\n}\n\nexport interface NetworkCapability {\n  network: string\n  display_name?: string\n  status: string\n  default?: boolean\n  layers: Record<string, NetworkLayerCapability>\n  tools: Record<string, string>\n  coverage?: {\n    from_block?: number\n    to_block?: number\n    from_timestamp?: string\n    to_timestamp?: string\n    chain_tip_block?: number\n    blocks_behind_tip?: number\n  }\n  freshness?: {\n    last_processed_at?: string\n    last_successful_sync_at?: string\n    max_data_age_seconds?: number\n    last_processing_duration_seconds?: number\n  }\n}\n\nexport interface NetworkCapabilitiesDocument {\n  schema: 'chain-insights.network-capabilities.v1'\n  networks: NetworkCapability[]\n}\n\nconst BITTENSOR_SEMANTIC_NETWORKS = new Set(['bittensor', 'bittensor_evm', 'bittensor_semantic'])\nconst PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS = {\n  aml_address_risk: 'available',\n  aml_trace_victim_funds: 'available',\n  aml_trace_deposit_sources: 'available',\n  aml_trace_suspect_funds: 'available',\n  graph_query: 'available',\n  graph_query_batch: 'available',\n  meta_network_capabilities: 'available',\n  meta_usage_status: 'available',\n  wallet_balance: 'available',\n} as const\nconst AVAILABLE_TOOLS_PER_LINE = 3\n\nfunction publicNetworkCapabilities(document: NetworkCapabilitiesDocument): NetworkCapabilitiesDocument {\n  const source = document.networks.find((network) => BITTENSOR_SEMANTIC_NETWORKS.has(network.network))\n  return {\n    schema: 'chain-insights.network-capabilities.v1',\n    networks: source\n      ? [{\n        network: 'bittensor',\n        display_name: 'Bittensor',\n        status: source.status || 'live',\n        default: source.default !== false,\n        layers: {\n          facts: { enabled: source.layers.facts?.enabled === true },\n          risk: { enabled: source.layers.risk?.enabled === true },\n          topology: {\n            enabled: source.layers.topology?.enabled === true,\n            ...(source.layers.topology?.live ? { live: source.layers.topology.live } : {}),\n            ...(source.layers.topology?.archive ? { archive: source.layers.topology.archive } : {}),\n          },\n        },\n        ...(source.coverage ? { coverage: source.coverage } : {}),\n        ...(source.freshness ? { freshness: source.freshness } : {}),\n        tools: PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,\n      }]\n      : [],\n  }\n}\n\nfunction metadataNetworksUrl(endpoint: string): URL {\n  const url = new URL(endpoint)\n  url.pathname = '/metadata/networks'\n  url.search = ''\n  url.hash = ''\n  return url\n}\n\nexport async function fetchNetworkCapabilities(\n  config: Pick<InvestigatorConfig, 'graphMcpAuthToken' | 'graphMcpMode' | 'graphMcpEndpoint'>,\n): Promise<NetworkCapabilitiesDocument> {\n  const endpoint = resolveGraphMcpEndpoint(config)\n  const request = metadataNetworksUrl(endpoint)\n  const headers = new Headers()\n  const token = config.graphMcpAuthToken?.trim()\n  if (token) {\n    applyMcpAuthHeaders(headers, token)\n  }\n  let response: Response\n  try {\n    response = await fetch(request, { headers })\n  } catch (err) {\n    throw new Error(`network capabilities unavailable at ${request}: ${(err as Error).message}`)\n  }\n  if (!response.ok) {\n    throw new Error(`network capabilities unavailable at ${request}: HTTP ${response.status}`)\n  }\n  const parsed = await response.json() as NetworkCapabilitiesDocument\n  if (parsed.schema !== 'chain-insights.network-capabilities.v1' || !Array.isArray(parsed.networks)) {\n    throw new Error('network capabilities response has unsupported schema')\n  }\n  return publicNetworkCapabilities(parsed)\n}\n\nfunction layerValue(network: NetworkCapability, layer: string): string {\n  const capability = network.layers[layer]\n  if (!capability?.enabled) return 'no'\n  return 'yes'\n}\n\nfunction availableTools(network: NetworkCapability): string[] {\n  const effectiveTools = BITTENSOR_SEMANTIC_NETWORKS.has(network.network) && network.layers.topology?.enabled === true\n    ? {\n      ...(network.tools ?? {}),\n      ...PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,\n    }\n    : network.tools ?? {}\n  const tools = Object.entries(effectiveTools)\n    .filter(([, status]) => status === 'available')\n    .map(([name]) => name)\n  return tools.sort()\n}\n\nfunction availableToolLines(network: NetworkCapability): string[] {\n  const tools = availableTools(network)\n  if (tools.length === 0) return ['none']\n  const lines: string[] = []\n  for (let index = 0; index < tools.length; index += AVAILABLE_TOOLS_PER_LINE) {\n    lines.push(tools.slice(index, index + AVAILABLE_TOOLS_PER_LINE).join(', '))\n  }\n  return lines\n}\n\nfunction shortDate(value?: string): string {\n  if (!value) return ''\n  return value.slice(0, 10)\n}\n\nfunction datasetLabel(network: NetworkCapability): string {\n  const coverage = network.coverage\n  if (!coverage) return 'unknown'\n  const blockRange = coverage.from_block !== undefined && coverage.to_block !== undefined\n    ? `${coverage.from_block}..${coverage.to_block}`\n    : 'blocks unknown'\n  const dateRange = coverage.from_timestamp && coverage.to_timestamp\n    ? `${shortDate(coverage.from_timestamp)}..${shortDate(coverage.to_timestamp)}`\n    : ''\n  if (blockRange === 'blocks unknown' && dateRange === '') return 'unknown'\n  if (blockRange === 'blocks unknown') return dateRange\n  if (dateRange === '') return blockRange\n  return `${blockRange} / ${dateRange}`\n}\n\nexport function formatNetworkCapabilities(document: NetworkCapabilitiesDocument): string {\n  if (document.networks.length === 0) return 'No supported networks advertised.'\n  const headers = ['Network', 'Topology', 'Facts', 'Risk', 'Dataset', 'Available tools']\n  const widths = [14, 10, 8, 8, 38, 64]\n  const row = (values: string[]) => values.map((value, index) => value.padEnd(widths[index]!)).join('  ')\n  const networkRows = document.networks.flatMap((network) => {\n    const toolLines = availableToolLines(network)\n    return toolLines.map((toolLine, index) => row([\n      index === 0 ? network.display_name || network.network : '',\n      index === 0 ? layerValue(network, 'topology') : '',\n      index === 0 ? layerValue(network, 'facts') : '',\n      index === 0 ? layerValue(network, 'risk') : '',\n      index === 0 ? datasetLabel(network) : '',\n      toolLine,\n    ]))\n  })\n  return [\n    row(headers),\n    widths.map((width) => '-'.repeat(width)).join('  '),\n    ...networkRows,\n  ].join('\\n')\n}\n"],"mappings":";;AAiDA,MAAM,8CAA8B,IAAI,IAAI;CAAC;CAAa;CAAiB;AAAoB,CAAC;AAChG,MAAM,oCAAoC;CACxC,kBAAkB;CAClB,wBAAwB;CACxB,2BAA2B;CAC3B,yBAAyB;CACzB,aAAa;CACb,mBAAmB;CACnB,2BAA2B;CAC3B,mBAAmB;CACnB,gBAAgB;AAClB;AACA,MAAM,2BAA2B;AAEjC,SAAS,0BAA0B,UAAoE;CACrG,MAAM,SAAS,SAAS,SAAS,MAAM,YAAY,4BAA4B,IAAI,QAAQ,OAAO,CAAC;CACnG,OAAO;EACL,QAAQ;EACR,UAAU,SACN,CAAC;GACD,SAAS;GACT,cAAc;GACd,QAAQ,OAAO,UAAU;GACzB,SAAS,OAAO,YAAY;GAC5B,QAAQ;IACN,OAAO,EAAE,SAAS,OAAO,OAAO,OAAO,YAAY,KAAK;IACxD,MAAM,EAAE,SAAS,OAAO,OAAO,MAAM,YAAY,KAAK;IACtD,UAAU;KACR,SAAS,OAAO,OAAO,UAAU,YAAY;KAC7C,GAAI,OAAO,OAAO,UAAU,OAAO,EAAE,MAAM,OAAO,OAAO,SAAS,KAAK,IAAI,CAAC;KAC5E,GAAI,OAAO,OAAO,UAAU,UAAU,EAAE,SAAS,OAAO,OAAO,SAAS,QAAQ,IAAI,CAAC;IACvF;GACF;GACA,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;GACvD,GAAI,OAAO,YAAY,EAAE,WAAW,OAAO,UAAU,IAAI,CAAC;GAC1D,OAAO;EACT,CAAC,IACC,CAAC;CACP;AACF;AAEA,SAAS,oBAAoB,UAAuB;CAClD,MAAM,MAAM,IAAI,IAAI,QAAQ;CAC5B,IAAI,WAAW;CACf,IAAI,SAAS;CACb,IAAI,OAAO;CACX,OAAO;AACT;AAEA,eAAsB,yBACpB,QACsC;CAEtC,MAAM,UAAU,oBADC,wBAAwB,MACE,CAAC;CAC5C,MAAM,UAAU,IAAI,QAAQ;CAC5B,MAAM,QAAQ,OAAO,mBAAmB,KAAK;CAC7C,IAAI,OACF,oBAAoB,SAAS,KAAK;CAEpC,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,MAAM,SAAS,EAAE,QAAQ,CAAC;CAC7C,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,uCAAuC,QAAQ,IAAK,IAAc,SAAS;CAC7F;CACA,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,QAAQ,SAAS,SAAS,QAAQ;CAE3F,MAAM,SAAS,MAAM,SAAS,KAAK;CACnC,IAAI,OAAO,WAAW,4CAA4C,CAAC,MAAM,QAAQ,OAAO,QAAQ,GAC9F,MAAM,IAAI,MAAM,sDAAsD;CAExE,OAAO,0BAA0B,MAAM;AACzC;AAEA,SAAS,WAAW,SAA4B,OAAuB;CAErE,IAAI,CADe,QAAQ,OAAO,MACnB,EAAE,SAAS,OAAO;CACjC,OAAO;AACT;AAEA,SAAS,eAAe,SAAsC;CAC5D,MAAM,iBAAiB,4BAA4B,IAAI,QAAQ,OAAO,KAAK,QAAQ,OAAO,UAAU,YAAY,OAC5G;EACA,GAAI,QAAQ,SAAS,CAAC;EACtB,GAAG;CACL,IACE,QAAQ,SAAS,CAAC;CAItB,OAHc,OAAO,QAAQ,cAAc,CAAC,CACzC,QAAQ,GAAG,YAAY,WAAW,WAAW,CAAC,CAC9C,KAAK,CAAC,UAAU,IACR,CAAC,CAAC,KAAK;AACpB;AAEA,SAAS,mBAAmB,SAAsC;CAChE,MAAM,QAAQ,eAAe,OAAO;CACpC,IAAI,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM;CACtC,MAAM,QAAkB,CAAC;CACzB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,0BACjD,MAAM,KAAK,MAAM,MAAM,OAAO,QAAQ,wBAAwB,CAAC,CAAC,KAAK,IAAI,CAAC;CAE5E,OAAO;AACT;AAEA,SAAS,UAAU,OAAwB;CACzC,IAAI,CAAC,OAAO,OAAO;CACnB,OAAO,MAAM,MAAM,GAAG,EAAE;AAC1B;AAEA,SAAS,aAAa,SAAoC;CACxD,MAAM,WAAW,QAAQ;CACzB,IAAI,CAAC,UAAU,OAAO;CACtB,MAAM,aAAa,SAAS,eAAe,KAAA,KAAa,SAAS,aAAa,KAAA,IAC1E,GAAG,SAAS,WAAW,IAAI,SAAS,aACpC;CACJ,MAAM,YAAY,SAAS,kBAAkB,SAAS,eAClD,GAAG,UAAU,SAAS,cAAc,EAAE,IAAI,UAAU,SAAS,YAAY,MACzE;CACJ,IAAI,eAAe,oBAAoB,cAAc,IAAI,OAAO;CAChE,IAAI,eAAe,kBAAkB,OAAO;CAC5C,IAAI,cAAc,IAAI,OAAO;CAC7B,OAAO,GAAG,WAAW,KAAK;AAC5B;AAEA,SAAgB,0BAA0B,UAA+C;CACvF,IAAI,SAAS,SAAS,WAAW,GAAG,OAAO;CAC3C,MAAM,UAAU;EAAC;EAAW;EAAY;EAAS;EAAQ;EAAW;CAAiB;CACrF,MAAM,SAAS;EAAC;EAAI;EAAI;EAAG;EAAG;EAAI;CAAE;CACpC,MAAM,OAAO,WAAqB,OAAO,KAAK,OAAO,UAAU,MAAM,OAAO,OAAO,MAAO,CAAC,CAAC,CAAC,KAAK,IAAI;CACtG,MAAM,cAAc,SAAS,SAAS,SAAS,YAAY;EAEzD,OADkB,mBAAmB,OACtB,CAAC,CAAC,KAAK,UAAU,UAAU,IAAI;GAC5C,UAAU,IAAI,QAAQ,gBAAgB,QAAQ,UAAU;GACxD,UAAU,IAAI,WAAW,SAAS,UAAU,IAAI;GAChD,UAAU,IAAI,WAAW,SAAS,OAAO,IAAI;GAC7C,UAAU,IAAI,WAAW,SAAS,MAAM,IAAI;GAC5C,UAAU,IAAI,aAAa,OAAO,IAAI;GACtC;EACF,CAAC,CAAC;CACJ,CAAC;CACD,OAAO;EACL,IAAI,OAAO;EACX,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;EAClD,GAAG;CACL,CAAC,CAAC,KAAK,IAAI;AACb"}