chain-insights 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +14 -1
  2. package/bin/cli.js +1 -1
  3. package/bin/install.cjs +1 -1
  4. package/dist/{capabilities-BZI6qROg.mjs → capabilities-BPnw6nP_.mjs} +20 -2
  5. package/dist/{capabilities-BZI6qROg.mjs.map → capabilities-BPnw6nP_.mjs.map} +1 -1
  6. package/dist/{capabilities-CPcrxodx.cjs → capabilities-EMRzwPBU.cjs} +19 -1
  7. package/dist/cli.cjs +67 -15
  8. package/dist/cli.mjs +67 -15
  9. package/dist/cli.mjs.map +1 -1
  10. package/dist/{client-D4aM4bzP.mjs → client-CHYskPnG.mjs} +6 -6
  11. package/dist/client-CHYskPnG.mjs.map +1 -0
  12. package/dist/{client-CqAzD519.cjs → client-Ypw9BNbn.cjs} +5 -5
  13. package/dist/create-C0buxEfU.mjs +48 -0
  14. package/dist/create-C0buxEfU.mjs.map +1 -0
  15. package/dist/create-DdggkF04.cjs +69 -0
  16. package/dist/index.cjs +7 -3
  17. package/dist/index.d.cts +10 -1
  18. package/dist/index.d.cts.map +1 -1
  19. package/dist/index.d.mts +10 -1
  20. package/dist/index.d.mts.map +1 -1
  21. package/dist/index.mjs +5 -4
  22. package/dist/mcp-proxy.cjs +5 -5
  23. package/dist/mcp-proxy.mjs +5 -5
  24. package/dist/mcp-proxy.mjs.map +1 -1
  25. package/dist/{tools-lPY6k-vJ.cjs → tools-BHfphgy9.cjs} +4 -4
  26. package/dist/{tools-BKLnlBG1.mjs → tools-BRQAPF2R.mjs} +5 -5
  27. package/dist/tools-BRQAPF2R.mjs.map +1 -0
  28. package/dist/{wallet-BEvHrHi3.cjs → wallet-B3hAr70M.cjs} +3 -3
  29. package/dist/{wallet-fMbhvKXT.mjs → wallet-COcm4oIb.mjs} +4 -4
  30. package/dist/wallet-COcm4oIb.mjs.map +1 -0
  31. package/docs/architecture.md +5 -5
  32. package/docs/graph-tools.md +3 -3
  33. package/docs/mcp-proxy.md +29 -20
  34. package/package.json +1 -1
  35. package/dist/client-D4aM4bzP.mjs.map +0 -1
  36. package/dist/tools-BKLnlBG1.mjs.map +0 -1
  37. package/dist/wallet-fMbhvKXT.mjs.map +0 -1
package/README.md CHANGED
@@ -23,7 +23,8 @@ as-is on macOS; on Windows use WSL.
23
23
  npx chain-insights@latest --help # run without installing
24
24
  npm install -g chain-insights # or install the cia CLI globally
25
25
  cia mcp call aml_address_risk network=robinhood address=0xYourAddressHere
26
- cia networks # supported networks + public tool surface
26
+ cia networks # all supported networks
27
+ cia network robinhood # details for one network
27
28
  ```
28
29
 
29
30
  Sixty seconds gets you the CLI and the live tool catalog.
@@ -214,6 +215,18 @@ cia mcp call aml_address_risk \
214
215
  network=robinhood address=0xYourAddressHere
215
216
  ```
216
217
 
218
+ Create a local payment wallet when paid access is needed:
219
+
220
+ ```bash
221
+ cia wallet create
222
+ ```
223
+
224
+ The command shows the private key once in a clearly marked warning panel.
225
+ Save it in a secure password manager or offline backup, then type `BACKED UP`
226
+ to finish. The encrypted local copy is stored at
227
+ `~/.chain-insights/wallet.json`. Continue with `cia wallet ready` when you are
228
+ ready to enable paid access.
229
+
217
230
  Example queries. Direct topology:
218
231
 
219
232
  ```bash
package/bin/cli.js CHANGED
@@ -4,6 +4,6 @@
4
4
  // CJS shim: bridges the npm bin entry to the ESM dist built by tsdown.
5
5
  // Dynamic import() is the correct bridge pattern from CommonJS to ESM.
6
6
  import('../dist/cli.mjs').catch((err) => {
7
- console.error('Failed to load chain-insights:', err.message)
7
+ console.error('Failed to load cia:', err.message)
8
8
  process.exit(1)
9
9
  })
package/bin/install.cjs CHANGED
@@ -282,5 +282,5 @@ for (const target of skillsTargets) {
282
282
  console.log(` ${cyan}Config:${reset} ${configPath}`)
283
283
  console.log(` ${cyan}Data dir:${reset} ${dataDir}`)
284
284
  console.log(
285
- `\n${dim}Run ${reset}${cyan}chain-insights status${reset}${dim} to verify the installation.${reset}\n`
285
+ `\n${dim}Run ${reset}${cyan}cia status${reset}${dim} to verify the installation.${reset}\n`
286
286
  )
@@ -1,10 +1,12 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { a as resolveGraphMcpEndpoint, n as applyMcpAuthHeaders } from "./client-D4aM4bzP.mjs";
2
+ import { a as resolveGraphMcpEndpoint, n as applyMcpAuthHeaders } from "./client-CHYskPnG.mjs";
3
3
  //#region src/mcp/capabilities.ts
4
4
  var capabilities_exports = /* @__PURE__ */ __exportAll({
5
5
  PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS: () => PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,
6
6
  fetchNetworkCapabilities: () => fetchNetworkCapabilities,
7
+ findNetworkCapability: () => findNetworkCapability,
7
8
  formatNetworkCapabilities: () => formatNetworkCapabilities,
9
+ formatNetworkCapability: () => formatNetworkCapability,
8
10
  mirrorGraphNetworkCapabilities: () => mirrorGraphNetworkCapabilities
9
11
  });
10
12
  const PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS = {
@@ -123,7 +125,23 @@ function formatNetworkCapabilities(document) {
123
125
  ...networkRows
124
126
  ].join("\n");
125
127
  }
128
+ function findNetworkCapability(document, name) {
129
+ const normalizedName = name.trim().toLowerCase();
130
+ if (!normalizedName) return void 0;
131
+ return document.networks.find((network) => [network.network, network.display_name].some((candidate) => candidate?.trim().toLowerCase() === normalizedName));
132
+ }
133
+ function formatNetworkCapability(network) {
134
+ const rows = [
135
+ ["Network", network.display_name || network.network],
136
+ ["Identifier", network.network],
137
+ ["Status", network.default ? `${network.status} (default)` : network.status],
138
+ ["Dataset", datasetLabel(network)],
139
+ ["Available tools", availableTools(network).join(", ") || "none"]
140
+ ];
141
+ const labelWidth = Math.max(...rows.map(([label]) => label.length));
142
+ return rows.map(([label, value]) => `${label.padEnd(labelWidth)} ${value}`).join("\n");
143
+ }
126
144
  //#endregion
127
145
  export { mirrorGraphNetworkCapabilities as n, capabilities_exports as t };
128
146
 
129
- //# sourceMappingURL=capabilities-BZI6qROg.mjs.map
147
+ //# sourceMappingURL=capabilities-BPnw6nP_.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-BZI6qROg.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\nexport const PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS = {\n aml_address_risk: 'available',\n graph_query: 'available',\n graph_query_batch: 'available',\n meta_network_capabilities: 'available',\n meta_usage_status: 'available',\n meta_help: 'available',\n wallet_balance: 'available',\n} as const\nconst AVAILABLE_TOOLS_PER_LINE = 3\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction advertisedNetwork(raw: unknown): NetworkCapability | null {\n if (!isRecord(raw) || typeof raw.network !== 'string' || raw.network.trim() === '') {\n return null\n }\n const network = raw.network.trim()\n const capability: NetworkCapability = {\n network,\n display_name:\n typeof raw.display_name === 'string' && raw.display_name.trim() !== ''\n ? raw.display_name\n : network,\n status: typeof raw.status === 'string' && raw.status.trim() !== '' ? raw.status : 'live',\n layers: {},\n tools: { ...PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS },\n }\n if (raw.default === true) capability.default = true\n if (raw.default === false) capability.default = false\n if (isRecord(raw.coverage)) capability.coverage = raw.coverage as NetworkCapability['coverage']\n if (isRecord(raw.freshness))\n capability.freshness = raw.freshness as NetworkCapability['freshness']\n return capability\n}\n\n/** Repeat GraphRAG's network list. CIA does not add, drop, or invent names. */\nexport function mirrorGraphNetworkCapabilities(document: {\n networks: unknown[]\n}): NetworkCapabilitiesDocument {\n return {\n schema: 'chain-insights.network-capabilities.v1',\n networks: document.networks\n .map((network) => advertisedNetwork(network))\n .filter((network): network is NetworkCapability => network !== null),\n }\n}\n\nfunction publicNetworkCapabilities(\n document: NetworkCapabilitiesDocument\n): NetworkCapabilitiesDocument {\n return mirrorGraphNetworkCapabilities(document)\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 (\n parsed.schema !== 'chain-insights.network-capabilities.v1' ||\n !Array.isArray(parsed.networks)\n ) {\n throw new Error('network capabilities response has unsupported schema')\n }\n return publicNetworkCapabilities(parsed)\n}\n\nfunction availableTools(network: NetworkCapability): string[] {\n const effectiveTools = {\n ...(network.tools ?? {}),\n ...PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,\n }\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 =\n coverage.from_block !== undefined && coverage.to_block !== undefined\n ? `${coverage.from_block}..${coverage.to_block}`\n : 'blocks unknown'\n const dateRange =\n 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', 'Dataset', 'Available tools']\n const widths = [14, 38, 64]\n const row = (values: string[]) =>\n 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) =>\n row([\n index === 0 ? network.display_name || network.network : '',\n index === 0 ? datasetLabel(network) : '',\n toolLine,\n ])\n )\n })\n return [row(headers), widths.map((width) => '-'.repeat(width)).join(' '), ...networkRows].join(\n '\\n'\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"capabilities-BPnw6nP_.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\nexport const PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS = {\n aml_address_risk: 'available',\n graph_query: 'available',\n graph_query_batch: 'available',\n meta_network_capabilities: 'available',\n meta_usage_status: 'available',\n meta_help: 'available',\n wallet_balance: 'available',\n} as const\nconst AVAILABLE_TOOLS_PER_LINE = 3\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction advertisedNetwork(raw: unknown): NetworkCapability | null {\n if (!isRecord(raw) || typeof raw.network !== 'string' || raw.network.trim() === '') {\n return null\n }\n const network = raw.network.trim()\n const capability: NetworkCapability = {\n network,\n display_name:\n typeof raw.display_name === 'string' && raw.display_name.trim() !== ''\n ? raw.display_name\n : network,\n status: typeof raw.status === 'string' && raw.status.trim() !== '' ? raw.status : 'live',\n layers: {},\n tools: { ...PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS },\n }\n if (raw.default === true) capability.default = true\n if (raw.default === false) capability.default = false\n if (isRecord(raw.coverage)) capability.coverage = raw.coverage as NetworkCapability['coverage']\n if (isRecord(raw.freshness))\n capability.freshness = raw.freshness as NetworkCapability['freshness']\n return capability\n}\n\n/** Repeat GraphRAG's network list. CIA does not add, drop, or invent names. */\nexport function mirrorGraphNetworkCapabilities(document: {\n networks: unknown[]\n}): NetworkCapabilitiesDocument {\n return {\n schema: 'chain-insights.network-capabilities.v1',\n networks: document.networks\n .map((network) => advertisedNetwork(network))\n .filter((network): network is NetworkCapability => network !== null),\n }\n}\n\nfunction publicNetworkCapabilities(\n document: NetworkCapabilitiesDocument\n): NetworkCapabilitiesDocument {\n return mirrorGraphNetworkCapabilities(document)\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 (\n parsed.schema !== 'chain-insights.network-capabilities.v1' ||\n !Array.isArray(parsed.networks)\n ) {\n throw new Error('network capabilities response has unsupported schema')\n }\n return publicNetworkCapabilities(parsed)\n}\n\nfunction availableTools(network: NetworkCapability): string[] {\n const effectiveTools = {\n ...(network.tools ?? {}),\n ...PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,\n }\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 =\n coverage.from_block !== undefined && coverage.to_block !== undefined\n ? `${coverage.from_block}..${coverage.to_block}`\n : 'blocks unknown'\n const dateRange =\n 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', 'Dataset', 'Available tools']\n const widths = [14, 38, 64]\n const row = (values: string[]) =>\n 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) =>\n row([\n index === 0 ? network.display_name || network.network : '',\n index === 0 ? datasetLabel(network) : '',\n toolLine,\n ])\n )\n })\n return [row(headers), widths.map((width) => '-'.repeat(width)).join(' '), ...networkRows].join(\n '\\n'\n )\n}\n\nexport function findNetworkCapability(\n document: NetworkCapabilitiesDocument,\n name: string\n): NetworkCapability | undefined {\n const normalizedName = name.trim().toLowerCase()\n if (!normalizedName) return undefined\n return document.networks.find((network) =>\n [network.network, network.display_name].some(\n (candidate) => candidate?.trim().toLowerCase() === normalizedName\n )\n )\n}\n\nexport function formatNetworkCapability(network: NetworkCapability): string {\n const rows = [\n ['Network', network.display_name || network.network],\n ['Identifier', network.network],\n ['Status', network.default ? `${network.status} (default)` : network.status],\n ['Dataset', datasetLabel(network)],\n ['Available tools', availableTools(network).join(', ') || 'none'],\n ]\n const labelWidth = Math.max(...rows.map(([label]) => label.length))\n return rows.map(([label, value]) => `${label.padEnd(labelWidth)} ${value}`).join('\\n')\n}\n"],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-C0BPl7ul.cjs");
2
- const require_client = require("./client-CqAzD519.cjs");
2
+ const require_client = require("./client-Ypw9BNbn.cjs");
3
3
  //#region src/mcp/capabilities.ts
4
4
  var capabilities_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
5
5
  PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS: () => PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS,
6
6
  fetchNetworkCapabilities: () => fetchNetworkCapabilities,
7
+ findNetworkCapability: () => findNetworkCapability,
7
8
  formatNetworkCapabilities: () => formatNetworkCapabilities,
9
+ formatNetworkCapability: () => formatNetworkCapability,
8
10
  mirrorGraphNetworkCapabilities: () => mirrorGraphNetworkCapabilities
9
11
  });
10
12
  const PUBLIC_CHAIN_INSIGHTS_TOOL_STATUS = {
@@ -123,6 +125,22 @@ function formatNetworkCapabilities(document) {
123
125
  ...networkRows
124
126
  ].join("\n");
125
127
  }
128
+ function findNetworkCapability(document, name) {
129
+ const normalizedName = name.trim().toLowerCase();
130
+ if (!normalizedName) return void 0;
131
+ return document.networks.find((network) => [network.network, network.display_name].some((candidate) => candidate?.trim().toLowerCase() === normalizedName));
132
+ }
133
+ function formatNetworkCapability(network) {
134
+ const rows = [
135
+ ["Network", network.display_name || network.network],
136
+ ["Identifier", network.network],
137
+ ["Status", network.default ? `${network.status} (default)` : network.status],
138
+ ["Dataset", datasetLabel(network)],
139
+ ["Available tools", availableTools(network).join(", ") || "none"]
140
+ ];
141
+ const labelWidth = Math.max(...rows.map(([label]) => label.length));
142
+ return rows.map(([label, value]) => `${label.padEnd(labelWidth)} ${value}`).join("\n");
143
+ }
126
144
  //#endregion
127
145
  Object.defineProperty(exports, "capabilities_exports", {
128
146
  enumerable: true,
package/dist/cli.cjs CHANGED
@@ -23,7 +23,7 @@ function printMcpTextContent(result) {
23
23
  const __dirname$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
24
24
  const installerPath = node_path.default.resolve(__dirname$1, "..", "bin", "install.cjs");
25
25
  const program = new commander.Command();
26
- program.name("chain-insights").description("AML investigation toolkit for blockchain analysis").version(require_version.PACKAGE_INFO.version).option("--claude", "Install Claude Code skills globally to ~/.claude/skills/").option("--codex", "Install Codex skills globally to ~/.codex/skills/ and register MCP").option("--hermes", "Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP");
26
+ program.name("cia").description("AML investigation toolkit for blockchain analysis").version(require_version.PACKAGE_INFO.version).option("--claude", "Install Claude Code skills globally to ~/.claude/skills/").option("--codex", "Install Codex skills globally to ~/.codex/skills/ and register MCP").option("--hermes", "Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP");
27
27
  const rawArgs = process.argv.slice(2);
28
28
  const installerFlags = rawArgs.filter((a) => a === "--claude" || a === "--codex" || a === "--hermes");
29
29
  const wantsHelpOrVersion = rawArgs.some((a) => a === "--help" || a === "-h" || a === "--version" || a === "-V");
@@ -52,7 +52,7 @@ function runInstaller(flag) {
52
52
  async function withGraphMcpClient(name, fn) {
53
53
  const { loadConfig } = await Promise.resolve().then(() => require("./config-B542AM4w.cjs")).then((n) => n.config_exports);
54
54
  const config = await loadConfig();
55
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
55
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Ypw9BNbn.cjs")).then((n) => n.client_exports);
56
56
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
57
57
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
58
58
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -71,12 +71,25 @@ async function withGraphMcpClient(name, fn) {
71
71
  }
72
72
  async function printNetworkCapabilities(opts) {
73
73
  const { loadConfig } = await Promise.resolve().then(() => require("./config-B542AM4w.cjs")).then((n) => n.config_exports);
74
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-CPcrxodx.cjs")).then((n) => n.capabilities_exports);
74
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-EMRzwPBU.cjs")).then((n) => n.capabilities_exports);
75
75
  const document = await fetchNetworkCapabilities(await loadConfig());
76
76
  if (opts.json) console.log(JSON.stringify(document, null, 2));
77
77
  else console.log(formatNetworkCapabilities(document));
78
78
  }
79
- program.command("networks").alias("network").description("List supported graph networks, capability layers, and available tools").option("--json", "Print raw capability JSON").action(async (opts) => {
79
+ async function printNetworkCapability(name, opts) {
80
+ const { loadConfig } = await Promise.resolve().then(() => require("./config-B542AM4w.cjs")).then((n) => n.config_exports);
81
+ const { fetchNetworkCapabilities, findNetworkCapability, formatNetworkCapability } = await Promise.resolve().then(() => require("./capabilities-EMRzwPBU.cjs")).then((n) => n.capabilities_exports);
82
+ const document = await fetchNetworkCapabilities(await loadConfig());
83
+ const network = findNetworkCapability(document, name);
84
+ if (!network) {
85
+ const available = document.networks.map((candidate) => candidate.network).join(", ");
86
+ const suffix = available ? ` Available networks: ${available}.` : "";
87
+ throw new Error(`Network "${name}" is not supported.${suffix} Run \`cia networks\` to list supported networks.`);
88
+ }
89
+ if (opts.json) console.log(JSON.stringify(network, null, 2));
90
+ else console.log(formatNetworkCapability(network));
91
+ }
92
+ program.command("networks").description("List supported graph networks, capability layers, and available tools").option("--json", "Print raw capability JSON").action(async (opts) => {
80
93
  try {
81
94
  await printNetworkCapabilities(opts);
82
95
  } catch (err) {
@@ -84,6 +97,14 @@ program.command("networks").alias("network").description("List supported graph n
84
97
  process.exit(1);
85
98
  }
86
99
  });
100
+ program.command("network").description("Show details for one supported graph network").argument("<name>", "Network identifier or display name (for example: robinhood)").option("--json", "Print raw capability JSON for this network").action(async (name, opts) => {
101
+ try {
102
+ await printNetworkCapability(name, opts);
103
+ } catch (err) {
104
+ console.error(err.message);
105
+ process.exit(1);
106
+ }
107
+ });
87
108
  program.command("status").description("Show toolkit status and configuration").action(async () => {
88
109
  const { loadConfig } = await Promise.resolve().then(() => require("./config-B542AM4w.cjs")).then((n) => n.config_exports);
89
110
  const config = await loadConfig();
@@ -219,7 +240,7 @@ program.command("config").description("Read or write configuration values").addC
219
240
  })).addCommand(new commander.Command("set").argument("<key>", "Config key to write").argument("<value>", "Value to set").action(async (key, value) => {
220
241
  if (key === "walletPrivateKey") {
221
242
  try {
222
- const { setWalletPrivateKey } = await Promise.resolve().then(() => require("./wallet-BEvHrHi3.cjs")).then((n) => n.wallet_exports);
243
+ const { setWalletPrivateKey } = await Promise.resolve().then(() => require("./wallet-B3hAr70M.cjs")).then((n) => n.wallet_exports);
223
244
  const address = await setWalletPrivateKey(value);
224
245
  console.log("Wallet private key encrypted and stored in ~/.chain-insights/wallet.json");
225
246
  console.log(`Wallet address: ${address}`);
@@ -243,21 +264,52 @@ program.command("config").description("Read or write configuration values").addC
243
264
  const displayed = key.toLowerCase().includes("token") ? "[redacted]" : coerced;
244
265
  console.log(`Set ${key} = ${displayed}`);
245
266
  }));
246
- program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new commander.Command("import").description("Import a Base payment wallet").argument("<private-key>", "0x-prefixed EVM private key").option("--force", "Replace an existing wallet (the previous key is backed up next to wallet.json)").action(async (privateKey, opts) => {
267
+ program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new commander.Command("create").description("Generate a new local Base payment wallet").action(async () => {
268
+ try {
269
+ const { isWalletConfigured, setWalletPrivateKey, walletPath } = await Promise.resolve().then(() => require("./wallet-B3hAr70M.cjs")).then((n) => n.wallet_exports);
270
+ const { createInterface } = await import("node:readline/promises");
271
+ const { formatWalletBackupWarning, generateWalletPrivateKey, isWalletBackupConfirmed } = await Promise.resolve().then(() => require("./create-DdggkF04.cjs")).then((n) => n.create_exports);
272
+ if (await isWalletConfigured()) throw new Error("A payment wallet already exists. Run `cia wallet address` to view it or use `cia wallet import <private-key> --force` to replace it.");
273
+ const privateKey = generateWalletPrivateKey();
274
+ const color = process.stderr.isTTY === true && process.env["NO_COLOR"] === void 0;
275
+ process.stderr.write(`${formatWalletBackupWarning(privateKey, { color })}\n`);
276
+ const prompt = createInterface({
277
+ input: process.stdin,
278
+ output: process.stderr
279
+ });
280
+ let answer;
281
+ try {
282
+ answer = await prompt.question("> ");
283
+ } finally {
284
+ prompt.close();
285
+ }
286
+ process.stderr.write("\n");
287
+ if (!isWalletBackupConfirmed(answer)) throw new Error("Wallet creation cancelled. The wallet was not saved.");
288
+ const address = await setWalletPrivateKey(privateKey);
289
+ console.log(`Wallet created: ${address}`);
290
+ console.log(`Encrypted local copy: ${walletPath()}`);
291
+ console.log("Next: cia wallet ready");
292
+ } catch (err) {
293
+ console.error(err.message);
294
+ process.exit(1);
295
+ }
296
+ })).addCommand(new commander.Command("import").description("Import a Base payment wallet").argument("<private-key>", "0x-prefixed EVM private key").option("--force", "Replace an existing wallet (the previous key is backed up next to wallet.json)").action(async (privateKey, opts) => {
247
297
  try {
248
- const { setWalletPrivateKey, isWalletConfigured } = await Promise.resolve().then(() => require("./wallet-BEvHrHi3.cjs")).then((n) => n.wallet_exports);
298
+ const { setWalletPrivateKey, isWalletConfigured } = await Promise.resolve().then(() => require("./wallet-B3hAr70M.cjs")).then((n) => n.wallet_exports);
249
299
  const replacing = opts.force === true && await isWalletConfigured();
250
300
  const address = await setWalletPrivateKey(privateKey, { force: opts.force });
251
301
  if (replacing) console.log("Previous wallet key backed up next to ~/.chain-insights/wallet.json");
252
302
  console.log(`Wallet imported: ${address}`);
253
- console.log("Next: run `chain-insights wallet ready`");
303
+ console.log("Keep your original private key backed up securely; it cannot be recovered from the encrypted local copy.");
304
+ console.log("Encrypted local copy: ~/.chain-insights/wallet.json");
305
+ console.log("Next: cia wallet ready");
254
306
  } catch (err) {
255
307
  console.error(err.message);
256
308
  process.exit(1);
257
309
  }
258
310
  })).addCommand(new commander.Command("address").description("Print the local payment wallet address").action(async () => {
259
311
  try {
260
- const { getWalletAccount } = await Promise.resolve().then(() => require("./tools-lPY6k-vJ.cjs")).then((n) => n.tools_exports);
312
+ const { getWalletAccount } = await Promise.resolve().then(() => require("./tools-BHfphgy9.cjs")).then((n) => n.tools_exports);
261
313
  const account = await getWalletAccount();
262
314
  console.log(account.address);
263
315
  } catch (err) {
@@ -266,7 +318,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
266
318
  }
267
319
  })).addCommand(new commander.Command("balance").description("Show the local payment wallet Base USDC balance").action(async () => {
268
320
  try {
269
- const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-lPY6k-vJ.cjs")).then((n) => n.tools_exports);
321
+ const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-BHfphgy9.cjs")).then((n) => n.tools_exports);
270
322
  console.log(await getWalletBalanceText());
271
323
  } catch (err) {
272
324
  console.error(err.message);
@@ -274,7 +326,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
274
326
  }
275
327
  })).addCommand(new commander.Command("ready").description("Check and prepare the wallet for paid Chain Insights Graph calls").option("--check-only", "Only check readiness; do not submit the one-time payment setup").addOption(new commander.Option("--no-approve", "Deprecated alias for --check-only").hideHelp()).option("--payment-usdc <amount>", "USDC setup cap to prepare for paid calls", "1").addOption(new commander.Option("--approval-usdc <amount>", "Deprecated alias for --payment-usdc").hideHelp()).option("--json", "Print machine-readable readiness metadata").action(async (opts) => {
276
328
  try {
277
- const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await Promise.resolve().then(() => require("./tools-lPY6k-vJ.cjs")).then((n) => n.tools_exports);
329
+ const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await Promise.resolve().then(() => require("./tools-BHfphgy9.cjs")).then((n) => n.tools_exports);
278
330
  const result = await prepareWalletForPaidCalls({
279
331
  minimumApprovalUnits: parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? "1"),
280
332
  approve: opts.checkOnly ? false : opts.approve !== false
@@ -290,7 +342,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
290
342
  }
291
343
  })).addCommand(new commander.Command("topup").description("Open a local browser page to top up the payment wallet").option("--no-open", "Print the top-up URL without opening a browser").option("--json", "Print machine-readable top-up metadata").action(async (opts) => {
292
344
  try {
293
- const { buildTopupInfo, getWalletAccount } = await Promise.resolve().then(() => require("./tools-lPY6k-vJ.cjs")).then((n) => n.tools_exports);
345
+ const { buildTopupInfo, getWalletAccount } = await Promise.resolve().then(() => require("./tools-BHfphgy9.cjs")).then((n) => n.tools_exports);
294
346
  const { startTopupServer } = await Promise.resolve().then(() => require("./topup-server-YN3iHrHW.cjs")).then((n) => n.topup_server_exports);
295
347
  const account = await getWalletAccount();
296
348
  const url = await startTopupServer(account);
@@ -325,7 +377,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
325
377
  const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
326
378
  const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-C8F9Yoxy.cjs")).then((n) => n.tool_visibility_exports);
327
379
  const { loadConfig } = await Promise.resolve().then(() => require("./config-B542AM4w.cjs")).then((n) => n.config_exports);
328
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
380
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Ypw9BNbn.cjs")).then((n) => n.client_exports);
329
381
  const config = await loadConfig();
330
382
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
331
383
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -373,7 +425,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
373
425
  assertPublicMcpToolName(tool);
374
426
  validatePublicMcpToolArguments(tool, args);
375
427
  if (tool === "wallet_balance") {
376
- const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-lPY6k-vJ.cjs")).then((n) => n.tools_exports);
428
+ const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-BHfphgy9.cjs")).then((n) => n.tools_exports);
377
429
  console.log(await getWalletBalanceText());
378
430
  return;
379
431
  }
@@ -395,7 +447,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
395
447
  } catch (err) {
396
448
  const { isMissingUsageStatusToolError, primitiveBackendUsageStatus, usageStatusText } = await Promise.resolve().then(() => require("./usage-status-BdwwgYsu.cjs")).then((n) => n.usage_status_exports);
397
449
  if (!isMissingUsageStatusToolError(err)) throw err;
398
- const { resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-CqAzD519.cjs")).then((n) => n.client_exports);
450
+ const { resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Ypw9BNbn.cjs")).then((n) => n.client_exports);
399
451
  console.log(usageStatusText(primitiveBackendUsageStatus(resolveGraphMcpEndpoint(config))));
400
452
  }
401
453
  return;
package/dist/cli.mjs CHANGED
@@ -21,7 +21,7 @@ function printMcpTextContent(result) {
21
21
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
22
  const installerPath = path.resolve(__dirname, "..", "bin", "install.cjs");
23
23
  const program = new Command();
24
- program.name("chain-insights").description("AML investigation toolkit for blockchain analysis").version(PACKAGE_INFO.version).option("--claude", "Install Claude Code skills globally to ~/.claude/skills/").option("--codex", "Install Codex skills globally to ~/.codex/skills/ and register MCP").option("--hermes", "Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP");
24
+ program.name("cia").description("AML investigation toolkit for blockchain analysis").version(PACKAGE_INFO.version).option("--claude", "Install Claude Code skills globally to ~/.claude/skills/").option("--codex", "Install Codex skills globally to ~/.codex/skills/ and register MCP").option("--hermes", "Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP");
25
25
  const rawArgs = process.argv.slice(2);
26
26
  const installerFlags = rawArgs.filter((a) => a === "--claude" || a === "--codex" || a === "--hermes");
27
27
  const wantsHelpOrVersion = rawArgs.some((a) => a === "--help" || a === "-h" || a === "--version" || a === "-V");
@@ -50,7 +50,7 @@ function runInstaller(flag) {
50
50
  async function withGraphMcpClient(name, fn) {
51
51
  const { loadConfig } = await import("./config-DbbPiGk0.mjs").then((n) => n.t);
52
52
  const config = await loadConfig();
53
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
53
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-CHYskPnG.mjs").then((n) => n.r);
54
54
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
55
55
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
56
56
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -69,12 +69,25 @@ async function withGraphMcpClient(name, fn) {
69
69
  }
70
70
  async function printNetworkCapabilities(opts) {
71
71
  const { loadConfig } = await import("./config-DbbPiGk0.mjs").then((n) => n.t);
72
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BZI6qROg.mjs").then((n) => n.t);
72
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BPnw6nP_.mjs").then((n) => n.t);
73
73
  const document = await fetchNetworkCapabilities(await loadConfig());
74
74
  if (opts.json) console.log(JSON.stringify(document, null, 2));
75
75
  else console.log(formatNetworkCapabilities(document));
76
76
  }
77
- program.command("networks").alias("network").description("List supported graph networks, capability layers, and available tools").option("--json", "Print raw capability JSON").action(async (opts) => {
77
+ async function printNetworkCapability(name, opts) {
78
+ const { loadConfig } = await import("./config-DbbPiGk0.mjs").then((n) => n.t);
79
+ const { fetchNetworkCapabilities, findNetworkCapability, formatNetworkCapability } = await import("./capabilities-BPnw6nP_.mjs").then((n) => n.t);
80
+ const document = await fetchNetworkCapabilities(await loadConfig());
81
+ const network = findNetworkCapability(document, name);
82
+ if (!network) {
83
+ const available = document.networks.map((candidate) => candidate.network).join(", ");
84
+ const suffix = available ? ` Available networks: ${available}.` : "";
85
+ throw new Error(`Network "${name}" is not supported.${suffix} Run \`cia networks\` to list supported networks.`);
86
+ }
87
+ if (opts.json) console.log(JSON.stringify(network, null, 2));
88
+ else console.log(formatNetworkCapability(network));
89
+ }
90
+ program.command("networks").description("List supported graph networks, capability layers, and available tools").option("--json", "Print raw capability JSON").action(async (opts) => {
78
91
  try {
79
92
  await printNetworkCapabilities(opts);
80
93
  } catch (err) {
@@ -82,6 +95,14 @@ program.command("networks").alias("network").description("List supported graph n
82
95
  process.exit(1);
83
96
  }
84
97
  });
98
+ program.command("network").description("Show details for one supported graph network").argument("<name>", "Network identifier or display name (for example: robinhood)").option("--json", "Print raw capability JSON for this network").action(async (name, opts) => {
99
+ try {
100
+ await printNetworkCapability(name, opts);
101
+ } catch (err) {
102
+ console.error(err.message);
103
+ process.exit(1);
104
+ }
105
+ });
85
106
  program.command("status").description("Show toolkit status and configuration").action(async () => {
86
107
  const { loadConfig } = await import("./config-DbbPiGk0.mjs").then((n) => n.t);
87
108
  const config = await loadConfig();
@@ -217,7 +238,7 @@ program.command("config").description("Read or write configuration values").addC
217
238
  })).addCommand(new Command("set").argument("<key>", "Config key to write").argument("<value>", "Value to set").action(async (key, value) => {
218
239
  if (key === "walletPrivateKey") {
219
240
  try {
220
- const { setWalletPrivateKey } = await import("./wallet-fMbhvKXT.mjs").then((n) => n.s);
241
+ const { setWalletPrivateKey } = await import("./wallet-COcm4oIb.mjs").then((n) => n.s);
221
242
  const address = await setWalletPrivateKey(value);
222
243
  console.log("Wallet private key encrypted and stored in ~/.chain-insights/wallet.json");
223
244
  console.log(`Wallet address: ${address}`);
@@ -241,21 +262,52 @@ program.command("config").description("Read or write configuration values").addC
241
262
  const displayed = key.toLowerCase().includes("token") ? "[redacted]" : coerced;
242
263
  console.log(`Set ${key} = ${displayed}`);
243
264
  }));
244
- program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new Command("import").description("Import a Base payment wallet").argument("<private-key>", "0x-prefixed EVM private key").option("--force", "Replace an existing wallet (the previous key is backed up next to wallet.json)").action(async (privateKey, opts) => {
265
+ program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new Command("create").description("Generate a new local Base payment wallet").action(async () => {
266
+ try {
267
+ const { isWalletConfigured, setWalletPrivateKey, walletPath } = await import("./wallet-COcm4oIb.mjs").then((n) => n.s);
268
+ const { createInterface } = await import("node:readline/promises");
269
+ const { formatWalletBackupWarning, generateWalletPrivateKey, isWalletBackupConfirmed } = await import("./create-C0buxEfU.mjs").then((n) => n.t);
270
+ if (await isWalletConfigured()) throw new Error("A payment wallet already exists. Run `cia wallet address` to view it or use `cia wallet import <private-key> --force` to replace it.");
271
+ const privateKey = generateWalletPrivateKey();
272
+ const color = process.stderr.isTTY === true && process.env["NO_COLOR"] === void 0;
273
+ process.stderr.write(`${formatWalletBackupWarning(privateKey, { color })}\n`);
274
+ const prompt = createInterface({
275
+ input: process.stdin,
276
+ output: process.stderr
277
+ });
278
+ let answer;
279
+ try {
280
+ answer = await prompt.question("> ");
281
+ } finally {
282
+ prompt.close();
283
+ }
284
+ process.stderr.write("\n");
285
+ if (!isWalletBackupConfirmed(answer)) throw new Error("Wallet creation cancelled. The wallet was not saved.");
286
+ const address = await setWalletPrivateKey(privateKey);
287
+ console.log(`Wallet created: ${address}`);
288
+ console.log(`Encrypted local copy: ${walletPath()}`);
289
+ console.log("Next: cia wallet ready");
290
+ } catch (err) {
291
+ console.error(err.message);
292
+ process.exit(1);
293
+ }
294
+ })).addCommand(new Command("import").description("Import a Base payment wallet").argument("<private-key>", "0x-prefixed EVM private key").option("--force", "Replace an existing wallet (the previous key is backed up next to wallet.json)").action(async (privateKey, opts) => {
245
295
  try {
246
- const { setWalletPrivateKey, isWalletConfigured } = await import("./wallet-fMbhvKXT.mjs").then((n) => n.s);
296
+ const { setWalletPrivateKey, isWalletConfigured } = await import("./wallet-COcm4oIb.mjs").then((n) => n.s);
247
297
  const replacing = opts.force === true && await isWalletConfigured();
248
298
  const address = await setWalletPrivateKey(privateKey, { force: opts.force });
249
299
  if (replacing) console.log("Previous wallet key backed up next to ~/.chain-insights/wallet.json");
250
300
  console.log(`Wallet imported: ${address}`);
251
- console.log("Next: run `chain-insights wallet ready`");
301
+ console.log("Keep your original private key backed up securely; it cannot be recovered from the encrypted local copy.");
302
+ console.log("Encrypted local copy: ~/.chain-insights/wallet.json");
303
+ console.log("Next: cia wallet ready");
252
304
  } catch (err) {
253
305
  console.error(err.message);
254
306
  process.exit(1);
255
307
  }
256
308
  })).addCommand(new Command("address").description("Print the local payment wallet address").action(async () => {
257
309
  try {
258
- const { getWalletAccount } = await import("./tools-BKLnlBG1.mjs").then((n) => n.p);
310
+ const { getWalletAccount } = await import("./tools-BRQAPF2R.mjs").then((n) => n.p);
259
311
  const account = await getWalletAccount();
260
312
  console.log(account.address);
261
313
  } catch (err) {
@@ -264,7 +316,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
264
316
  }
265
317
  })).addCommand(new Command("balance").description("Show the local payment wallet Base USDC balance").action(async () => {
266
318
  try {
267
- const { getWalletBalanceText } = await import("./tools-BKLnlBG1.mjs").then((n) => n.p);
319
+ const { getWalletBalanceText } = await import("./tools-BRQAPF2R.mjs").then((n) => n.p);
268
320
  console.log(await getWalletBalanceText());
269
321
  } catch (err) {
270
322
  console.error(err.message);
@@ -272,7 +324,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
272
324
  }
273
325
  })).addCommand(new Command("ready").description("Check and prepare the wallet for paid Chain Insights Graph calls").option("--check-only", "Only check readiness; do not submit the one-time payment setup").addOption(new Option("--no-approve", "Deprecated alias for --check-only").hideHelp()).option("--payment-usdc <amount>", "USDC setup cap to prepare for paid calls", "1").addOption(new Option("--approval-usdc <amount>", "Deprecated alias for --payment-usdc").hideHelp()).option("--json", "Print machine-readable readiness metadata").action(async (opts) => {
274
326
  try {
275
- const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import("./tools-BKLnlBG1.mjs").then((n) => n.p);
327
+ const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import("./tools-BRQAPF2R.mjs").then((n) => n.p);
276
328
  const result = await prepareWalletForPaidCalls({
277
329
  minimumApprovalUnits: parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? "1"),
278
330
  approve: opts.checkOnly ? false : opts.approve !== false
@@ -288,7 +340,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
288
340
  }
289
341
  })).addCommand(new Command("topup").description("Open a local browser page to top up the payment wallet").option("--no-open", "Print the top-up URL without opening a browser").option("--json", "Print machine-readable top-up metadata").action(async (opts) => {
290
342
  try {
291
- const { buildTopupInfo, getWalletAccount } = await import("./tools-BKLnlBG1.mjs").then((n) => n.p);
343
+ const { buildTopupInfo, getWalletAccount } = await import("./tools-BRQAPF2R.mjs").then((n) => n.p);
292
344
  const { startTopupServer } = await import("./topup-server-BLdF1SFQ.mjs").then((n) => n.r);
293
345
  const account = await getWalletAccount();
294
346
  const url = await startTopupServer(account);
@@ -323,7 +375,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
323
375
  const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
324
376
  const { visibleRemoteTools } = await import("./tool-visibility-CXbwfKhv.mjs").then((n) => n.i);
325
377
  const { loadConfig } = await import("./config-DbbPiGk0.mjs").then((n) => n.t);
326
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
378
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-CHYskPnG.mjs").then((n) => n.r);
327
379
  const config = await loadConfig();
328
380
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
329
381
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -371,7 +423,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
371
423
  assertPublicMcpToolName(tool);
372
424
  validatePublicMcpToolArguments(tool, args);
373
425
  if (tool === "wallet_balance") {
374
- const { getWalletBalanceText } = await import("./tools-BKLnlBG1.mjs").then((n) => n.p);
426
+ const { getWalletBalanceText } = await import("./tools-BRQAPF2R.mjs").then((n) => n.p);
375
427
  console.log(await getWalletBalanceText());
376
428
  return;
377
429
  }
@@ -393,7 +445,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
393
445
  } catch (err) {
394
446
  const { isMissingUsageStatusToolError, primitiveBackendUsageStatus, usageStatusText } = await import("./usage-status-CHiOPA-2.mjs").then((n) => n.n);
395
447
  if (!isMissingUsageStatusToolError(err)) throw err;
396
- const { resolveGraphMcpEndpoint } = await import("./client-D4aM4bzP.mjs").then((n) => n.r);
448
+ const { resolveGraphMcpEndpoint } = await import("./client-CHYskPnG.mjs").then((n) => n.r);
397
449
  console.log(usageStatusText(primitiveBackendUsageStatus(resolveGraphMcpEndpoint(config))));
398
450
  }
399
451
  return;