chain-insights 0.2.27 → 0.2.28

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.
@@ -1,4 +1,4 @@
1
- const require_client = require("./client-DRJq31u_.cjs");
1
+ const require_client = require("./client-ByXzwNum.cjs");
2
2
  //#region src/mcp/capabilities.ts
3
3
  function metadataNetworksUrl(endpoint) {
4
4
  const url = new URL(endpoint);
@@ -1,4 +1,4 @@
1
- import { a as resolveGraphMcpEndpoint } from "./client-Bfw9P9uA.mjs";
1
+ import { a as resolveGraphMcpEndpoint } from "./client-7vkBVEIj.mjs";
2
2
  //#region src/mcp/capabilities.ts
3
3
  function metadataNetworksUrl(endpoint) {
4
4
  const url = new URL(endpoint);
@@ -81,4 +81,4 @@ function formatNetworkCapabilities(document) {
81
81
  //#endregion
82
82
  export { fetchNetworkCapabilities, formatNetworkCapabilities };
83
83
 
84
- //# sourceMappingURL=capabilities-BCm-2oBt.mjs.map
84
+ //# sourceMappingURL=capabilities-CYv7k4wI.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities-BCm-2oBt.mjs","names":[],"sources":["../src/mcp/capabilities.ts"],"sourcesContent":["import type { InvestigatorConfig } from '../config/schema.js'\nimport { resolveGraphMcpEndpoint } from './client.js'\n\nexport interface NetworkRetention {\n mode: 'full_history' | 'rolling_window' | 'expanding_then_rolling' | 'bounded_range' | 'unknown' | string\n window_days?: number\n from_block?: number\n to_block?: number\n from_timestamp?: string\n to_timestamp?: string\n started_at?: string\n rolls_after_at?: string\n current_window_seconds?: number\n}\n\nexport interface NetworkLayerCapability {\n enabled: boolean\n retention?: NetworkRetention | null\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\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, 'mcpAuthToken' | 'graphMcpAuthToken' | 'graphMcpMode' | 'graphMcpEndpoint' | 'mcpEndpoint'>,\n): Promise<NetworkCapabilitiesDocument> {\n const endpoint = resolveGraphMcpEndpoint(config)\n const request = metadataNetworksUrl(endpoint)\n const headers = new Headers()\n const token = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim()\n if (token) {\n headers.set('X-MCP-Debug-Token', token)\n headers.set('Authorization', `Bearer ${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 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 availableToolsLabel(network: NetworkCapability): string {\n const tools = Object.entries(network.tools ?? {})\n .filter(([, status]) => status === 'available')\n .map(([name]) => name)\n return tools.length > 0 ? tools.join(', ') : 'none'\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 : 'dates unknown'\n if (blockRange === 'blocks unknown' && dateRange === 'dates unknown') return 'unknown'\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 return [\n row(headers),\n widths.map((width) => '-'.repeat(width)).join(' '),\n ...document.networks.map((network) => row([\n network.display_name || network.network,\n layerValue(network, 'topology'),\n layerValue(network, 'facts'),\n layerValue(network, 'risk'),\n datasetLabel(network),\n availableToolsLabel(network),\n ])),\n ].join('\\n')\n}\n"],"mappings":";;AAgDA,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,KAAK,OAAO,cAAc,KAAK;CAC5E,IAAI,OAAO;EACT,QAAQ,IAAI,qBAAqB,KAAK;EACtC,QAAQ,IAAI,iBAAiB,UAAU,OAAO;CAChD;CACA,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;AACT;AAEA,SAAS,WAAW,SAA4B,OAAuB;CAErE,IAAI,CADe,QAAQ,OAAO,QACjB,SAAS,OAAO;CACjC,OAAO;AACT;AAEA,SAAS,oBAAoB,SAAoC;CAC/D,MAAM,QAAQ,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,EAC7C,QAAQ,GAAG,YAAY,WAAW,WAAW,EAC7C,KAAK,CAAC,UAAU,IAAI;CACvB,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;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,iBAAiB,OAAO;CAC7E,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,EAAE,KAAK,IAAI;CACtG,OAAO;EACL,IAAI,OAAO;EACX,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI;EAClD,GAAG,SAAS,SAAS,KAAK,YAAY,IAAI;GACxC,QAAQ,gBAAgB,QAAQ;GAChC,WAAW,SAAS,UAAU;GAC9B,WAAW,SAAS,OAAO;GAC3B,WAAW,SAAS,MAAM;GAC1B,aAAa,OAAO;GACpB,oBAAoB,OAAO;EAC7B,CAAC,CAAC;CACJ,EAAE,KAAK,IAAI;AACb"}
1
+ {"version":3,"file":"capabilities-CYv7k4wI.mjs","names":[],"sources":["../src/mcp/capabilities.ts"],"sourcesContent":["import type { InvestigatorConfig } from '../config/schema.js'\nimport { resolveGraphMcpEndpoint } from './client.js'\n\nexport interface NetworkRetention {\n mode: 'full_history' | 'rolling_window' | 'expanding_then_rolling' | 'bounded_range' | 'unknown' | string\n window_days?: number\n from_block?: number\n to_block?: number\n from_timestamp?: string\n to_timestamp?: string\n started_at?: string\n rolls_after_at?: string\n current_window_seconds?: number\n}\n\nexport interface NetworkLayerCapability {\n enabled: boolean\n retention?: NetworkRetention | null\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\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, 'mcpAuthToken' | 'graphMcpAuthToken' | 'graphMcpMode' | 'graphMcpEndpoint' | 'mcpEndpoint'>,\n): Promise<NetworkCapabilitiesDocument> {\n const endpoint = resolveGraphMcpEndpoint(config)\n const request = metadataNetworksUrl(endpoint)\n const headers = new Headers()\n const token = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim()\n if (token) {\n headers.set('X-MCP-Debug-Token', token)\n headers.set('Authorization', `Bearer ${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 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 availableToolsLabel(network: NetworkCapability): string {\n const tools = Object.entries(network.tools ?? {})\n .filter(([, status]) => status === 'available')\n .map(([name]) => name)\n return tools.length > 0 ? tools.join(', ') : 'none'\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 : 'dates unknown'\n if (blockRange === 'blocks unknown' && dateRange === 'dates unknown') return 'unknown'\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 return [\n row(headers),\n widths.map((width) => '-'.repeat(width)).join(' '),\n ...document.networks.map((network) => row([\n network.display_name || network.network,\n layerValue(network, 'topology'),\n layerValue(network, 'facts'),\n layerValue(network, 'risk'),\n datasetLabel(network),\n availableToolsLabel(network),\n ])),\n ].join('\\n')\n}\n"],"mappings":";;AAgDA,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,KAAK,OAAO,cAAc,KAAK;CAC5E,IAAI,OAAO;EACT,QAAQ,IAAI,qBAAqB,KAAK;EACtC,QAAQ,IAAI,iBAAiB,UAAU,OAAO;CAChD;CACA,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;AACT;AAEA,SAAS,WAAW,SAA4B,OAAuB;CAErE,IAAI,CADe,QAAQ,OAAO,QACjB,SAAS,OAAO;CACjC,OAAO;AACT;AAEA,SAAS,oBAAoB,SAAoC;CAC/D,MAAM,QAAQ,OAAO,QAAQ,QAAQ,SAAS,CAAC,CAAC,EAC7C,QAAQ,GAAG,YAAY,WAAW,WAAW,EAC7C,KAAK,CAAC,UAAU,IAAI;CACvB,OAAO,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI;AAC/C;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,iBAAiB,OAAO;CAC7E,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,EAAE,KAAK,IAAI;CACtG,OAAO;EACL,IAAI,OAAO;EACX,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI;EAClD,GAAG,SAAS,SAAS,KAAK,YAAY,IAAI;GACxC,QAAQ,gBAAgB,QAAQ;GAChC,WAAW,SAAS,UAAU;GAC9B,WAAW,SAAS,OAAO;GAC3B,WAAW,SAAS,MAAM;GAC1B,aAAa,OAAO;GACpB,oBAAoB,OAAO;EAC7B,CAAC,CAAC;CACJ,EAAE,KAAK,IAAI;AACb"}
package/dist/cli.cjs CHANGED
@@ -73,7 +73,7 @@ function optionalScamTopologyActivityPolicy(value) {
73
73
  async function withGraphMcpClient(name, fn) {
74
74
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
75
75
  const config = await loadConfig();
76
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-DRJq31u_.cjs")).then((n) => n.client_exports);
76
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-ByXzwNum.cjs")).then((n) => n.client_exports);
77
77
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
78
78
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
79
79
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -93,7 +93,7 @@ function printMcpTextContent(result) {
93
93
  }
94
94
  async function printNetworkCapabilities(opts) {
95
95
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
96
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-C1-Y-VZx.cjs"));
96
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-BAZ16MFI.cjs"));
97
97
  const document = await fetchNetworkCapabilities(await loadConfig());
98
98
  if (opts.json) console.log(JSON.stringify(document, null, 2));
99
99
  else console.log(formatNetworkCapabilities(document));
@@ -261,7 +261,7 @@ program.command("config").description("Read or write configuration values").addC
261
261
  })).addCommand(new commander.Command("set").argument("<key>", "Config key to write").argument("<value>", "Value to set").action(async (key, value) => {
262
262
  if (key === "walletPrivateKey") {
263
263
  try {
264
- const { setWalletPrivateKey } = await Promise.resolve().then(() => require("./wallet-TAlNMvIM.cjs")).then((n) => n.wallet_exports);
264
+ const { setWalletPrivateKey } = await Promise.resolve().then(() => require("./wallet-gC2jxh7j.cjs")).then((n) => n.wallet_exports);
265
265
  const address = await setWalletPrivateKey(value);
266
266
  console.log("Wallet private key encrypted and stored in ~/.chain-insights/wallet.json");
267
267
  console.log(`Wallet address: ${address}`);
@@ -285,9 +285,19 @@ program.command("config").description("Read or write configuration values").addC
285
285
  const displayed = key.toLowerCase().includes("token") ? "[redacted]" : coerced;
286
286
  console.log(`Set ${key} = ${displayed}`);
287
287
  }));
288
- program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new commander.Command("address").description("Print the local payment wallet address").action(async () => {
288
+ 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").action(async (privateKey) => {
289
289
  try {
290
- const { getWalletAccount } = await Promise.resolve().then(() => require("./tools-kqWI7jPU.cjs")).then((n) => n.tools_exports);
290
+ const { setWalletPrivateKey } = await Promise.resolve().then(() => require("./wallet-gC2jxh7j.cjs")).then((n) => n.wallet_exports);
291
+ const address = await setWalletPrivateKey(privateKey);
292
+ console.log(`Wallet imported: ${address}`);
293
+ console.log("Next: run `chain-insights wallet ready`");
294
+ } catch (err) {
295
+ console.error(err.message);
296
+ process.exit(1);
297
+ }
298
+ })).addCommand(new commander.Command("address").description("Print the local payment wallet address").action(async () => {
299
+ try {
300
+ const { getWalletAccount } = await Promise.resolve().then(() => require("./tools-BhTI3Lmg.cjs")).then((n) => n.tools_exports);
291
301
  const account = await getWalletAccount();
292
302
  console.log(account.address);
293
303
  } catch (err) {
@@ -296,7 +306,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
296
306
  }
297
307
  })).addCommand(new commander.Command("balance").description("Show the local payment wallet Base USDC balance").action(async () => {
298
308
  try {
299
- const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-kqWI7jPU.cjs")).then((n) => n.tools_exports);
309
+ const { getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-BhTI3Lmg.cjs")).then((n) => n.tools_exports);
300
310
  console.log(await getWalletBalanceText());
301
311
  } catch (err) {
302
312
  console.error(err.message);
@@ -304,7 +314,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
304
314
  }
305
315
  })).addCommand(new commander.Command("ready").description("Check and prepare the wallet for paid GraphRAG MCP 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) => {
306
316
  try {
307
- const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await Promise.resolve().then(() => require("./tools-kqWI7jPU.cjs")).then((n) => n.tools_exports);
317
+ const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await Promise.resolve().then(() => require("./tools-BhTI3Lmg.cjs")).then((n) => n.tools_exports);
308
318
  const result = await prepareWalletForPaidCalls({
309
319
  minimumApprovalUnits: parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? "1"),
310
320
  approve: opts.checkOnly ? false : opts.approve !== false
@@ -320,7 +330,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
320
330
  }
321
331
  })).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) => {
322
332
  try {
323
- const { buildTopupInfo, getWalletAccount } = await Promise.resolve().then(() => require("./tools-kqWI7jPU.cjs")).then((n) => n.tools_exports);
333
+ const { buildTopupInfo, getWalletAccount } = await Promise.resolve().then(() => require("./tools-BhTI3Lmg.cjs")).then((n) => n.tools_exports);
324
334
  const { startTopupServer } = await Promise.resolve().then(() => require("./topup-server-DhYlOOBM.cjs")).then((n) => n.topup_server_exports);
325
335
  const account = await getWalletAccount();
326
336
  const url = await startTopupServer(account);
@@ -355,7 +365,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
355
365
  const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
356
366
  const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-iAVQV3t0.cjs")).then((n) => n.tool_visibility_exports);
357
367
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
358
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-DRJq31u_.cjs")).then((n) => n.client_exports);
368
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-ByXzwNum.cjs")).then((n) => n.client_exports);
359
369
  const config = await loadConfig();
360
370
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
361
371
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -738,7 +748,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
738
748
  console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
739
749
  process.exit(1);
740
750
  }
741
- const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-Ckl96RcN.cjs"));
751
+ const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-BKHImisp.cjs"));
742
752
  await PlaybookRunner.run(definition, {
743
753
  caseId: opts.case,
744
754
  from: fromN,
package/dist/cli.mjs CHANGED
@@ -71,7 +71,7 @@ function optionalScamTopologyActivityPolicy(value) {
71
71
  async function withGraphMcpClient(name, fn) {
72
72
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
73
73
  const config = await loadConfig();
74
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-Bfw9P9uA.mjs").then((n) => n.n);
74
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-7vkBVEIj.mjs").then((n) => n.n);
75
75
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
76
76
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
77
77
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -91,7 +91,7 @@ function printMcpTextContent(result) {
91
91
  }
92
92
  async function printNetworkCapabilities(opts) {
93
93
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
94
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BCm-2oBt.mjs");
94
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-CYv7k4wI.mjs");
95
95
  const document = await fetchNetworkCapabilities(await loadConfig());
96
96
  if (opts.json) console.log(JSON.stringify(document, null, 2));
97
97
  else console.log(formatNetworkCapabilities(document));
@@ -259,7 +259,7 @@ program.command("config").description("Read or write configuration values").addC
259
259
  })).addCommand(new Command("set").argument("<key>", "Config key to write").argument("<value>", "Value to set").action(async (key, value) => {
260
260
  if (key === "walletPrivateKey") {
261
261
  try {
262
- const { setWalletPrivateKey } = await import("./wallet-D8IqFRKY.mjs").then((n) => n.s);
262
+ const { setWalletPrivateKey } = await import("./wallet-BL0fJC29.mjs").then((n) => n.s);
263
263
  const address = await setWalletPrivateKey(value);
264
264
  console.log("Wallet private key encrypted and stored in ~/.chain-insights/wallet.json");
265
265
  console.log(`Wallet address: ${address}`);
@@ -283,9 +283,19 @@ program.command("config").description("Read or write configuration values").addC
283
283
  const displayed = key.toLowerCase().includes("token") ? "[redacted]" : coerced;
284
284
  console.log(`Set ${key} = ${displayed}`);
285
285
  }));
286
- program.command("wallet").description("Manage the local Base USDC payment wallet").addCommand(new Command("address").description("Print the local payment wallet address").action(async () => {
286
+ 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").action(async (privateKey) => {
287
287
  try {
288
- const { getWalletAccount } = await import("./tools-6emZlUwg.mjs").then((n) => n.c);
288
+ const { setWalletPrivateKey } = await import("./wallet-BL0fJC29.mjs").then((n) => n.s);
289
+ const address = await setWalletPrivateKey(privateKey);
290
+ console.log(`Wallet imported: ${address}`);
291
+ console.log("Next: run `chain-insights wallet ready`");
292
+ } catch (err) {
293
+ console.error(err.message);
294
+ process.exit(1);
295
+ }
296
+ })).addCommand(new Command("address").description("Print the local payment wallet address").action(async () => {
297
+ try {
298
+ const { getWalletAccount } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
289
299
  const account = await getWalletAccount();
290
300
  console.log(account.address);
291
301
  } catch (err) {
@@ -294,7 +304,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
294
304
  }
295
305
  })).addCommand(new Command("balance").description("Show the local payment wallet Base USDC balance").action(async () => {
296
306
  try {
297
- const { getWalletBalanceText } = await import("./tools-6emZlUwg.mjs").then((n) => n.c);
307
+ const { getWalletBalanceText } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
298
308
  console.log(await getWalletBalanceText());
299
309
  } catch (err) {
300
310
  console.error(err.message);
@@ -302,7 +312,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
302
312
  }
303
313
  })).addCommand(new Command("ready").description("Check and prepare the wallet for paid GraphRAG MCP 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) => {
304
314
  try {
305
- const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import("./tools-6emZlUwg.mjs").then((n) => n.c);
315
+ const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
306
316
  const result = await prepareWalletForPaidCalls({
307
317
  minimumApprovalUnits: parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? "1"),
308
318
  approve: opts.checkOnly ? false : opts.approve !== false
@@ -318,7 +328,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
318
328
  }
319
329
  })).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) => {
320
330
  try {
321
- const { buildTopupInfo, getWalletAccount } = await import("./tools-6emZlUwg.mjs").then((n) => n.c);
331
+ const { buildTopupInfo, getWalletAccount } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
322
332
  const { startTopupServer } = await import("./topup-server-R3dNp-p8.mjs").then((n) => n.r);
323
333
  const account = await getWalletAccount();
324
334
  const url = await startTopupServer(account);
@@ -353,7 +363,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
353
363
  const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
354
364
  const { visibleRemoteTools } = await import("./tool-visibility-BHRFLXuU.mjs").then((n) => n.n);
355
365
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
356
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-Bfw9P9uA.mjs").then((n) => n.n);
366
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-7vkBVEIj.mjs").then((n) => n.n);
357
367
  const config = await loadConfig();
358
368
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
359
369
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -736,7 +746,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
736
746
  console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
737
747
  process.exit(1);
738
748
  }
739
- const { PlaybookRunner } = await import("./runner-C-QgZu-S.mjs");
749
+ const { PlaybookRunner } = await import("./runner-B-9g4X1q.mjs");
740
750
  await PlaybookRunner.run(definition, {
741
751
  caseId: opts.case,
742
752
  from: fromN,
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { Command, Option } from 'commander'\nimport { execFileSync } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport { PACKAGE_INFO, PACKAGE_VERSION } from './version.js'\n\n// Resolve bin/install.cjs relative to this file's location in dist/\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst installerPath = path.resolve(__dirname, '..', 'bin', 'install.cjs')\n\nconst program = new Command()\n\nprogram\n .name('chain-insights')\n .description('AML investigation toolkit for blockchain analysis')\n .version(PACKAGE_INFO.version)\n .option('--claude', 'Install Claude Code skills globally to ~/.claude/skills/')\n .option('--codex', 'Install Codex skills globally to ~/.codex/skills/ and register MCP')\n .option('--hermes', 'Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP')\n\n// Handle installer flags when invoked with no subcommand (bare `chain-insights --claude`)\nconst rawArgs = process.argv.slice(2)\nconst installerFlags = rawArgs.filter(a => a === '--claude' || a === '--codex' || a === '--hermes')\nif (installerFlags.length > 0 && !rawArgs.some(a => !a.startsWith('-'))) {\n try {\n execFileSync(process.execPath, [installerPath, ...installerFlags], { stdio: 'inherit' })\n } catch (err) {\n console.error('Installation failed:', (err as Error).message)\n process.exit(1)\n }\n process.exit(0)\n}\n\nif (rawArgs[0] === 'mcp' && rawArgs[1] === 'trace-funds') {\n console.error(\"error: unknown command 'trace-funds'\")\n process.exit(1)\n}\n\nasync function resolveCaseSelector(input: string): Promise<string> {\n const { resolveCaseSelector } = await import('./cases/selector.js')\n return resolveCaseSelector(input)\n}\n\nasync function scopeCasesToInvocationDir(): Promise<void> {\n if (process.env['CHAIN_INSIGHTS_CASES_ROOT']?.trim()) return\n const { activeCasesRoot } = await import('./workspace/active.js')\n process.env['CHAIN_INSIGHTS_CASES_ROOT'] = activeCasesRoot()\n}\n\nasync function showCaseContext(caseSelector: string): Promise<void> {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const ctx = await CaseStore.loadContext(caseId)\n console.log(`\\n=== Case: ${ctx.case.id} ===`)\n console.log(`Name: ${ctx.case.name}`)\n console.log(`Status: ${ctx.case.status}`)\n console.log(`Tags: ${ctx.case.tags.join(', ') || 'none'}`)\n console.log(`Evidence files: ${ctx.evidenceCount}`)\n console.log(`Dossiers: ${ctx.dossierSummaries.length}`)\n if (ctx.lastSession) {\n console.log(`\\n--- Last Session (${ctx.lastSession.sessionId}) ---`)\n console.log(ctx.lastSession.body.slice(0, 500))\n } else {\n console.log('\\nNo previous sessions.')\n }\n if (ctx.dossierSummaries.length > 0) {\n console.log('\\n--- Entity Dossiers ---')\n for (const d of ctx.dossierSummaries) {\n console.log(` ${d.address} [${d.type}] tags: ${d.riskTags || 'none'}`)\n }\n }\n}\n\nfunction optionalNumber(value: string | undefined): number | undefined {\n if (value === undefined) return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed)) throw new Error(`Invalid number: ${value}`)\n return parsed\n}\n\nfunction optionalNumberArg(value: unknown, name: string): number | undefined {\n if (value === undefined) return undefined\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') return optionalNumber(value)\n throw new Error(`Invalid number for ${name}: ${String(value)}`)\n}\n\ntype ScamTopologyActivityPolicyModeArg = 'node_relative_only' | 'global_incident_only'\n\nfunction optionalScamTopologyActivityPolicy(value: unknown): ScamTopologyActivityPolicyModeArg | undefined {\n if (value === undefined || value === null || value === '') return undefined\n if (value === 'node_relative_only' || value === 'global_incident_only') return value\n throw new Error('activity_policy must be one of: node_relative_only, global_incident_only')\n}\n\nasync function withGraphMcpClient<T>(name: string, fn: (client: import('@modelcontextprotocol/sdk/client/index.js').Client, config: Awaited<ReturnType<typeof import('./config/index.js').loadConfig>>) => Promise<T>): Promise<T> {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./mcp/client.js')\n const paymentFetch = await createConfiguredGraphMcpFetch(config)\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js')\n const client = new Client({ name, version: PACKAGE_VERSION })\n await client.connect(new StreamableHTTPClientTransport(new URL(resolveGraphMcpEndpoint(config)), { fetch: paymentFetch }))\n try {\n return await fn(client, config)\n } finally {\n await client.close()\n }\n}\n\nfunction printMcpTextContent(result: { content?: Array<{ type: string; text?: string }> }): void {\n for (const item of result.content ?? []) {\n if (item.type === 'text') console.log(item.text)\n }\n}\n\nasync function printNetworkCapabilities(opts: { json?: boolean }): Promise<void> {\n const { loadConfig } = await import('./config/index.js')\n const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import('./mcp/capabilities.js')\n const document = await fetchNetworkCapabilities(await loadConfig())\n if (opts.json) {\n console.log(JSON.stringify(document, null, 2))\n } else {\n console.log(formatNetworkCapabilities(document))\n }\n}\n\nprogram\n .command('networks')\n .alias('network')\n .description('List supported graph networks, capability layers, retention, and freshness')\n .option('--json', 'Print raw capability JSON')\n .action(async (opts: { json?: boolean }) => {\n try {\n await printNetworkCapabilities(opts)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('serve')\n .description('Start local visualization server')\n .option('-p, --port <number>', 'Port to bind (default: 4321)', '4321')\n .action(async (opts: { port: string }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n const workspaceRoot = requireWorkspaceRoot()\n const { startServer } = await import('./server/index.js')\n console.log(`Workspace: ${workspaceRoot}`)\n startServer(parseInt(opts.port, 10))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('status')\n .description('Show toolkit status and configuration')\n .action(async () => {\n const { loadConfig } = await import('./config/index.js')\n const { findActiveWorkspace, activeDataDir } = await import('./workspace/active.js')\n const config = await loadConfig()\n const workspace = findActiveWorkspace()\n const graphMcpStatus = config.graphMcpMode === 'debug' && config.graphMcpAuthToken?.trim()\n ? 'bearer access mode'\n : `${config.graphMcpMode} mode`\n console.log('Config: ', activeDataDir(config.dataDir))\n if (workspace) console.log('Workspace:', workspace.root)\n console.log('Server: ', `http://127.0.0.1:${config.serverPort}`)\n console.log('Graph MCP:', graphMcpStatus)\n console.log('Graph endpoint:', config.graphMcpEndpoint)\n })\n\nprogram\n .command('debug')\n .description('Configure Graph MCP debug mode')\n .addCommand(\n new Command('on')\n .description('Enable Graph MCP debug mode without x402 payments')\n .requiredOption('--token <token>', 'Debug bearer token')\n .option('--endpoint <url>', 'Graph MCP endpoint')\n .action(async (opts: { token: string; endpoint?: string }) => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({\n graphMcpMode: 'debug',\n graphMcpAuthToken: opts.token,\n ...(opts.endpoint ? { graphMcpEndpoint: opts.endpoint } : {}),\n })\n console.log('Graph MCP debug mode enabled')\n if (opts.endpoint) console.log(`Graph endpoint: ${opts.endpoint}`)\n console.log('Payments: disabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('off')\n .description('Disable Graph MCP debug mode and use paid x402 calls')\n .action(async () => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({ graphMcpMode: 'paid', graphMcpAuthToken: '' })\n console.log('Graph MCP debug mode disabled')\n console.log('Payments: enabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('status')\n .description('Show Graph MCP payment/debug mode')\n .action(async () => {\n try {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n console.log(`Graph MCP mode: ${config.graphMcpMode}`)\n console.log(`Graph endpoint: ${config.graphMcpEndpoint}`)\n console.log(`Debug token: ${config.graphMcpAuthToken?.trim() ? 'configured' : 'not configured'}`)\n console.log(`Payments: ${config.graphMcpMode === 'debug' ? 'disabled' : 'enabled'}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('access-key')\n .description('Configure Graph MCP test access key mode')\n .addCommand(\n new Command('set')\n .description('Use a Graph MCP test access key without x402 payments')\n .argument('<key>', 'Test access key')\n .option('--endpoint <url>', 'Graph MCP endpoint')\n .action(async (key: string, opts: { endpoint?: string }) => {\n try {\n const normalizedKey = key.trim()\n if (!normalizedKey) throw new Error('Test access key is required')\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({\n graphMcpMode: 'debug',\n graphMcpAuthToken: normalizedKey,\n ...(opts.endpoint ? { graphMcpEndpoint: opts.endpoint } : {}),\n })\n console.log('Graph MCP test access key configured')\n if (opts.endpoint) console.log(`Graph endpoint: ${opts.endpoint}`)\n console.log('Payments: disabled when the server accepts this key')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('clear')\n .description('Remove the Graph MCP test access key and use paid x402 calls')\n .action(async () => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({ graphMcpMode: 'paid', graphMcpAuthToken: '' })\n console.log('Graph MCP test access key cleared')\n console.log('Payments: enabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('status')\n .description('Show Graph MCP test access key status')\n .action(async () => {\n try {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n console.log(`Graph endpoint: ${config.graphMcpEndpoint}`)\n console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? 'configured' : 'not configured'}`)\n console.log(`Payments: ${config.graphMcpAuthToken?.trim() ? 'disabled when accepted by server' : 'enabled'}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('init')\n .description('Initialize an investigation workspace')\n .argument('[dir]', 'Workspace directory to initialize', '.')\n .option('--force', 'Overwrite existing workspace files')\n .action(async (dir: string, opts: { force?: boolean }) => {\n try {\n const { initWorkspace } = await import('./workspace/init.js')\n const result = await initWorkspace({ targetDir: dir, force: opts.force })\n console.log(`Workspace initialized: ${result.workspaceRoot}`)\n console.log(`Files written: ${result.filesWritten.length}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('setup')\n .description('Configure external MCP clients')\n .addCommand(\n new Command('claude-desktop')\n .alias('claude')\n .description('Install or update the Claude Desktop MCP server entry')\n .option('--config <path>', 'Path to claude_desktop_config.json')\n .option('--dry-run', 'Print the intended change without writing files')\n .action(async (opts: { config?: string; dryRun?: boolean }) => {\n try {\n const { setupClaudeDesktop } = await import('./claude-desktop/setup.js')\n const result = await setupClaudeDesktop({\n configPath: opts.config,\n dryRun: opts.dryRun,\n })\n\n console.log(`Claude Desktop config: ${result.configPath}`)\n console.log('MCP server: chain-insights')\n console.log(`Command: ${result.command}`)\n console.log(`Args: ${result.args.join(' ')}`)\n if (result.dryRun) {\n console.log(`Dry run: ${result.changed ? 'would update config' : 'already up to date'}`)\n } else if (result.changed) {\n console.log(`Updated: yes`)\n if (result.backupPath) console.log(`Backup: ${result.backupPath}`)\n } else {\n console.log('Updated: already up to date')\n }\n console.log('Reload required: quit and reopen Claude Desktop; it does not hot-reload MCP config.')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('config')\n .description('Read or write configuration values')\n .addCommand(\n new Command('get')\n .argument('<key>', 'Config key to read')\n .action(async (key: string) => {\n const { loadConfig } = await import('./config/index.js')\n const { CONFIG_KEYS } = await import('./config/schema.js')\n if (!CONFIG_KEYS.includes(key as typeof CONFIG_KEYS[number])) {\n console.error(`Unknown config key: ${key}`)\n process.exit(1)\n }\n const config = await loadConfig()\n const value = (config as Record<string, unknown>)[key]\n console.log(value ?? '')\n })\n )\n .addCommand(\n new Command('set')\n .argument('<key>', 'Config key to write')\n .argument('<value>', 'Value to set')\n .action(async (key: string, value: string) => {\n // D-01: walletPrivateKey is intercepted before saveConfig — the raw private key\n // must NEVER be written to config.json.\n if (key === 'walletPrivateKey') {\n try {\n const { setWalletPrivateKey } = await import('./wallet/index.js')\n const address = await setWalletPrivateKey(value)\n console.log('Wallet private key encrypted and stored in ~/.chain-insights/wallet.json')\n console.log(`Wallet address: ${address}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return // MUST return — walletPrivateKey must never reach saveConfig or config.json\n }\n const { loadConfig, saveConfig } = await import('./config/index.js')\n const { CONFIG_KEYS, DEFAULT_CONFIG } = await import('./config/schema.js')\n const current = await loadConfig()\n if (!CONFIG_KEYS.includes(key as typeof CONFIG_KEYS[number])) {\n console.error(`Unknown config key: ${key}`)\n process.exit(1)\n }\n const existing = (current as Record<string, unknown>)[key]\n const defaultValue = (DEFAULT_CONFIG as Record<string, unknown>)[key]\n const coerced = typeof existing === 'number' || typeof defaultValue === 'number' ? Number(value) : value\n await saveConfig({ [key]: coerced } as Parameters<typeof saveConfig>[0])\n const displayed = key.toLowerCase().includes('token') ? '[redacted]' : coerced\n console.log(`Set ${key} = ${displayed}`)\n })\n )\n\nprogram\n .command('wallet')\n .description('Manage the local Base USDC payment wallet')\n .addCommand(\n new Command('address')\n .description('Print the local payment wallet address')\n .action(async () => {\n try {\n const { getWalletAccount } = await import('./wallet/tools.js')\n const account = await getWalletAccount()\n console.log(account.address)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('balance')\n .description('Show the local payment wallet Base USDC balance')\n .action(async () => {\n try {\n const { getWalletBalanceText } = await import('./wallet/tools.js')\n console.log(await getWalletBalanceText())\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('ready')\n .description('Check and prepare the wallet for paid GraphRAG MCP calls')\n .option('--check-only', 'Only check readiness; do not submit the one-time payment setup')\n .addOption(new Option('--no-approve', 'Deprecated alias for --check-only').hideHelp())\n .option('--payment-usdc <amount>', 'USDC setup cap to prepare for paid calls', '1')\n .addOption(new Option('--approval-usdc <amount>', 'Deprecated alias for --payment-usdc').hideHelp())\n .option('--json', 'Print machine-readable readiness metadata')\n .action(async (opts: { checkOnly?: boolean; approve?: boolean; paymentUsdc?: string; approvalUsdc?: string; json?: boolean }) => {\n try {\n const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import('./wallet/tools.js')\n const minimumApprovalUnits = parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? '1')\n const result = await prepareWalletForPaidCalls({\n minimumApprovalUnits,\n approve: opts.checkOnly ? false : opts.approve !== false,\n })\n\n if (opts.json) {\n console.log(JSON.stringify(result, (_key, value) => (\n typeof value === 'bigint' ? value.toString() : value\n ), 2))\n return\n }\n\n console.log(formatWalletReadiness(result.readiness, result.approval))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('topup')\n .description('Open a local browser page to top up the payment wallet')\n .option('--no-open', 'Print the top-up URL without opening a browser')\n .option('--json', 'Print machine-readable top-up metadata')\n .action(async (opts: { open?: boolean; json?: boolean }) => {\n try {\n const { buildTopupInfo, getWalletAccount } = await import('./wallet/tools.js')\n const { startTopupServer } = await import('./wallet/topup-server.js')\n const account = await getWalletAccount()\n const url = await startTopupServer(account)\n const info = buildTopupInfo(account.address, url)\n\n if (opts.json) {\n console.log(JSON.stringify(info, null, 2))\n } else {\n console.log(`Top-up URL: ${url}`)\n console.log(`Wallet: ${account.address}`)\n console.log('Network: Base')\n console.log('Token: USDC')\n console.log('Press Ctrl+C to stop the top-up server.')\n }\n\n if (opts.open !== false) {\n const open = (await import('open')).default\n await open(url)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('mcp')\n .description('Interact with the Chain Insights MCP endpoint')\n .allowExcessArguments(false)\n .addCommand(\n new Command('networks')\n .description('List supported graph networks, capability layers, retention, and freshness')\n .option('--json', 'Print raw capability JSON')\n .action(async (opts: { json?: boolean }) => {\n try {\n await printNetworkCapabilities(opts)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('tools')\n .description('List available MCP tools (cached 24h)')\n .option('--refresh', 'Force refresh schema cache')\n .action(async (opts: { refresh?: boolean }) => {\n try {\n const { loadSchema, saveSchema } = await import('./mcp/schema-cache.js')\n const { formatToolsTable } = await import('./mcp/format.js')\n const { visibleRemoteTools } = await import('./mcp/tool-visibility.js')\n const { loadConfig } = await import('./config/index.js')\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./mcp/client.js')\n const config = await loadConfig()\n const graphMcpEndpoint = resolveGraphMcpEndpoint(config)\n let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint)\n if (!tools) {\n const paymentFetch = await createConfiguredGraphMcpFetch(config)\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js')\n const client = new Client({ name: 'chain-insights-cli', version: PACKAGE_VERSION })\n await client.connect(new StreamableHTTPClientTransport(new URL(graphMcpEndpoint), { fetch: paymentFetch }))\n try {\n const result = await client.listTools()\n tools = result.tools as Array<{ name: string; description?: string }>\n await saveSchema(tools, graphMcpEndpoint)\n } finally {\n await client.close()\n }\n }\n console.log(formatToolsTable(visibleRemoteTools(tools)))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('address-risk')\n .description('Screen an address for risk, exchange behavior, and optional compare_address connection risk')\n .requiredOption('--address <address>', 'Full blockchain address to screen')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--compare-address <address>', 'Optional second address for connection-risk compare mode')\n .option('--remote', 'Force remote MCP tool call instead of local Chain Insights recipe')\n .action(async (opts: { address: string; network: string; compareAddress?: string; remote?: boolean }) => {\n try {\n await withGraphMcpClient('chain-insights-cli-address-risk', async (client) => {\n if (opts.remote) {\n const result = await client.callTool({\n name: 'address_risk',\n arguments: {\n address: opts.address,\n network: opts.network,\n ...(opts.compareAddress ? { compare_address: opts.compareAddress } : {}),\n },\n })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n return\n }\n const { addressRisk } = await import('./investigation/public-tools.js')\n const result = await addressRisk(client, {\n address: opts.address,\n network: opts.network,\n compareAddress: opts.compareAddress,\n })\n console.log(result.summaryText)\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('track-funds')\n .description('Trace trusted/victim addresses and optional known untrusted/scammer addresses')\n .requiredOption('--trusted-addresses <addresses>', 'Comma-separated full trusted/victim addresses, max 5')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--untrusted-addresses <addresses>', 'Comma-separated full known untrusted/scammer addresses, max 5')\n .option('--case <id>', 'Case ID to attach compact evidence pointers')\n .option('--max-hops <number>', 'Maximum trace hops, 1-5')\n .option('--per-address-limit <number>', 'Maximum exchange paths/results per address, 1-10')\n .option('--min-amount-sum <number>', 'Minimum r.amount_sum for traced edges')\n .option('--remote', 'Force remote MCP tool call instead of local Chain Insights recipe')\n .action(async (opts: {\n trustedAddresses: string\n network: string\n untrustedAddresses?: string\n case?: string\n maxHops?: string\n perAddressLimit?: string\n minAmountSum?: string\n remote?: boolean\n }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n requireWorkspaceRoot()\n await withGraphMcpClient('chain-insights-cli-track-funds', async (client, config) => {\n if (opts.remote) {\n const result = await client.callTool({\n name: 'track_funds',\n arguments: {\n trusted_addresses: opts.trustedAddresses,\n network: opts.network,\n ...(opts.untrustedAddresses ? { untrusted_addresses: opts.untrustedAddresses } : {}),\n },\n })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n return\n }\n const { trackFunds } = await import('./investigation/public-tools.js')\n const caseId = opts.case ? await resolveCaseSelector(opts.case) : undefined\n const result = await trackFunds(client, config, {\n trustedAddresses: opts.trustedAddresses,\n untrustedAddresses: opts.untrustedAddresses,\n network: opts.network,\n caseId,\n maxHops: optionalNumber(opts.maxHops),\n perAddressLimit: optionalNumber(opts.perAddressLimit),\n minAmountSum: optionalNumber(opts.minAmountSum),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('scam-topology')\n .description('Build victim-incident scam topology and ML-ready scam labels')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .requiredOption('--victim-address <address>', 'Full victim/source address that anchors the incident')\n .requiredOption('--incident-timestamp-ms <milliseconds>', 'Earliest known incident transfer timestamp in milliseconds')\n .option('--max-hops <number>', 'Maximum trace hops, default 16, max 64')\n .option('--activity-policy <mode>', 'Traversal activity policy: node_relative_only or global_incident_only', 'node_relative_only')\n .option('--case <id>', 'Case ID to attach compact evidence pointers')\n .action(async (opts: {\n network: string\n victimAddress: string\n incidentTimestampMs: string\n maxHops?: string\n activityPolicy?: string\n case?: string\n }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n requireWorkspaceRoot()\n await withGraphMcpClient('chain-insights-cli-scam-topology', async (client, config) => {\n const { scamTopology } = await import('./investigation/public-tools.js')\n const incidentTimestampMs = optionalNumber(opts.incidentTimestampMs)\n if (incidentTimestampMs === undefined) throw new Error('incident-timestamp-ms is required')\n const caseId = opts.case ? await resolveCaseSelector(opts.case) : undefined\n const result = await scamTopology(client, config, {\n victimAddress: opts.victimAddress,\n network: opts.network,\n maxHops: optionalNumber(opts.maxHops),\n incidentTimestampMs,\n activityPolicyMode: optionalScamTopologyActivityPolicy(opts.activityPolicy),\n caseId,\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('stake-insights')\n .description('Explain Bittensor staking behavior around an address, coldkey, or hotkey')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--address <address>', 'Full Bittensor address to inspect as either coldkey or hotkey')\n .option('--coldkey <address>', 'Full Bittensor coldkey address to inspect')\n .option('--hotkey <address>', 'Full Bittensor hotkey address to inspect')\n .option('--netuid <number>', 'Optional subnet netuid filter')\n .option('--start-timestamp-ms <milliseconds>', 'Optional inclusive lower activity timestamp bound')\n .option('--end-timestamp-ms <milliseconds>', 'Optional inclusive upper activity timestamp bound')\n .option('--start-block <number>', 'Optional start block. Current stake graph parity may require timestamp windows instead.')\n .option('--end-block <number>', 'Optional end block. Current stake graph parity may require timestamp windows instead.')\n .option('--depth <number>', 'Optional expansion depth limit, default 1, max 3')\n .action(async (opts: {\n network: string\n address?: string\n coldkey?: string\n hotkey?: string\n netuid?: string\n startTimestampMs?: string\n endTimestampMs?: string\n startBlock?: string\n endBlock?: string\n depth?: string\n }) => {\n try {\n await withGraphMcpClient('chain-insights-cli-stake-insights', async (client) => {\n const { stakeInsights } = await import('./investigation/public-tools.js')\n const result = await stakeInsights(client, {\n network: opts.network,\n address: opts.address,\n coldkey: opts.coldkey,\n hotkey: opts.hotkey,\n netuid: optionalNumber(opts.netuid),\n startTimestampMs: optionalNumber(opts.startTimestampMs),\n endTimestampMs: optionalNumber(opts.endTimestampMs),\n startBlock: optionalNumber(opts.startBlock),\n endBlock: optionalNumber(opts.endBlock),\n depth: optionalNumber(opts.depth),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('call')\n .description('Call an MCP tool directly (debug)')\n .argument('<tool>', 'Tool name to call')\n .argument('[args...]', 'Key=value arguments (e.g. address=0x1234 chain=ethereum)')\n .action(async (tool: string, rawArgs: string[]) => {\n try {\n const { parseMcpCallArgs } = await import('./mcp/call-args.js')\n const { assertPublicMcpToolName } = await import('./mcp/tool-visibility.js')\n const args = parseMcpCallArgs(rawArgs)\n assertPublicMcpToolName(tool)\n await withGraphMcpClient('chain-insights-cli-call', async (client, config) => {\n if (tool === 'address_risk') {\n const { addressRisk } = await import('./investigation/public-tools.js')\n const result = await addressRisk(client, {\n address: String(args['address'] ?? ''),\n network: String(args['network'] ?? ''),\n compareAddress: args['compare_address'] === undefined ? undefined : String(args['compare_address']),\n })\n console.log(result.summaryText)\n return\n }\n if (tool === 'track_funds') {\n const { trackFunds } = await import('./investigation/public-tools.js')\n const result = await trackFunds(client, config, {\n trustedAddresses: args['trusted_addresses'] as string | string[] | undefined ?? '',\n untrustedAddresses: args['untrusted_addresses'] as string | string[] | undefined,\n network: String(args['network'] ?? ''),\n caseId: args['case_id'] === undefined ? undefined : String(args['case_id']),\n maxHops: typeof args['max_hops'] === 'number' ? args['max_hops'] : undefined,\n perAddressLimit: typeof args['per_address_limit'] === 'number' ? args['per_address_limit'] : undefined,\n minAmountSum: typeof args['min_amount_sum'] === 'number' ? args['min_amount_sum'] : undefined,\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n if (tool === 'scam_topology') {\n const { scamTopology } = await import('./investigation/public-tools.js')\n const victimAddress = String(args['victim_address'] ?? '').trim()\n if (!victimAddress) throw new Error('victim_address is required')\n const incidentTimestampMs = optionalNumberArg(args['incident_timestamp_ms'], 'incident_timestamp_ms')\n if (incidentTimestampMs === undefined) throw new Error('incident_timestamp_ms is required')\n const result = await scamTopology(client, config, {\n victimAddress,\n network: String(args['network'] ?? ''),\n caseId: args['case_id'] === undefined ? undefined : String(args['case_id']),\n maxHops: typeof args['max_hops'] === 'number' ? args['max_hops'] : undefined,\n incidentTimestampMs,\n activityPolicyMode: optionalScamTopologyActivityPolicy(args['activity_policy']),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n if (tool === 'stake_insights') {\n const { stakeInsights } = await import('./investigation/public-tools.js')\n const result = await stakeInsights(client, {\n network: String(args['network'] ?? ''),\n address: args['address'] === undefined ? undefined : String(args['address']),\n coldkey: args['coldkey'] === undefined ? undefined : String(args['coldkey']),\n hotkey: args['hotkey'] === undefined ? undefined : String(args['hotkey']),\n netuid: optionalNumberArg(args['netuid'], 'netuid'),\n startTimestampMs: optionalNumberArg(args['start_timestamp_ms'], 'start_timestamp_ms'),\n endTimestampMs: optionalNumberArg(args['end_timestamp_ms'], 'end_timestamp_ms'),\n startBlock: optionalNumberArg(args['start_block'], 'start_block'),\n endBlock: optionalNumberArg(args['end_block'], 'end_block'),\n depth: optionalNumberArg(args['depth'] ?? args['max_hops'], 'depth'),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n const result = await client.callTool({ name: tool, arguments: args })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nconst caseCommand = new Command('case')\n .description('Manage investigation cases')\n .hook('preAction', async () => {\n await scopeCasesToInvocationDir()\n })\n .addCommand(\n new Command('open')\n .description('Open a new investigation case')\n .argument('<name>', 'Case name (e.g. \"Tornado Mixer Investigation\")')\n .option('--tags <tags>', 'Comma-separated tags (e.g. aml,mixer,defi)', '')\n .option('--description <desc>', 'Brief description of the investigation', '')\n .action(async (name: string, opts: { tags: string; description: string }) => {\n try {\n if (/^[1-9]\\d*$/.test(name.trim())) {\n throw new Error('Numeric case names look like list selectors. Use a descriptive case name, e.g. `cia case open \"Tracking stolen funds from <address>\"`.')\n }\n const { CaseStore } = await import('./cases/index.js')\n const tags = opts.tags ? opts.tags.split(',').map(t => t.trim()).filter(Boolean) : []\n const c = await CaseStore.create({ name, tags, description: opts.description })\n const { casesRoot } = await import('./cases/store.js')\n console.log(`Case opened: ${c.id}`)\n console.log(`Directory: ${path.join(casesRoot(), c.id)}/`)\n console.log(`Status: ${c.status}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('activate')\n .description('Activate a case (set status to active)')\n .argument('<case-id>', 'Case ID to activate')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'active')\n console.log(`Case ${c.id} is now: active`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('suspend')\n .description('Suspend a case (set status to suspended)')\n .argument('<case-id>', 'Case ID to suspend')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'suspended')\n console.log(`Case ${c.id} is now: suspended`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('close')\n .description('Close a case permanently')\n .argument('<case-id>', 'Case ID to close')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'closed')\n console.log(`Case ${c.id} is now: closed`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('list')\n .description('List all investigation cases')\n .option('--status <status>', 'Filter by status (open|active|suspended|closed)')\n .action(async (opts: { status?: string }) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const cases = await CaseStore.list()\n const filtered = opts.status ? cases.filter(c => c.status === opts.status) : cases\n if (filtered.length === 0) {\n console.log('No cases found.')\n return\n }\n for (const [index, c] of filtered.entries()) {\n console.log(`${index + 1}. ${c.id} [${c.status}] ${c.name}`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('evidence')\n .description('Manage case evidence')\n .addCommand(\n new Command('add')\n .description('Add evidence to a case from an MCP query result')\n .argument('<case-id>', 'Case ID to add evidence to')\n .option('--source <tool>', 'MCP tool name that produced this evidence', 'manual')\n .option('--content <text>', 'Evidence content (MCP response or notes)', '')\n .option('--query-params <params>', 'Query parameters used (e.g. address=0x1234)', '')\n .action(async (caseSelector: string, opts: { source: string; content: string; queryParams: string }) => {\n try {\n const { EvidenceStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const result = await EvidenceStore.append(caseId, {\n source: opts.source,\n content: opts.content,\n queryParams: opts.queryParams,\n })\n console.log(`Evidence saved: ${result.filename}`)\n console.log(`SHA-256: ${result.sha256}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('verify')\n .description('Verify evidence manifest integrity for a case')\n .argument('<case-id>', 'Case ID to verify')\n .action(async (caseSelector: string) => {\n try {\n const { EvidenceStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const result = await EvidenceStore.verifyManifest(caseId)\n if (result.ok) {\n console.log(`Manifest OK — ${result.count} evidence file(s) verified`)\n } else {\n console.error(`Manifest FAILED — tampered files: ${(result.tampered ?? []).join(', ')}`)\n process.exit(1)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('dossier')\n .description('Manage entity dossiers for a case')\n .addCommand(\n new Command('update')\n .description('Append a finding to an entity dossier')\n .argument('<case-id>', 'Case ID')\n .argument('<address>', 'Entity address or identifier')\n .option('--finding <text>', 'Finding to append to the dossier', '')\n .option('--type <type>', 'Entity type (eoa|contract|exchange|mixer|unknown)', 'unknown')\n .action(async (caseSelector: string, address: string, opts: { finding: string; type: string }) => {\n try {\n const { DossierStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const validTypes = ['eoa', 'contract', 'exchange', 'mixer', 'unknown'] as const\n const entityType = validTypes.includes(opts.type as typeof validTypes[number])\n ? (opts.type as typeof validTypes[number])\n : 'unknown'\n await DossierStore.appendFinding(caseId, address, opts.finding, entityType)\n console.log(`Dossier updated for ${address}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('session')\n .description('Manage investigation sessions')\n .addCommand(\n new Command('start')\n .description('Start a new investigation session for a case')\n .argument('<case-id>', 'Case ID')\n .argument('[title...]', 'Optional session title')\n .action(async (caseSelector: string, titleParts: string[]) => {\n try {\n const { SessionStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const title = titleParts.join(' ').trim()\n const s = await SessionStore.start(caseId, title ? { title } : {})\n console.log(`Session started: ${s.sessionId}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('end')\n .description('End the current session with findings and next steps')\n .argument('<case-id>', 'Case ID')\n .option('--findings <text>', 'Key findings from this session', '')\n .option('--next-steps <text>', 'Next steps for the investigation', '')\n .action(async (caseSelector: string, opts: { findings: string; nextSteps: string }) => {\n try {\n const { SessionStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n await SessionStore.end(caseId, { findings: opts.findings, nextSteps: opts.nextSteps })\n await SessionStore.archiveOldSessions(caseId)\n console.log(`Session ended for case ${caseId}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('show')\n .description('Show saved case context')\n .argument('<case-id>', 'Case ID or case list number to show')\n .action(async (caseSelector: string) => {\n try {\n await showCaseContext(caseSelector)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram.addCommand(caseCommand)\n\nprogram\n .command('playbook')\n .description('Run and manage investigation playbooks')\n .addCommand(\n new Command('run')\n .description('Execute a playbook by name')\n .argument('<name>', 'Playbook name (e.g. trace-funds, risk-check, entity-profile)')\n .option('--case <id>', 'Case ID to attach evidence to (auto-created if omitted)')\n .option('--from <n>', 'Resume from step N (1-based)', '1')\n .option('--dry-run', 'Show steps without executing')\n .option('-p, --param <kv...>', 'Parameters as key=value pairs (repeatable, e.g. -p address=0x1 -p hops=3)')\n .action(async (name: string, opts: { case?: string; from: string; dryRun?: boolean; param?: string[] }) => {\n try {\n // 1. Parse --param key=value pairs into Record<string,string> — split on first '=' only (T-05-06)\n const resolvedParams: Record<string, string> = {}\n for (const kv of (opts.param ?? [])) {\n const eq = kv.indexOf('=')\n if (eq === -1) {\n console.error(`Invalid param format: \"${kv}\". Use key=value`)\n process.exit(1)\n }\n const key = kv.slice(0, eq)\n if (!key) {\n console.error(`Invalid param format: \"${kv}\". Key must be non-empty`)\n process.exit(1)\n }\n resolvedParams[key] = kv.slice(eq + 1)\n }\n // 2. Resolve playbook content (user-dir first, built-in fallback)\n const { resolvePlaybookContent } = await import('./playbooks/resolver.js')\n const markdown = await resolvePlaybookContent(name)\n // 3. Parse markdown → PlaybookDefinition\n const { PlaybookParser } = await import('./playbooks/parser.js')\n const definition = PlaybookParser.parse(markdown, resolvedParams)\n // 4. Validate required params are provided\n for (const spec of definition.params) {\n if (spec.required && !resolvedParams[spec.name] && !spec.default) {\n console.error(`Missing required param: ${spec.name}. Pass with: -p ${spec.name}=<value>`)\n process.exit(1)\n }\n }\n // 5. Validate --from value\n const fromN = parseInt(opts.from, 10)\n if (isNaN(fromN) || fromN < 1) {\n console.error(`Invalid --from value: \"${opts.from}\". Must be a positive integer.`)\n process.exit(1)\n }\n // 6. Run\n const { PlaybookRunner } = await import('./playbooks/runner.js')\n await PlaybookRunner.run(definition, {\n caseId: opts.case,\n from: fromN,\n dryRun: opts.dryRun,\n params: resolvedParams,\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('list')\n .description('List available playbooks (built-in and user-defined)')\n .action(async () => {\n try {\n const { listPlaybooks } = await import('./playbooks/resolver.js')\n const playbooks = await listPlaybooks()\n if (playbooks.length === 0) { console.log('No playbooks found.'); return }\n for (const p of playbooks) {\n console.log(` ${p.name.padEnd(20)} [${p.source}]`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('show')\n .description('Show steps for a playbook without executing')\n .argument('<name>', 'Playbook name')\n .action(async (name: string) => {\n try {\n const { resolvePlaybookContent } = await import('./playbooks/resolver.js')\n const { PlaybookParser } = await import('./playbooks/parser.js')\n const markdown = await resolvePlaybookContent(name)\n const definition = PlaybookParser.parse(markdown, {})\n console.log(`Playbook: ${definition.name} v${definition.version}`)\n console.log(`${definition.description}\\n`)\n console.log(`Parameters:`)\n for (const p of definition.params) {\n const req = p.required ? '(required)' : `(optional, default: ${p.default ?? 'none'})`\n console.log(` ${p.name}: ${p.type} ${req}`)\n }\n console.log(`\\nSteps:`)\n for (const step of definition.steps) {\n console.log(` ${step.index}. ${step.label} → tool: ${step.tool}`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('viz')\n .description('Generate money flow visualization')\n .argument('[case-id]', 'Case ID to visualize')\n .option('--data <file>', 'Raw transaction JSON file for ad-hoc visualization')\n .option('-p, --port <number>', 'Server port', '4321')\n .action(async (caseId: string | undefined, opts: { data?: string; port: string }) => {\n try {\n if (!caseId && !opts.data) {\n console.error('Provide either a case ID or --data <file.json>')\n process.exit(1)\n }\n const { generateVisualization } = await import('./viz/index.js')\n const result = await generateVisualization({ caseId, dataFile: opts.data })\n const { startServer } = await import('./server/index.js')\n const port = parseInt(opts.port, 10)\n startServer(port)\n const url = `http://127.0.0.1:${port}/viz/${result.vizId}`\n console.log(`Visualization: ${url}`)\n const open = (await import('open')).default\n await open(url)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram.parse(process.argv)\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["import { Command, Option } from 'commander'\nimport { execFileSync } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport { PACKAGE_INFO, PACKAGE_VERSION } from './version.js'\n\n// Resolve bin/install.cjs relative to this file's location in dist/\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst installerPath = path.resolve(__dirname, '..', 'bin', 'install.cjs')\n\nconst program = new Command()\n\nprogram\n .name('chain-insights')\n .description('AML investigation toolkit for blockchain analysis')\n .version(PACKAGE_INFO.version)\n .option('--claude', 'Install Claude Code skills globally to ~/.claude/skills/')\n .option('--codex', 'Install Codex skills globally to ~/.codex/skills/ and register MCP')\n .option('--hermes', 'Install Hermes skills globally to ~/.hermes/skills/chain-insights/ and register MCP')\n\n// Handle installer flags when invoked with no subcommand (bare `chain-insights --claude`)\nconst rawArgs = process.argv.slice(2)\nconst installerFlags = rawArgs.filter(a => a === '--claude' || a === '--codex' || a === '--hermes')\nif (installerFlags.length > 0 && !rawArgs.some(a => !a.startsWith('-'))) {\n try {\n execFileSync(process.execPath, [installerPath, ...installerFlags], { stdio: 'inherit' })\n } catch (err) {\n console.error('Installation failed:', (err as Error).message)\n process.exit(1)\n }\n process.exit(0)\n}\n\nif (rawArgs[0] === 'mcp' && rawArgs[1] === 'trace-funds') {\n console.error(\"error: unknown command 'trace-funds'\")\n process.exit(1)\n}\n\nasync function resolveCaseSelector(input: string): Promise<string> {\n const { resolveCaseSelector } = await import('./cases/selector.js')\n return resolveCaseSelector(input)\n}\n\nasync function scopeCasesToInvocationDir(): Promise<void> {\n if (process.env['CHAIN_INSIGHTS_CASES_ROOT']?.trim()) return\n const { activeCasesRoot } = await import('./workspace/active.js')\n process.env['CHAIN_INSIGHTS_CASES_ROOT'] = activeCasesRoot()\n}\n\nasync function showCaseContext(caseSelector: string): Promise<void> {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const ctx = await CaseStore.loadContext(caseId)\n console.log(`\\n=== Case: ${ctx.case.id} ===`)\n console.log(`Name: ${ctx.case.name}`)\n console.log(`Status: ${ctx.case.status}`)\n console.log(`Tags: ${ctx.case.tags.join(', ') || 'none'}`)\n console.log(`Evidence files: ${ctx.evidenceCount}`)\n console.log(`Dossiers: ${ctx.dossierSummaries.length}`)\n if (ctx.lastSession) {\n console.log(`\\n--- Last Session (${ctx.lastSession.sessionId}) ---`)\n console.log(ctx.lastSession.body.slice(0, 500))\n } else {\n console.log('\\nNo previous sessions.')\n }\n if (ctx.dossierSummaries.length > 0) {\n console.log('\\n--- Entity Dossiers ---')\n for (const d of ctx.dossierSummaries) {\n console.log(` ${d.address} [${d.type}] tags: ${d.riskTags || 'none'}`)\n }\n }\n}\n\nfunction optionalNumber(value: string | undefined): number | undefined {\n if (value === undefined) return undefined\n const parsed = Number(value)\n if (!Number.isFinite(parsed)) throw new Error(`Invalid number: ${value}`)\n return parsed\n}\n\nfunction optionalNumberArg(value: unknown, name: string): number | undefined {\n if (value === undefined) return undefined\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') return optionalNumber(value)\n throw new Error(`Invalid number for ${name}: ${String(value)}`)\n}\n\ntype ScamTopologyActivityPolicyModeArg = 'node_relative_only' | 'global_incident_only'\n\nfunction optionalScamTopologyActivityPolicy(value: unknown): ScamTopologyActivityPolicyModeArg | undefined {\n if (value === undefined || value === null || value === '') return undefined\n if (value === 'node_relative_only' || value === 'global_incident_only') return value\n throw new Error('activity_policy must be one of: node_relative_only, global_incident_only')\n}\n\nasync function withGraphMcpClient<T>(name: string, fn: (client: import('@modelcontextprotocol/sdk/client/index.js').Client, config: Awaited<ReturnType<typeof import('./config/index.js').loadConfig>>) => Promise<T>): Promise<T> {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./mcp/client.js')\n const paymentFetch = await createConfiguredGraphMcpFetch(config)\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js')\n const client = new Client({ name, version: PACKAGE_VERSION })\n await client.connect(new StreamableHTTPClientTransport(new URL(resolveGraphMcpEndpoint(config)), { fetch: paymentFetch }))\n try {\n return await fn(client, config)\n } finally {\n await client.close()\n }\n}\n\nfunction printMcpTextContent(result: { content?: Array<{ type: string; text?: string }> }): void {\n for (const item of result.content ?? []) {\n if (item.type === 'text') console.log(item.text)\n }\n}\n\nasync function printNetworkCapabilities(opts: { json?: boolean }): Promise<void> {\n const { loadConfig } = await import('./config/index.js')\n const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import('./mcp/capabilities.js')\n const document = await fetchNetworkCapabilities(await loadConfig())\n if (opts.json) {\n console.log(JSON.stringify(document, null, 2))\n } else {\n console.log(formatNetworkCapabilities(document))\n }\n}\n\nprogram\n .command('networks')\n .alias('network')\n .description('List supported graph networks, capability layers, retention, and freshness')\n .option('--json', 'Print raw capability JSON')\n .action(async (opts: { json?: boolean }) => {\n try {\n await printNetworkCapabilities(opts)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('serve')\n .description('Start local visualization server')\n .option('-p, --port <number>', 'Port to bind (default: 4321)', '4321')\n .action(async (opts: { port: string }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n const workspaceRoot = requireWorkspaceRoot()\n const { startServer } = await import('./server/index.js')\n console.log(`Workspace: ${workspaceRoot}`)\n startServer(parseInt(opts.port, 10))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('status')\n .description('Show toolkit status and configuration')\n .action(async () => {\n const { loadConfig } = await import('./config/index.js')\n const { findActiveWorkspace, activeDataDir } = await import('./workspace/active.js')\n const config = await loadConfig()\n const workspace = findActiveWorkspace()\n const graphMcpStatus = config.graphMcpMode === 'debug' && config.graphMcpAuthToken?.trim()\n ? 'bearer access mode'\n : `${config.graphMcpMode} mode`\n console.log('Config: ', activeDataDir(config.dataDir))\n if (workspace) console.log('Workspace:', workspace.root)\n console.log('Server: ', `http://127.0.0.1:${config.serverPort}`)\n console.log('Graph MCP:', graphMcpStatus)\n console.log('Graph endpoint:', config.graphMcpEndpoint)\n })\n\nprogram\n .command('debug')\n .description('Configure Graph MCP debug mode')\n .addCommand(\n new Command('on')\n .description('Enable Graph MCP debug mode without x402 payments')\n .requiredOption('--token <token>', 'Debug bearer token')\n .option('--endpoint <url>', 'Graph MCP endpoint')\n .action(async (opts: { token: string; endpoint?: string }) => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({\n graphMcpMode: 'debug',\n graphMcpAuthToken: opts.token,\n ...(opts.endpoint ? { graphMcpEndpoint: opts.endpoint } : {}),\n })\n console.log('Graph MCP debug mode enabled')\n if (opts.endpoint) console.log(`Graph endpoint: ${opts.endpoint}`)\n console.log('Payments: disabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('off')\n .description('Disable Graph MCP debug mode and use paid x402 calls')\n .action(async () => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({ graphMcpMode: 'paid', graphMcpAuthToken: '' })\n console.log('Graph MCP debug mode disabled')\n console.log('Payments: enabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('status')\n .description('Show Graph MCP payment/debug mode')\n .action(async () => {\n try {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n console.log(`Graph MCP mode: ${config.graphMcpMode}`)\n console.log(`Graph endpoint: ${config.graphMcpEndpoint}`)\n console.log(`Debug token: ${config.graphMcpAuthToken?.trim() ? 'configured' : 'not configured'}`)\n console.log(`Payments: ${config.graphMcpMode === 'debug' ? 'disabled' : 'enabled'}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('access-key')\n .description('Configure Graph MCP test access key mode')\n .addCommand(\n new Command('set')\n .description('Use a Graph MCP test access key without x402 payments')\n .argument('<key>', 'Test access key')\n .option('--endpoint <url>', 'Graph MCP endpoint')\n .action(async (key: string, opts: { endpoint?: string }) => {\n try {\n const normalizedKey = key.trim()\n if (!normalizedKey) throw new Error('Test access key is required')\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({\n graphMcpMode: 'debug',\n graphMcpAuthToken: normalizedKey,\n ...(opts.endpoint ? { graphMcpEndpoint: opts.endpoint } : {}),\n })\n console.log('Graph MCP test access key configured')\n if (opts.endpoint) console.log(`Graph endpoint: ${opts.endpoint}`)\n console.log('Payments: disabled when the server accepts this key')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('clear')\n .description('Remove the Graph MCP test access key and use paid x402 calls')\n .action(async () => {\n try {\n const { saveConfig } = await import('./config/index.js')\n await saveConfig({ graphMcpMode: 'paid', graphMcpAuthToken: '' })\n console.log('Graph MCP test access key cleared')\n console.log('Payments: enabled for Graph MCP calls')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('status')\n .description('Show Graph MCP test access key status')\n .action(async () => {\n try {\n const { loadConfig } = await import('./config/index.js')\n const config = await loadConfig()\n console.log(`Graph endpoint: ${config.graphMcpEndpoint}`)\n console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? 'configured' : 'not configured'}`)\n console.log(`Payments: ${config.graphMcpAuthToken?.trim() ? 'disabled when accepted by server' : 'enabled'}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('init')\n .description('Initialize an investigation workspace')\n .argument('[dir]', 'Workspace directory to initialize', '.')\n .option('--force', 'Overwrite existing workspace files')\n .action(async (dir: string, opts: { force?: boolean }) => {\n try {\n const { initWorkspace } = await import('./workspace/init.js')\n const result = await initWorkspace({ targetDir: dir, force: opts.force })\n console.log(`Workspace initialized: ${result.workspaceRoot}`)\n console.log(`Files written: ${result.filesWritten.length}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram\n .command('setup')\n .description('Configure external MCP clients')\n .addCommand(\n new Command('claude-desktop')\n .alias('claude')\n .description('Install or update the Claude Desktop MCP server entry')\n .option('--config <path>', 'Path to claude_desktop_config.json')\n .option('--dry-run', 'Print the intended change without writing files')\n .action(async (opts: { config?: string; dryRun?: boolean }) => {\n try {\n const { setupClaudeDesktop } = await import('./claude-desktop/setup.js')\n const result = await setupClaudeDesktop({\n configPath: opts.config,\n dryRun: opts.dryRun,\n })\n\n console.log(`Claude Desktop config: ${result.configPath}`)\n console.log('MCP server: chain-insights')\n console.log(`Command: ${result.command}`)\n console.log(`Args: ${result.args.join(' ')}`)\n if (result.dryRun) {\n console.log(`Dry run: ${result.changed ? 'would update config' : 'already up to date'}`)\n } else if (result.changed) {\n console.log(`Updated: yes`)\n if (result.backupPath) console.log(`Backup: ${result.backupPath}`)\n } else {\n console.log('Updated: already up to date')\n }\n console.log('Reload required: quit and reopen Claude Desktop; it does not hot-reload MCP config.')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('config')\n .description('Read or write configuration values')\n .addCommand(\n new Command('get')\n .argument('<key>', 'Config key to read')\n .action(async (key: string) => {\n const { loadConfig } = await import('./config/index.js')\n const { CONFIG_KEYS } = await import('./config/schema.js')\n if (!CONFIG_KEYS.includes(key as typeof CONFIG_KEYS[number])) {\n console.error(`Unknown config key: ${key}`)\n process.exit(1)\n }\n const config = await loadConfig()\n const value = (config as Record<string, unknown>)[key]\n console.log(value ?? '')\n })\n )\n .addCommand(\n new Command('set')\n .argument('<key>', 'Config key to write')\n .argument('<value>', 'Value to set')\n .action(async (key: string, value: string) => {\n // D-01: walletPrivateKey is intercepted before saveConfig — the raw private key\n // must NEVER be written to config.json.\n if (key === 'walletPrivateKey') {\n try {\n const { setWalletPrivateKey } = await import('./wallet/index.js')\n const address = await setWalletPrivateKey(value)\n console.log('Wallet private key encrypted and stored in ~/.chain-insights/wallet.json')\n console.log(`Wallet address: ${address}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n return // MUST return — walletPrivateKey must never reach saveConfig or config.json\n }\n const { loadConfig, saveConfig } = await import('./config/index.js')\n const { CONFIG_KEYS, DEFAULT_CONFIG } = await import('./config/schema.js')\n const current = await loadConfig()\n if (!CONFIG_KEYS.includes(key as typeof CONFIG_KEYS[number])) {\n console.error(`Unknown config key: ${key}`)\n process.exit(1)\n }\n const existing = (current as Record<string, unknown>)[key]\n const defaultValue = (DEFAULT_CONFIG as Record<string, unknown>)[key]\n const coerced = typeof existing === 'number' || typeof defaultValue === 'number' ? Number(value) : value\n await saveConfig({ [key]: coerced } as Parameters<typeof saveConfig>[0])\n const displayed = key.toLowerCase().includes('token') ? '[redacted]' : coerced\n console.log(`Set ${key} = ${displayed}`)\n })\n )\n\nprogram\n .command('wallet')\n .description('Manage the local Base USDC payment wallet')\n .addCommand(\n new Command('import')\n .description('Import a Base payment wallet')\n .argument('<private-key>', '0x-prefixed EVM private key')\n .action(async (privateKey: string) => {\n try {\n const { setWalletPrivateKey } = await import('./wallet/index.js')\n const address = await setWalletPrivateKey(privateKey)\n console.log(`Wallet imported: ${address}`)\n console.log('Next: run `chain-insights wallet ready`')\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('address')\n .description('Print the local payment wallet address')\n .action(async () => {\n try {\n const { getWalletAccount } = await import('./wallet/tools.js')\n const account = await getWalletAccount()\n console.log(account.address)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('balance')\n .description('Show the local payment wallet Base USDC balance')\n .action(async () => {\n try {\n const { getWalletBalanceText } = await import('./wallet/tools.js')\n console.log(await getWalletBalanceText())\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('ready')\n .description('Check and prepare the wallet for paid GraphRAG MCP calls')\n .option('--check-only', 'Only check readiness; do not submit the one-time payment setup')\n .addOption(new Option('--no-approve', 'Deprecated alias for --check-only').hideHelp())\n .option('--payment-usdc <amount>', 'USDC setup cap to prepare for paid calls', '1')\n .addOption(new Option('--approval-usdc <amount>', 'Deprecated alias for --payment-usdc').hideHelp())\n .option('--json', 'Print machine-readable readiness metadata')\n .action(async (opts: { checkOnly?: boolean; approve?: boolean; paymentUsdc?: string; approvalUsdc?: string; json?: boolean }) => {\n try {\n const { formatWalletReadiness, parsePaymentApprovalUnits, prepareWalletForPaidCalls } = await import('./wallet/tools.js')\n const minimumApprovalUnits = parsePaymentApprovalUnits(opts.paymentUsdc ?? opts.approvalUsdc ?? '1')\n const result = await prepareWalletForPaidCalls({\n minimumApprovalUnits,\n approve: opts.checkOnly ? false : opts.approve !== false,\n })\n\n if (opts.json) {\n console.log(JSON.stringify(result, (_key, value) => (\n typeof value === 'bigint' ? value.toString() : value\n ), 2))\n return\n }\n\n console.log(formatWalletReadiness(result.readiness, result.approval))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('topup')\n .description('Open a local browser page to top up the payment wallet')\n .option('--no-open', 'Print the top-up URL without opening a browser')\n .option('--json', 'Print machine-readable top-up metadata')\n .action(async (opts: { open?: boolean; json?: boolean }) => {\n try {\n const { buildTopupInfo, getWalletAccount } = await import('./wallet/tools.js')\n const { startTopupServer } = await import('./wallet/topup-server.js')\n const account = await getWalletAccount()\n const url = await startTopupServer(account)\n const info = buildTopupInfo(account.address, url)\n\n if (opts.json) {\n console.log(JSON.stringify(info, null, 2))\n } else {\n console.log(`Top-up URL: ${url}`)\n console.log(`Wallet: ${account.address}`)\n console.log('Network: Base')\n console.log('Token: USDC')\n console.log('Press Ctrl+C to stop the top-up server.')\n }\n\n if (opts.open !== false) {\n const open = (await import('open')).default\n await open(url)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('mcp')\n .description('Interact with the Chain Insights MCP endpoint')\n .allowExcessArguments(false)\n .addCommand(\n new Command('networks')\n .description('List supported graph networks, capability layers, retention, and freshness')\n .option('--json', 'Print raw capability JSON')\n .action(async (opts: { json?: boolean }) => {\n try {\n await printNetworkCapabilities(opts)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('tools')\n .description('List available MCP tools (cached 24h)')\n .option('--refresh', 'Force refresh schema cache')\n .action(async (opts: { refresh?: boolean }) => {\n try {\n const { loadSchema, saveSchema } = await import('./mcp/schema-cache.js')\n const { formatToolsTable } = await import('./mcp/format.js')\n const { visibleRemoteTools } = await import('./mcp/tool-visibility.js')\n const { loadConfig } = await import('./config/index.js')\n const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import('./mcp/client.js')\n const config = await loadConfig()\n const graphMcpEndpoint = resolveGraphMcpEndpoint(config)\n let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint)\n if (!tools) {\n const paymentFetch = await createConfiguredGraphMcpFetch(config)\n const { Client } = await import('@modelcontextprotocol/sdk/client/index.js')\n const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js')\n const client = new Client({ name: 'chain-insights-cli', version: PACKAGE_VERSION })\n await client.connect(new StreamableHTTPClientTransport(new URL(graphMcpEndpoint), { fetch: paymentFetch }))\n try {\n const result = await client.listTools()\n tools = result.tools as Array<{ name: string; description?: string }>\n await saveSchema(tools, graphMcpEndpoint)\n } finally {\n await client.close()\n }\n }\n console.log(formatToolsTable(visibleRemoteTools(tools)))\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('address-risk')\n .description('Screen an address for risk, exchange behavior, and optional compare_address connection risk')\n .requiredOption('--address <address>', 'Full blockchain address to screen')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--compare-address <address>', 'Optional second address for connection-risk compare mode')\n .option('--remote', 'Force remote MCP tool call instead of local Chain Insights recipe')\n .action(async (opts: { address: string; network: string; compareAddress?: string; remote?: boolean }) => {\n try {\n await withGraphMcpClient('chain-insights-cli-address-risk', async (client) => {\n if (opts.remote) {\n const result = await client.callTool({\n name: 'address_risk',\n arguments: {\n address: opts.address,\n network: opts.network,\n ...(opts.compareAddress ? { compare_address: opts.compareAddress } : {}),\n },\n })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n return\n }\n const { addressRisk } = await import('./investigation/public-tools.js')\n const result = await addressRisk(client, {\n address: opts.address,\n network: opts.network,\n compareAddress: opts.compareAddress,\n })\n console.log(result.summaryText)\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('track-funds')\n .description('Trace trusted/victim addresses and optional known untrusted/scammer addresses')\n .requiredOption('--trusted-addresses <addresses>', 'Comma-separated full trusted/victim addresses, max 5')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--untrusted-addresses <addresses>', 'Comma-separated full known untrusted/scammer addresses, max 5')\n .option('--case <id>', 'Case ID to attach compact evidence pointers')\n .option('--max-hops <number>', 'Maximum trace hops, 1-5')\n .option('--per-address-limit <number>', 'Maximum exchange paths/results per address, 1-10')\n .option('--min-amount-sum <number>', 'Minimum r.amount_sum for traced edges')\n .option('--remote', 'Force remote MCP tool call instead of local Chain Insights recipe')\n .action(async (opts: {\n trustedAddresses: string\n network: string\n untrustedAddresses?: string\n case?: string\n maxHops?: string\n perAddressLimit?: string\n minAmountSum?: string\n remote?: boolean\n }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n requireWorkspaceRoot()\n await withGraphMcpClient('chain-insights-cli-track-funds', async (client, config) => {\n if (opts.remote) {\n const result = await client.callTool({\n name: 'track_funds',\n arguments: {\n trusted_addresses: opts.trustedAddresses,\n network: opts.network,\n ...(opts.untrustedAddresses ? { untrusted_addresses: opts.untrustedAddresses } : {}),\n },\n })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n return\n }\n const { trackFunds } = await import('./investigation/public-tools.js')\n const caseId = opts.case ? await resolveCaseSelector(opts.case) : undefined\n const result = await trackFunds(client, config, {\n trustedAddresses: opts.trustedAddresses,\n untrustedAddresses: opts.untrustedAddresses,\n network: opts.network,\n caseId,\n maxHops: optionalNumber(opts.maxHops),\n perAddressLimit: optionalNumber(opts.perAddressLimit),\n minAmountSum: optionalNumber(opts.minAmountSum),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('scam-topology')\n .description('Build victim-incident scam topology and ML-ready scam labels')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .requiredOption('--victim-address <address>', 'Full victim/source address that anchors the incident')\n .requiredOption('--incident-timestamp-ms <milliseconds>', 'Earliest known incident transfer timestamp in milliseconds')\n .option('--max-hops <number>', 'Maximum trace hops, default 16, max 64')\n .option('--activity-policy <mode>', 'Traversal activity policy: node_relative_only or global_incident_only', 'node_relative_only')\n .option('--case <id>', 'Case ID to attach compact evidence pointers')\n .action(async (opts: {\n network: string\n victimAddress: string\n incidentTimestampMs: string\n maxHops?: string\n activityPolicy?: string\n case?: string\n }) => {\n try {\n const { requireWorkspaceRoot } = await import('./workspace/output-root.js')\n requireWorkspaceRoot()\n await withGraphMcpClient('chain-insights-cli-scam-topology', async (client, config) => {\n const { scamTopology } = await import('./investigation/public-tools.js')\n const incidentTimestampMs = optionalNumber(opts.incidentTimestampMs)\n if (incidentTimestampMs === undefined) throw new Error('incident-timestamp-ms is required')\n const caseId = opts.case ? await resolveCaseSelector(opts.case) : undefined\n const result = await scamTopology(client, config, {\n victimAddress: opts.victimAddress,\n network: opts.network,\n maxHops: optionalNumber(opts.maxHops),\n incidentTimestampMs,\n activityPolicyMode: optionalScamTopologyActivityPolicy(opts.activityPolicy),\n caseId,\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('stake-insights')\n .description('Explain Bittensor staking behavior around an address, coldkey, or hotkey')\n .requiredOption('--network <network>', 'Network to query. Run `cia mcp networks` for supported networks.')\n .option('--address <address>', 'Full Bittensor address to inspect as either coldkey or hotkey')\n .option('--coldkey <address>', 'Full Bittensor coldkey address to inspect')\n .option('--hotkey <address>', 'Full Bittensor hotkey address to inspect')\n .option('--netuid <number>', 'Optional subnet netuid filter')\n .option('--start-timestamp-ms <milliseconds>', 'Optional inclusive lower activity timestamp bound')\n .option('--end-timestamp-ms <milliseconds>', 'Optional inclusive upper activity timestamp bound')\n .option('--start-block <number>', 'Optional start block. Current stake graph parity may require timestamp windows instead.')\n .option('--end-block <number>', 'Optional end block. Current stake graph parity may require timestamp windows instead.')\n .option('--depth <number>', 'Optional expansion depth limit, default 1, max 3')\n .action(async (opts: {\n network: string\n address?: string\n coldkey?: string\n hotkey?: string\n netuid?: string\n startTimestampMs?: string\n endTimestampMs?: string\n startBlock?: string\n endBlock?: string\n depth?: string\n }) => {\n try {\n await withGraphMcpClient('chain-insights-cli-stake-insights', async (client) => {\n const { stakeInsights } = await import('./investigation/public-tools.js')\n const result = await stakeInsights(client, {\n network: opts.network,\n address: opts.address,\n coldkey: opts.coldkey,\n hotkey: opts.hotkey,\n netuid: optionalNumber(opts.netuid),\n startTimestampMs: optionalNumber(opts.startTimestampMs),\n endTimestampMs: optionalNumber(opts.endTimestampMs),\n startBlock: optionalNumber(opts.startBlock),\n endBlock: optionalNumber(opts.endBlock),\n depth: optionalNumber(opts.depth),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('call')\n .description('Call an MCP tool directly (debug)')\n .argument('<tool>', 'Tool name to call')\n .argument('[args...]', 'Key=value arguments (e.g. address=0x1234 chain=ethereum)')\n .action(async (tool: string, rawArgs: string[]) => {\n try {\n const { parseMcpCallArgs } = await import('./mcp/call-args.js')\n const { assertPublicMcpToolName } = await import('./mcp/tool-visibility.js')\n const args = parseMcpCallArgs(rawArgs)\n assertPublicMcpToolName(tool)\n await withGraphMcpClient('chain-insights-cli-call', async (client, config) => {\n if (tool === 'address_risk') {\n const { addressRisk } = await import('./investigation/public-tools.js')\n const result = await addressRisk(client, {\n address: String(args['address'] ?? ''),\n network: String(args['network'] ?? ''),\n compareAddress: args['compare_address'] === undefined ? undefined : String(args['compare_address']),\n })\n console.log(result.summaryText)\n return\n }\n if (tool === 'track_funds') {\n const { trackFunds } = await import('./investigation/public-tools.js')\n const result = await trackFunds(client, config, {\n trustedAddresses: args['trusted_addresses'] as string | string[] | undefined ?? '',\n untrustedAddresses: args['untrusted_addresses'] as string | string[] | undefined,\n network: String(args['network'] ?? ''),\n caseId: args['case_id'] === undefined ? undefined : String(args['case_id']),\n maxHops: typeof args['max_hops'] === 'number' ? args['max_hops'] : undefined,\n perAddressLimit: typeof args['per_address_limit'] === 'number' ? args['per_address_limit'] : undefined,\n minAmountSum: typeof args['min_amount_sum'] === 'number' ? args['min_amount_sum'] : undefined,\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n if (tool === 'scam_topology') {\n const { scamTopology } = await import('./investigation/public-tools.js')\n const victimAddress = String(args['victim_address'] ?? '').trim()\n if (!victimAddress) throw new Error('victim_address is required')\n const incidentTimestampMs = optionalNumberArg(args['incident_timestamp_ms'], 'incident_timestamp_ms')\n if (incidentTimestampMs === undefined) throw new Error('incident_timestamp_ms is required')\n const result = await scamTopology(client, config, {\n victimAddress,\n network: String(args['network'] ?? ''),\n caseId: args['case_id'] === undefined ? undefined : String(args['case_id']),\n maxHops: typeof args['max_hops'] === 'number' ? args['max_hops'] : undefined,\n incidentTimestampMs,\n activityPolicyMode: optionalScamTopologyActivityPolicy(args['activity_policy']),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n if (tool === 'stake_insights') {\n const { stakeInsights } = await import('./investigation/public-tools.js')\n const result = await stakeInsights(client, {\n network: String(args['network'] ?? ''),\n address: args['address'] === undefined ? undefined : String(args['address']),\n coldkey: args['coldkey'] === undefined ? undefined : String(args['coldkey']),\n hotkey: args['hotkey'] === undefined ? undefined : String(args['hotkey']),\n netuid: optionalNumberArg(args['netuid'], 'netuid'),\n startTimestampMs: optionalNumberArg(args['start_timestamp_ms'], 'start_timestamp_ms'),\n endTimestampMs: optionalNumberArg(args['end_timestamp_ms'], 'end_timestamp_ms'),\n startBlock: optionalNumberArg(args['start_block'], 'start_block'),\n endBlock: optionalNumberArg(args['end_block'], 'end_block'),\n depth: optionalNumberArg(args['depth'] ?? args['max_hops'], 'depth'),\n })\n console.log(result.summaryText)\n console.log(JSON.stringify(result.structuredContent, null, 2))\n return\n }\n const result = await client.callTool({ name: tool, arguments: args })\n printMcpTextContent(result as { content?: Array<{ type: string; text?: string }> })\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nconst caseCommand = new Command('case')\n .description('Manage investigation cases')\n .hook('preAction', async () => {\n await scopeCasesToInvocationDir()\n })\n .addCommand(\n new Command('open')\n .description('Open a new investigation case')\n .argument('<name>', 'Case name (e.g. \"Tornado Mixer Investigation\")')\n .option('--tags <tags>', 'Comma-separated tags (e.g. aml,mixer,defi)', '')\n .option('--description <desc>', 'Brief description of the investigation', '')\n .action(async (name: string, opts: { tags: string; description: string }) => {\n try {\n if (/^[1-9]\\d*$/.test(name.trim())) {\n throw new Error('Numeric case names look like list selectors. Use a descriptive case name, e.g. `cia case open \"Tracking stolen funds from <address>\"`.')\n }\n const { CaseStore } = await import('./cases/index.js')\n const tags = opts.tags ? opts.tags.split(',').map(t => t.trim()).filter(Boolean) : []\n const c = await CaseStore.create({ name, tags, description: opts.description })\n const { casesRoot } = await import('./cases/store.js')\n console.log(`Case opened: ${c.id}`)\n console.log(`Directory: ${path.join(casesRoot(), c.id)}/`)\n console.log(`Status: ${c.status}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('activate')\n .description('Activate a case (set status to active)')\n .argument('<case-id>', 'Case ID to activate')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'active')\n console.log(`Case ${c.id} is now: active`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('suspend')\n .description('Suspend a case (set status to suspended)')\n .argument('<case-id>', 'Case ID to suspend')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'suspended')\n console.log(`Case ${c.id} is now: suspended`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('close')\n .description('Close a case permanently')\n .argument('<case-id>', 'Case ID to close')\n .action(async (caseSelector: string) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const c = await CaseStore.setStatus(caseId, 'closed')\n console.log(`Case ${c.id} is now: closed`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('list')\n .description('List all investigation cases')\n .option('--status <status>', 'Filter by status (open|active|suspended|closed)')\n .action(async (opts: { status?: string }) => {\n try {\n const { CaseStore } = await import('./cases/index.js')\n const cases = await CaseStore.list()\n const filtered = opts.status ? cases.filter(c => c.status === opts.status) : cases\n if (filtered.length === 0) {\n console.log('No cases found.')\n return\n }\n for (const [index, c] of filtered.entries()) {\n console.log(`${index + 1}. ${c.id} [${c.status}] ${c.name}`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('evidence')\n .description('Manage case evidence')\n .addCommand(\n new Command('add')\n .description('Add evidence to a case from an MCP query result')\n .argument('<case-id>', 'Case ID to add evidence to')\n .option('--source <tool>', 'MCP tool name that produced this evidence', 'manual')\n .option('--content <text>', 'Evidence content (MCP response or notes)', '')\n .option('--query-params <params>', 'Query parameters used (e.g. address=0x1234)', '')\n .action(async (caseSelector: string, opts: { source: string; content: string; queryParams: string }) => {\n try {\n const { EvidenceStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const result = await EvidenceStore.append(caseId, {\n source: opts.source,\n content: opts.content,\n queryParams: opts.queryParams,\n })\n console.log(`Evidence saved: ${result.filename}`)\n console.log(`SHA-256: ${result.sha256}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('verify')\n .description('Verify evidence manifest integrity for a case')\n .argument('<case-id>', 'Case ID to verify')\n .action(async (caseSelector: string) => {\n try {\n const { EvidenceStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const result = await EvidenceStore.verifyManifest(caseId)\n if (result.ok) {\n console.log(`Manifest OK — ${result.count} evidence file(s) verified`)\n } else {\n console.error(`Manifest FAILED — tampered files: ${(result.tampered ?? []).join(', ')}`)\n process.exit(1)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('dossier')\n .description('Manage entity dossiers for a case')\n .addCommand(\n new Command('update')\n .description('Append a finding to an entity dossier')\n .argument('<case-id>', 'Case ID')\n .argument('<address>', 'Entity address or identifier')\n .option('--finding <text>', 'Finding to append to the dossier', '')\n .option('--type <type>', 'Entity type (eoa|contract|exchange|mixer|unknown)', 'unknown')\n .action(async (caseSelector: string, address: string, opts: { finding: string; type: string }) => {\n try {\n const { DossierStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const validTypes = ['eoa', 'contract', 'exchange', 'mixer', 'unknown'] as const\n const entityType = validTypes.includes(opts.type as typeof validTypes[number])\n ? (opts.type as typeof validTypes[number])\n : 'unknown'\n await DossierStore.appendFinding(caseId, address, opts.finding, entityType)\n console.log(`Dossier updated for ${address}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('session')\n .description('Manage investigation sessions')\n .addCommand(\n new Command('start')\n .description('Start a new investigation session for a case')\n .argument('<case-id>', 'Case ID')\n .argument('[title...]', 'Optional session title')\n .action(async (caseSelector: string, titleParts: string[]) => {\n try {\n const { SessionStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n const title = titleParts.join(' ').trim()\n const s = await SessionStore.start(caseId, title ? { title } : {})\n console.log(`Session started: ${s.sessionId}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('end')\n .description('End the current session with findings and next steps')\n .argument('<case-id>', 'Case ID')\n .option('--findings <text>', 'Key findings from this session', '')\n .option('--next-steps <text>', 'Next steps for the investigation', '')\n .action(async (caseSelector: string, opts: { findings: string; nextSteps: string }) => {\n try {\n const { SessionStore } = await import('./cases/index.js')\n const caseId = await resolveCaseSelector(caseSelector)\n await SessionStore.end(caseId, { findings: opts.findings, nextSteps: opts.nextSteps })\n await SessionStore.archiveOldSessions(caseId)\n console.log(`Session ended for case ${caseId}`)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n )\n .addCommand(\n new Command('show')\n .description('Show saved case context')\n .argument('<case-id>', 'Case ID or case list number to show')\n .action(async (caseSelector: string) => {\n try {\n await showCaseContext(caseSelector)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram.addCommand(caseCommand)\n\nprogram\n .command('playbook')\n .description('Run and manage investigation playbooks')\n .addCommand(\n new Command('run')\n .description('Execute a playbook by name')\n .argument('<name>', 'Playbook name (e.g. trace-funds, risk-check, entity-profile)')\n .option('--case <id>', 'Case ID to attach evidence to (auto-created if omitted)')\n .option('--from <n>', 'Resume from step N (1-based)', '1')\n .option('--dry-run', 'Show steps without executing')\n .option('-p, --param <kv...>', 'Parameters as key=value pairs (repeatable, e.g. -p address=0x1 -p hops=3)')\n .action(async (name: string, opts: { case?: string; from: string; dryRun?: boolean; param?: string[] }) => {\n try {\n // 1. Parse --param key=value pairs into Record<string,string> — split on first '=' only (T-05-06)\n const resolvedParams: Record<string, string> = {}\n for (const kv of (opts.param ?? [])) {\n const eq = kv.indexOf('=')\n if (eq === -1) {\n console.error(`Invalid param format: \"${kv}\". Use key=value`)\n process.exit(1)\n }\n const key = kv.slice(0, eq)\n if (!key) {\n console.error(`Invalid param format: \"${kv}\". Key must be non-empty`)\n process.exit(1)\n }\n resolvedParams[key] = kv.slice(eq + 1)\n }\n // 2. Resolve playbook content (user-dir first, built-in fallback)\n const { resolvePlaybookContent } = await import('./playbooks/resolver.js')\n const markdown = await resolvePlaybookContent(name)\n // 3. Parse markdown → PlaybookDefinition\n const { PlaybookParser } = await import('./playbooks/parser.js')\n const definition = PlaybookParser.parse(markdown, resolvedParams)\n // 4. Validate required params are provided\n for (const spec of definition.params) {\n if (spec.required && !resolvedParams[spec.name] && !spec.default) {\n console.error(`Missing required param: ${spec.name}. Pass with: -p ${spec.name}=<value>`)\n process.exit(1)\n }\n }\n // 5. Validate --from value\n const fromN = parseInt(opts.from, 10)\n if (isNaN(fromN) || fromN < 1) {\n console.error(`Invalid --from value: \"${opts.from}\". Must be a positive integer.`)\n process.exit(1)\n }\n // 6. Run\n const { PlaybookRunner } = await import('./playbooks/runner.js')\n await PlaybookRunner.run(definition, {\n caseId: opts.case,\n from: fromN,\n dryRun: opts.dryRun,\n params: resolvedParams,\n })\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('list')\n .description('List available playbooks (built-in and user-defined)')\n .action(async () => {\n try {\n const { listPlaybooks } = await import('./playbooks/resolver.js')\n const playbooks = await listPlaybooks()\n if (playbooks.length === 0) { console.log('No playbooks found.'); return }\n for (const p of playbooks) {\n console.log(` ${p.name.padEnd(20)} [${p.source}]`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n .addCommand(\n new Command('show')\n .description('Show steps for a playbook without executing')\n .argument('<name>', 'Playbook name')\n .action(async (name: string) => {\n try {\n const { resolvePlaybookContent } = await import('./playbooks/resolver.js')\n const { PlaybookParser } = await import('./playbooks/parser.js')\n const markdown = await resolvePlaybookContent(name)\n const definition = PlaybookParser.parse(markdown, {})\n console.log(`Playbook: ${definition.name} v${definition.version}`)\n console.log(`${definition.description}\\n`)\n console.log(`Parameters:`)\n for (const p of definition.params) {\n const req = p.required ? '(required)' : `(optional, default: ${p.default ?? 'none'})`\n console.log(` ${p.name}: ${p.type} ${req}`)\n }\n console.log(`\\nSteps:`)\n for (const step of definition.steps) {\n console.log(` ${step.index}. ${step.label} → tool: ${step.tool}`)\n }\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n )\n\nprogram\n .command('viz')\n .description('Generate money flow visualization')\n .argument('[case-id]', 'Case ID to visualize')\n .option('--data <file>', 'Raw transaction JSON file for ad-hoc visualization')\n .option('-p, --port <number>', 'Server port', '4321')\n .action(async (caseId: string | undefined, opts: { data?: string; port: string }) => {\n try {\n if (!caseId && !opts.data) {\n console.error('Provide either a case ID or --data <file.json>')\n process.exit(1)\n }\n const { generateVisualization } = await import('./viz/index.js')\n const result = await generateVisualization({ caseId, dataFile: opts.data })\n const { startServer } = await import('./server/index.js')\n const port = parseInt(opts.port, 10)\n startServer(port)\n const url = `http://127.0.0.1:${port}/viz/${result.vizId}`\n console.log(`Visualization: ${url}`)\n const open = (await import('open')).default\n await open(url)\n } catch (err) {\n console.error((err as Error).message)\n process.exit(1)\n }\n })\n\nprogram.parse(process.argv)\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { s as prepareWalletForPaidCalls } from "./tools-6emZlUwg.mjs";
2
+ import { s as prepareWalletForPaidCalls } from "./tools-v6kcdojg.mjs";
3
3
  import { privateKeyToAccount } from "viem/accounts";
4
4
  import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
5
5
  import { ExactEvmScheme } from "@x402/evm";
@@ -139,8 +139,8 @@ function resolveGraphMcpEndpoint(config) {
139
139
  async function createConfiguredFetchWithToken(authToken, missingTokenName) {
140
140
  const normalizedAuthToken = authToken?.trim();
141
141
  if (normalizedAuthToken) return createMcpAuthFetchClient(normalizedAuthToken);
142
- const { isWalletConfigured, decryptKey } = await import("./wallet-D8IqFRKY.mjs").then((n) => n.s);
143
- if (!await isWalletConfigured()) throw new Error(`Wallet not configured and ${missingTokenName} is empty. Run \`chain-insights access-key set <key>\` for invited test access or \`chain-insights config set ${missingTokenName} <token>\` for local MCP debug bypass, or \`chain-insights config set walletPrivateKey <key>\` to enable paid x402 MCP calls.`);
142
+ const { isWalletConfigured, decryptKey } = await import("./wallet-BL0fJC29.mjs").then((n) => n.s);
143
+ if (!await isWalletConfigured()) throw new Error("Hosted access is not configured. Run `chain-insights access-key set <key>` for invited test access. For wallet-paid access, run `chain-insights wallet import <private-key>` once, then run `chain-insights wallet ready`; run `chain-insights wallet topup` if it says the wallet needs funds.");
144
144
  return createMcpFetchClient(await decryptKey());
145
145
  }
146
146
  async function createConfiguredMcpFetch(config) {
@@ -157,4 +157,4 @@ async function createConfiguredGraphMcpFetch(config) {
157
157
  //#endregion
158
158
  export { resolveGraphMcpEndpoint as a, createMcpFetchClient as i, client_exports as n, createConfiguredMcpFetch as r, PaymentRequiredError as t };
159
159
 
160
- //# sourceMappingURL=client-Bfw9P9uA.mjs.map
160
+ //# sourceMappingURL=client-7vkBVEIj.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-Bfw9P9uA.mjs","names":[],"sources":["../src/mcp/client.ts"],"sourcesContent":["import { wrapFetchWithPaymentFromConfig } from '@x402/fetch'\nimport { ExactEvmScheme } from '@x402/evm'\nimport { UptoEvmScheme } from '@x402/evm/upto/client'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { prepareWalletForPaidCalls } from '../wallet/tools.js'\n\ntype FetchLike = typeof fetch\ntype FetchInput = Parameters<FetchLike>[0]\ntype FetchInit = Parameters<FetchLike>[1]\n\nexport class PaymentRequiredError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'PaymentRequiredError'\n }\n}\n\nfunction createHeaderFetch(authToken: string, baseFetch: FetchLike): FetchLike {\n return (async (input: FetchInput, init?: FetchInit) => {\n const requestHeaders = input instanceof Request ? input.headers : undefined\n const headers = new Headers(init?.headers ?? requestHeaders)\n headers.set('X-MCP-Debug-Token', authToken)\n headers.set('Authorization', `Bearer ${authToken}`)\n\n return baseFetch(input, {\n ...init,\n headers,\n })\n }) as FetchLike\n}\n\nexport const PAYMENT_NEXT_STEPS =\n 'Next steps: run `chain-insights wallet ready` to check funding and finish one-time payment setup, ' +\n 'run `chain-insights wallet topup` if it says the wallet needs USDC, ' +\n 'or `chain-insights access-key set <key>` if you have been given test access.'\n\ninterface PaymentRequirementDetails {\n reason: string\n scheme?: string\n network?: string\n amount?: string\n amountUnits?: bigint\n payTo?: string\n}\n\nfunction paymentRequirementFromResponse(response: Response): PaymentRequirementDetails | null {\n const encoded = response.headers.get('payment-required')\n if (!encoded) return null\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf8')\n const parsed = JSON.parse(decoded) as {\n error?: unknown\n accepts?: Array<{ scheme?: unknown; network?: unknown; amount?: unknown; payTo?: unknown }>\n }\n const reason = typeof parsed.error === 'string' && parsed.error.trim() ? parsed.error.trim() : 'payment_required'\n const firstRequirement = Array.isArray(parsed.accepts) ? parsed.accepts[0] : undefined\n const amount = typeof firstRequirement?.amount === 'string' ? firstRequirement.amount.trim() : undefined\n return {\n reason,\n scheme: typeof firstRequirement?.scheme === 'string' ? firstRequirement.scheme : undefined,\n network: typeof firstRequirement?.network === 'string' ? firstRequirement.network : undefined,\n amount,\n amountUnits: amount && /^\\d+$/.test(amount) ? BigInt(amount) : undefined,\n payTo: typeof firstRequirement?.payTo === 'string' ? firstRequirement.payTo.trim() : undefined,\n }\n } catch {\n return null\n }\n}\n\nfunction describePaymentRequiredResponse(response: Response, payerAddress?: string): string {\n const requirement = paymentRequirementFromResponse(response)\n if (!requirement) return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n\n try {\n const { reason, payTo } = requirement\n if (payerAddress && payTo && payerAddress.toLowerCase() === payTo.toLowerCase()) {\n return 'Local payment wallet matches the MCP payTo address. Configure a separate payer wallet with USDC on Base; do not use the service recipient wallet as the client payment wallet.'\n }\n const details = [\n requirement.scheme ? `scheme=${requirement.scheme}` : undefined,\n requirement.network ? `network=${requirement.network}` : undefined,\n requirement.amount ? `amount=${requirement.amount}` : undefined,\n ].filter(Boolean).join(' ')\n const message = details ? `x402 payment failed: ${reason} (${details})` : `x402 payment failed: ${reason}`\n if (reason.includes('allowance_required')) {\n return `${message}. The payment wallet needs one-time setup before paid MCP calls can settle. Run \\`chain-insights wallet ready\\`; Base ETH is used for the setup gas.`\n }\n if (reason === 'payment_required') {\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n }\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n } catch {\n return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n }\n}\n\nfunction createPaymentFailureReportingFetch(\n baseFetch: FetchLike,\n payerAddress?: string,\n paymentWallet?: { address: `0x${string}`; privateKey: `0x${string}` },\n): FetchLike {\n const reportingFetch = (async (input: FetchInput, init?: FetchInit) => {\n const response = await baseFetch(input, init)\n if (response.status !== 402) return response\n const requirement = paymentRequirementFromResponse(response)\n if (paymentWallet && requirement?.reason.includes('allowance_required')) {\n try {\n await prepareWalletForPaidCalls({\n account: paymentWallet,\n ...(requirement.amountUnits === undefined ? {} : { minimumApprovalUnits: requirement.amountUnits }),\n })\n } catch (err) {\n throw new PaymentRequiredError(\n 'Payment setup is not ready yet. Run `chain-insights wallet ready` and try again. ' +\n `${(err as Error).message}`,\n )\n }\n const retryResponse = await baseFetch(input, init)\n if (retryResponse.status !== 402) return retryResponse\n throw new PaymentRequiredError(describePaymentRequiredResponse(retryResponse, payerAddress))\n }\n throw new PaymentRequiredError(describePaymentRequiredResponse(response, payerAddress))\n }) as FetchLike\n return Object.assign(reportingFetch, baseFetch)\n}\n\n/**\n * Creates an x402-payment-wrapped fetch function for the Chain Insights MCP.\n * Payments are made in USDC on Base Mainnet (eip155:8453).\n *\n * The factory is pure — no side effects, no state, no caching.\n * If called with an invalid private key format, viem throws — the error propagates.\n *\n * @param privateKey - 0x-prefixed EVM private key (decrypted from wallet.json)\n * @returns A fetch-compatible function that auto-handles HTTP 402 payment challenges\n */\nexport function createMcpFetchClient(privateKey: `0x${string}`, authToken?: string) {\n const account = privateKeyToAccount(privateKey)\n const paymentFetch = wrapFetchWithPaymentFromConfig(fetch, {\n schemes: [\n {\n network: 'eip155:8453', // Base Mainnet — dynamic MCP pricing uses the x402 upto scheme\n client: new UptoEvmScheme(account),\n },\n {\n network: 'eip155:8453', // Base Mainnet — only supported chain in v1\n client: new ExactEvmScheme(account),\n },\n ],\n })\n const reportingFetch = createPaymentFailureReportingFetch(\n paymentFetch,\n account.address,\n { address: account.address, privateKey },\n )\n return authToken ? createHeaderFetch(authToken, reportingFetch) : reportingFetch\n}\n\n/**\n * Creates a bearer/debug-token fetch for local Graph MCP testing.\n *\n * The public x402 debug bypass expects X-MCP-Debug-Token.\n * Private endpoints commonly expect Authorization: Bearer <token>.\n * Sending both lets one config value work for public debug and private M2M endpoints.\n *\n * Wraps with 402 interception so that if the server still requires payment\n * (e.g. token not accepted for paid tools), the user sees actionable guidance\n * instead of a generic transport error.\n */\nexport function createMcpAuthFetchClient(authToken: string, baseFetch: FetchLike = fetch): FetchLike {\n const headerFetch = createHeaderFetch(authToken, baseFetch)\n return createPaymentFailureReportingFetch(headerFetch)\n}\n\nexport function resolveGraphMcpEndpoint(config: Pick<InvestigatorConfig, 'graphMcpEndpoint' | 'mcpEndpoint'>): string {\n const graphEndpoint = config.graphMcpEndpoint?.trim()\n return graphEndpoint || config.mcpEndpoint\n}\n\nasync function createConfiguredFetchWithToken(\n authToken: string | undefined,\n missingTokenName: string,\n): Promise<FetchLike> {\n const normalizedAuthToken = authToken?.trim()\n if (normalizedAuthToken) return createMcpAuthFetchClient(normalizedAuthToken)\n\n const { isWalletConfigured, decryptKey } = await import('../wallet/index.js')\n if (!(await isWalletConfigured())) {\n throw new Error(\n `Wallet not configured and ${missingTokenName} is empty. ` +\n `Run \\`chain-insights access-key set <key>\\` for invited test access or \\`chain-insights config set ${missingTokenName} <token>\\` for local MCP debug bypass, ` +\n 'or `chain-insights config set walletPrivateKey <key>` to enable paid x402 MCP calls.',\n )\n }\n\n const privateKey = await decryptKey()\n return createMcpFetchClient(privateKey as `0x${string}`)\n}\n\nexport async function createConfiguredMcpFetch(config: Pick<InvestigatorConfig, 'mcpAuthToken'>): Promise<FetchLike> {\n return createConfiguredFetchWithToken(config.mcpAuthToken, 'mcpAuthToken')\n}\n\nexport async function createConfiguredGraphMcpFetch(\n config: Pick<InvestigatorConfig, 'mcpAuthToken' | 'graphMcpAuthToken' | 'graphMcpMode'>,\n): Promise<FetchLike> {\n if (config.graphMcpMode === 'debug') {\n const authToken = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim()\n if (!authToken) {\n throw new Error('Graph MCP debug mode requires graphMcpAuthToken. Run `cia access-key set <key>` or `cia debug on --token <token>`.')\n }\n return createMcpAuthFetchClient(authToken)\n }\n\n return createConfiguredFetchWithToken(undefined, 'walletPrivateKey')\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client-7vkBVEIj.mjs","names":[],"sources":["../src/mcp/client.ts"],"sourcesContent":["import { wrapFetchWithPaymentFromConfig } from '@x402/fetch'\nimport { ExactEvmScheme } from '@x402/evm'\nimport { UptoEvmScheme } from '@x402/evm/upto/client'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport type { InvestigatorConfig } from '../config/schema.js'\nimport { prepareWalletForPaidCalls } from '../wallet/tools.js'\n\ntype FetchLike = typeof fetch\ntype FetchInput = Parameters<FetchLike>[0]\ntype FetchInit = Parameters<FetchLike>[1]\n\nexport class PaymentRequiredError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'PaymentRequiredError'\n }\n}\n\nfunction createHeaderFetch(authToken: string, baseFetch: FetchLike): FetchLike {\n return (async (input: FetchInput, init?: FetchInit) => {\n const requestHeaders = input instanceof Request ? input.headers : undefined\n const headers = new Headers(init?.headers ?? requestHeaders)\n headers.set('X-MCP-Debug-Token', authToken)\n headers.set('Authorization', `Bearer ${authToken}`)\n\n return baseFetch(input, {\n ...init,\n headers,\n })\n }) as FetchLike\n}\n\nexport const PAYMENT_NEXT_STEPS =\n 'Next steps: run `chain-insights wallet ready` to check funding and finish one-time payment setup, ' +\n 'run `chain-insights wallet topup` if it says the wallet needs USDC, ' +\n 'or `chain-insights access-key set <key>` if you have been given test access.'\n\ninterface PaymentRequirementDetails {\n reason: string\n scheme?: string\n network?: string\n amount?: string\n amountUnits?: bigint\n payTo?: string\n}\n\nfunction paymentRequirementFromResponse(response: Response): PaymentRequirementDetails | null {\n const encoded = response.headers.get('payment-required')\n if (!encoded) return null\n\n try {\n const decoded = Buffer.from(encoded, 'base64').toString('utf8')\n const parsed = JSON.parse(decoded) as {\n error?: unknown\n accepts?: Array<{ scheme?: unknown; network?: unknown; amount?: unknown; payTo?: unknown }>\n }\n const reason = typeof parsed.error === 'string' && parsed.error.trim() ? parsed.error.trim() : 'payment_required'\n const firstRequirement = Array.isArray(parsed.accepts) ? parsed.accepts[0] : undefined\n const amount = typeof firstRequirement?.amount === 'string' ? firstRequirement.amount.trim() : undefined\n return {\n reason,\n scheme: typeof firstRequirement?.scheme === 'string' ? firstRequirement.scheme : undefined,\n network: typeof firstRequirement?.network === 'string' ? firstRequirement.network : undefined,\n amount,\n amountUnits: amount && /^\\d+$/.test(amount) ? BigInt(amount) : undefined,\n payTo: typeof firstRequirement?.payTo === 'string' ? firstRequirement.payTo.trim() : undefined,\n }\n } catch {\n return null\n }\n}\n\nfunction describePaymentRequiredResponse(response: Response, payerAddress?: string): string {\n const requirement = paymentRequirementFromResponse(response)\n if (!requirement) return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n\n try {\n const { reason, payTo } = requirement\n if (payerAddress && payTo && payerAddress.toLowerCase() === payTo.toLowerCase()) {\n return 'Local payment wallet matches the MCP payTo address. Configure a separate payer wallet with USDC on Base; do not use the service recipient wallet as the client payment wallet.'\n }\n const details = [\n requirement.scheme ? `scheme=${requirement.scheme}` : undefined,\n requirement.network ? `network=${requirement.network}` : undefined,\n requirement.amount ? `amount=${requirement.amount}` : undefined,\n ].filter(Boolean).join(' ')\n const message = details ? `x402 payment failed: ${reason} (${details})` : `x402 payment failed: ${reason}`\n if (reason.includes('allowance_required')) {\n return `${message}. The payment wallet needs one-time setup before paid MCP calls can settle. Run \\`chain-insights wallet ready\\`; Base ETH is used for the setup gas.`\n }\n if (reason === 'payment_required') {\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n }\n return `${message}. ${PAYMENT_NEXT_STEPS}`\n } catch {\n return `Payment required — this tool costs USDC on Base via x402 micropayments. ${PAYMENT_NEXT_STEPS}`\n }\n}\n\nfunction createPaymentFailureReportingFetch(\n baseFetch: FetchLike,\n payerAddress?: string,\n paymentWallet?: { address: `0x${string}`; privateKey: `0x${string}` },\n): FetchLike {\n const reportingFetch = (async (input: FetchInput, init?: FetchInit) => {\n const response = await baseFetch(input, init)\n if (response.status !== 402) return response\n const requirement = paymentRequirementFromResponse(response)\n if (paymentWallet && requirement?.reason.includes('allowance_required')) {\n try {\n await prepareWalletForPaidCalls({\n account: paymentWallet,\n ...(requirement.amountUnits === undefined ? {} : { minimumApprovalUnits: requirement.amountUnits }),\n })\n } catch (err) {\n throw new PaymentRequiredError(\n 'Payment setup is not ready yet. Run `chain-insights wallet ready` and try again. ' +\n `${(err as Error).message}`,\n )\n }\n const retryResponse = await baseFetch(input, init)\n if (retryResponse.status !== 402) return retryResponse\n throw new PaymentRequiredError(describePaymentRequiredResponse(retryResponse, payerAddress))\n }\n throw new PaymentRequiredError(describePaymentRequiredResponse(response, payerAddress))\n }) as FetchLike\n return Object.assign(reportingFetch, baseFetch)\n}\n\n/**\n * Creates an x402-payment-wrapped fetch function for the Chain Insights MCP.\n * Payments are made in USDC on Base Mainnet (eip155:8453).\n *\n * The factory is pure — no side effects, no state, no caching.\n * If called with an invalid private key format, viem throws — the error propagates.\n *\n * @param privateKey - 0x-prefixed EVM private key (decrypted from wallet.json)\n * @returns A fetch-compatible function that auto-handles HTTP 402 payment challenges\n */\nexport function createMcpFetchClient(privateKey: `0x${string}`, authToken?: string) {\n const account = privateKeyToAccount(privateKey)\n const paymentFetch = wrapFetchWithPaymentFromConfig(fetch, {\n schemes: [\n {\n network: 'eip155:8453', // Base Mainnet — dynamic MCP pricing uses the x402 upto scheme\n client: new UptoEvmScheme(account),\n },\n {\n network: 'eip155:8453', // Base Mainnet — only supported chain in v1\n client: new ExactEvmScheme(account),\n },\n ],\n })\n const reportingFetch = createPaymentFailureReportingFetch(\n paymentFetch,\n account.address,\n { address: account.address, privateKey },\n )\n return authToken ? createHeaderFetch(authToken, reportingFetch) : reportingFetch\n}\n\n/**\n * Creates a bearer/debug-token fetch for local Graph MCP testing.\n *\n * The public x402 debug bypass expects X-MCP-Debug-Token.\n * Private endpoints commonly expect Authorization: Bearer <token>.\n * Sending both lets one config value work for public debug and private M2M endpoints.\n *\n * Wraps with 402 interception so that if the server still requires payment\n * (e.g. token not accepted for paid tools), the user sees actionable guidance\n * instead of a generic transport error.\n */\nexport function createMcpAuthFetchClient(authToken: string, baseFetch: FetchLike = fetch): FetchLike {\n const headerFetch = createHeaderFetch(authToken, baseFetch)\n return createPaymentFailureReportingFetch(headerFetch)\n}\n\nexport function resolveGraphMcpEndpoint(config: Pick<InvestigatorConfig, 'graphMcpEndpoint' | 'mcpEndpoint'>): string {\n const graphEndpoint = config.graphMcpEndpoint?.trim()\n return graphEndpoint || config.mcpEndpoint\n}\n\nasync function createConfiguredFetchWithToken(\n authToken: string | undefined,\n missingTokenName: string,\n): Promise<FetchLike> {\n const normalizedAuthToken = authToken?.trim()\n if (normalizedAuthToken) return createMcpAuthFetchClient(normalizedAuthToken)\n\n const { isWalletConfigured, decryptKey } = await import('../wallet/index.js')\n if (!(await isWalletConfigured())) {\n throw new Error(\n 'Hosted access is not configured. ' +\n 'Run `chain-insights access-key set <key>` for invited test access. ' +\n 'For wallet-paid access, run `chain-insights wallet import <private-key>` once, then run `chain-insights wallet ready`; ' +\n 'run `chain-insights wallet topup` if it says the wallet needs funds.',\n )\n }\n\n const privateKey = await decryptKey()\n return createMcpFetchClient(privateKey as `0x${string}`)\n}\n\nexport async function createConfiguredMcpFetch(config: Pick<InvestigatorConfig, 'mcpAuthToken'>): Promise<FetchLike> {\n return createConfiguredFetchWithToken(config.mcpAuthToken, 'mcpAuthToken')\n}\n\nexport async function createConfiguredGraphMcpFetch(\n config: Pick<InvestigatorConfig, 'mcpAuthToken' | 'graphMcpAuthToken' | 'graphMcpMode'>,\n): Promise<FetchLike> {\n if (config.graphMcpMode === 'debug') {\n const authToken = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim()\n if (!authToken) {\n throw new Error('Graph MCP debug mode requires graphMcpAuthToken. Run `cia access-key set <key>` or `cia debug on --token <token>`.')\n }\n return createMcpAuthFetchClient(authToken)\n }\n\n return createConfiguredFetchWithToken(undefined, 'walletPrivateKey')\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-DakpK96I.cjs");
2
- const require_tools = require("./tools-kqWI7jPU.cjs");
2
+ const require_tools = require("./tools-BhTI3Lmg.cjs");
3
3
  let viem_accounts = require("viem/accounts");
4
4
  let _x402_fetch = require("@x402/fetch");
5
5
  let _x402_evm = require("@x402/evm");
@@ -139,8 +139,8 @@ function resolveGraphMcpEndpoint(config) {
139
139
  async function createConfiguredFetchWithToken(authToken, missingTokenName) {
140
140
  const normalizedAuthToken = authToken?.trim();
141
141
  if (normalizedAuthToken) return createMcpAuthFetchClient(normalizedAuthToken);
142
- const { isWalletConfigured, decryptKey } = await Promise.resolve().then(() => require("./wallet-TAlNMvIM.cjs")).then((n) => n.wallet_exports);
143
- if (!await isWalletConfigured()) throw new Error(`Wallet not configured and ${missingTokenName} is empty. Run \`chain-insights access-key set <key>\` for invited test access or \`chain-insights config set ${missingTokenName} <token>\` for local MCP debug bypass, or \`chain-insights config set walletPrivateKey <key>\` to enable paid x402 MCP calls.`);
142
+ const { isWalletConfigured, decryptKey } = await Promise.resolve().then(() => require("./wallet-gC2jxh7j.cjs")).then((n) => n.wallet_exports);
143
+ if (!await isWalletConfigured()) throw new Error("Hosted access is not configured. Run `chain-insights access-key set <key>` for invited test access. For wallet-paid access, run `chain-insights wallet import <private-key>` once, then run `chain-insights wallet ready`; run `chain-insights wallet topup` if it says the wallet needs funds.");
144
144
  return createMcpFetchClient(await decryptKey());
145
145
  }
146
146
  async function createConfiguredMcpFetch(config) {
package/dist/index.cjs CHANGED
@@ -2,10 +2,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_config = require("./config-BwVx19Og.cjs");
3
3
  const require_app = require("./app-BxojXjtB.cjs");
4
4
  const require_server = require("./server-BqVdWath.cjs");
5
- const require_wallet = require("./wallet-TAlNMvIM.cjs");
6
- const require_tools = require("./tools-kqWI7jPU.cjs");
5
+ const require_wallet = require("./wallet-gC2jxh7j.cjs");
6
+ const require_tools = require("./tools-BhTI3Lmg.cjs");
7
7
  const require_topup_server = require("./topup-server-DhYlOOBM.cjs");
8
- const require_client = require("./client-DRJq31u_.cjs");
8
+ const require_client = require("./client-ByXzwNum.cjs");
9
9
  const require_viz = require("./viz-Da9YWN_I.cjs");
10
10
  exports.buildTopupInfo = require_tools.buildTopupInfo;
11
11
  exports.createApp = require_app.createApp;
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { i as saveConfig, n as loadConfig, r as resetConfigCache } from "./config-Drgc2HuF.mjs";
2
2
  import { t as createApp } from "./app-CRd39JJ8.mjs";
3
3
  import { n as startServer } from "./server-BXLX2j_A.mjs";
4
- import { a as setWalletPrivateKey, i as normalizeWalletPrivateKey, n as encryptKey, o as walletAddressFromPrivateKey, r as isWalletConfigured, t as decryptKey } from "./wallet-D8IqFRKY.mjs";
5
- import { a as getWalletAccount, i as getBalanceUsdc, n as formatWalletBalance, o as getWalletBalanceText, r as getBalanceEth, t as buildTopupInfo } from "./tools-6emZlUwg.mjs";
4
+ import { a as setWalletPrivateKey, i as normalizeWalletPrivateKey, n as encryptKey, o as walletAddressFromPrivateKey, r as isWalletConfigured, t as decryptKey } from "./wallet-BL0fJC29.mjs";
5
+ import { a as getWalletAccount, i as getBalanceUsdc, n as formatWalletBalance, o as getWalletBalanceText, r as getBalanceEth, t as buildTopupInfo } from "./tools-v6kcdojg.mjs";
6
6
  import { i as generateArtifactHtml, n as startTopupServer, t as getTopupUrl } from "./topup-server-R3dNp-p8.mjs";
7
- import { i as createMcpFetchClient } from "./client-Bfw9P9uA.mjs";
7
+ import { i as createMcpFetchClient } from "./client-7vkBVEIj.mjs";
8
8
  import { t as generateVisualization } from "./viz-DkJyqlUu.mjs";
9
9
  export { buildTopupInfo, createApp, createMcpFetchClient, decryptKey, encryptKey, formatWalletBalance, generateArtifactHtml, generateVisualization, getBalanceEth, getBalanceUsdc, getTopupUrl, getWalletAccount, getWalletBalanceText, isWalletConfigured, loadConfig, normalizeWalletPrivateKey, resetConfigCache, saveConfig, setWalletPrivateKey, startServer, startTopupServer, walletAddressFromPrivateKey };
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-DakpK96I.cjs");
3
3
  const require_version = require("./version-CO9Or_YV.cjs");
4
- const require_client = require("./client-DRJq31u_.cjs");
4
+ const require_client = require("./client-ByXzwNum.cjs");
5
5
  const require_tool_visibility = require("./tool-visibility-iAVQV3t0.cjs");
6
6
  let node_url = require("node:url");
7
7
  let node_path = require("node:path");
@@ -589,7 +589,7 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
589
589
  async function createProxy() {
590
590
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
591
591
  const { activeDataDir, findActiveWorkspace } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
592
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-DRJq31u_.cjs")).then((n) => n.client_exports);
592
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-ByXzwNum.cjs")).then((n) => n.client_exports);
593
593
  const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-CJk1EL3L.cjs"));
594
594
  const loadedConfig = await loadConfig();
595
595
  const activeWorkspace = findActiveWorkspace();
@@ -710,7 +710,7 @@ async function createProxy() {
710
710
  inputSchema: zod.object({}).passthrough()
711
711
  }, async () => {
712
712
  try {
713
- const { getWalletAccount, getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-kqWI7jPU.cjs")).then((n) => n.tools_exports);
713
+ const { getWalletAccount, getWalletBalanceText } = await Promise.resolve().then(() => require("./tools-BhTI3Lmg.cjs")).then((n) => n.tools_exports);
714
714
  return {
715
715
  content: [{
716
716
  type: "text",
@@ -1,5 +1,5 @@
1
1
  import { n as PACKAGE_VERSION } from "./version-BA3J8hu4.mjs";
2
- import { t as PaymentRequiredError } from "./client-Bfw9P9uA.mjs";
2
+ import { t as PaymentRequiredError } from "./client-7vkBVEIj.mjs";
3
3
  import { t as HIDDEN_REMOTE_TOOL_NAMES } from "./tool-visibility-BHRFLXuU.mjs";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import path from "node:path";
@@ -585,7 +585,7 @@ async function normalizeRemoteToolResult(result, config, toolName = "remote-grap
585
585
  async function createProxy() {
586
586
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
587
587
  const { activeDataDir, findActiveWorkspace } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
588
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-Bfw9P9uA.mjs").then((n) => n.n);
588
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-7vkBVEIj.mjs").then((n) => n.n);
589
589
  const { loadSchema, saveSchema } = await import("./schema-cache-DwDvPy4e.mjs");
590
590
  const loadedConfig = await loadConfig();
591
591
  const activeWorkspace = findActiveWorkspace();
@@ -706,7 +706,7 @@ async function createProxy() {
706
706
  inputSchema: z.object({}).passthrough()
707
707
  }, async () => {
708
708
  try {
709
- const { getWalletAccount, getWalletBalanceText } = await import("./tools-6emZlUwg.mjs").then((n) => n.c);
709
+ const { getWalletAccount, getWalletBalanceText } = await import("./tools-v6kcdojg.mjs").then((n) => n.c);
710
710
  return {
711
711
  content: [{
712
712
  type: "text",
@@ -1,6 +1,6 @@
1
1
  import { n as PACKAGE_VERSION } from "./version-BA3J8hu4.mjs";
2
2
  import { n as loadConfig } from "./config-Drgc2HuF.mjs";
3
- import { r as createConfiguredMcpFetch } from "./client-Bfw9P9uA.mjs";
3
+ import { r as createConfiguredMcpFetch } from "./client-7vkBVEIj.mjs";
4
4
  import { t as generateVisualization } from "./viz-DkJyqlUu.mjs";
5
5
  import { CaseStore } from "./store-BT2SCcQr.mjs";
6
6
  import { t as EvidenceStore } from "./evidence-D96PTzOQ.mjs";
@@ -117,7 +117,7 @@ async run(playbook, opts) {
117
117
  console.log(`Step ${step.index} skipped.`);
118
118
  continue;
119
119
  } else throw new Error(`Aborted at step ${step.index} due to payment failure.`);
120
- } else throw new Error(`Payment required for step ${step.index} but no interactive terminal available. Configure wallet with \`chain-insights config set walletPrivateKey <key>\`. Aborting.`);
120
+ } else throw new Error(`Payment required for step ${step.index} but no interactive terminal available. Configure wallet with \`chain-insights wallet import <private-key>\`, then run \`chain-insights wallet ready\`. Aborting.`);
121
121
  else {
122
122
  const completedMsg = step.index - 1 - startIndex > 0 ? `Completed: steps ${startIndex + 1}..${step.index - 1}.` : "No steps completed before failure.";
123
123
  console.error(`Step ${step.index} failed: ${err.message}. ${completedMsg} Run with --from ${step.index} to resume.`);
@@ -146,4 +146,4 @@ async run(playbook, opts) {
146
146
  //#endregion
147
147
  export { PlaybookRunner };
148
148
 
149
- //# sourceMappingURL=runner-C-QgZu-S.mjs.map
149
+ //# sourceMappingURL=runner-B-9g4X1q.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner-C-QgZu-S.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights config set walletPrivateKey <key>\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runner-B-9g4X1q.mjs","names":[],"sources":["../src/playbooks/runner.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client/index.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { CaseStore } from '../cases/store.js'\nimport { EvidenceStore } from '../cases/evidence.js'\nimport { loadConfig } from '../config/index.js'\nimport { createConfiguredMcpFetch } from '../mcp/client.js'\nimport { generateVisualization } from '../viz/index.js'\nimport { PACKAGE_VERSION } from '../version.js'\nimport type { PlaybookDefinition } from './schema.js'\n\nexport interface RunnerOptions {\n caseId?: string // attach to existing case; omit for quick-case auto-creation\n from?: number // 1-based step to resume from (default: 1)\n dryRun?: boolean // print steps, no MCP calls\n params?: Record<string, string>\n}\n\n/** Sleep for ms milliseconds. */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** Check if an error is a timeout/abort error. */\nfunction isTimeoutError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n return err.name === 'AbortError' || (err as NodeJS.ErrnoException).code === 'ECONNRESET'\n}\n\n/** Check if an error is a payment failure. */\nfunction isPaymentError(err: unknown): boolean {\n if (!(err instanceof Error)) return false\n const msg = err.message.toLowerCase()\n // Match HTTP 402 status more precisely, or x402-specific error signals\n return msg.includes('http 402') ||\n msg.includes('status 402') ||\n msg.includes('payment required') ||\n msg.includes('x402')\n}\n\n/**\n * Call an MCP tool with retry logic on timeout (up to 3 total attempts).\n * Returns the text result or throws on non-retryable error.\n */\nasync function callWithRetry(\n client: Client,\n toolName: string,\n params: Record<string, string>\n): Promise<string> {\n const MAX_ATTEMPTS = 3\n let lastErr: unknown\n\n for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {\n try {\n const result = await client.callTool({ name: toolName, arguments: params })\n const content = result.content as Array<{ type: string; text?: string }>\n return content.filter(c => c.type === 'text').map(c => c.text ?? '').join('\\n')\n } catch (err) {\n if (isTimeoutError(err) && attempt < MAX_ATTEMPTS) {\n lastErr = err\n await sleep(1000)\n continue\n }\n throw err\n }\n }\n\n throw lastErr\n}\n\nasync function validateStepTools(client: Client, steps: PlaybookDefinition['steps']): Promise<void> {\n const result = await client.listTools()\n const available = new Set(result.tools.map(tool => tool.name))\n const missing = [...new Set(steps.map(step => step.tool).filter(tool => !available.has(tool)))]\n if (missing.length === 0) return\n\n const availableList = [...available].sort().join(', ') || 'none'\n throw new Error(\n `Unknown MCP tool(s) in playbook: ${missing.join(', ')}. ` +\n `Available tools: ${availableList}. Run \\`chain-insights mcp tools --refresh\\` to inspect the live MCP schema.`\n )\n}\n\nexport const PlaybookRunner = {\n /**\n * Execute a playbook definition step-by-step against the live MCP.\n *\n * @param playbook - Parsed and validated PlaybookDefinition\n * @param opts - Runner options (caseId, from, dryRun, params)\n */\n async run(playbook: PlaybookDefinition, opts: RunnerOptions): Promise<void> {\n const startIndex = (opts.from ?? 1) - 1 // convert 1-based to 0-based\n const stepsToRun = playbook.steps.slice(startIndex)\n const totalSteps = playbook.steps.length\n\n // --- DRY RUN ---\n if (opts.dryRun) {\n console.log(`Playbook: ${playbook.name} (dry run — no MCP calls)`)\n console.log(`Steps: ${totalSteps} total, starting from ${startIndex + 1}`)\n console.log('')\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.tool} (params: ${JSON.stringify(step.params)})`)\n }\n console.log('')\n console.log('Cost: unknown (MCP pricing not available without live connection)')\n return\n }\n\n // --- MCP AUTH CHECK (before case creation to avoid orphan cases) ---\n const config = await loadConfig()\n const mcpFetch = await createConfiguredMcpFetch(config)\n\n // --- CASE RESOLUTION ---\n let caseId: string\n if (opts.caseId) {\n const existingCase = await CaseStore.get(opts.caseId)\n caseId = existingCase.id\n } else {\n const newCase = await CaseStore.create({\n name: `quick-${playbook.name}-${Date.now()}`,\n tags: ['quick', 'playbook', playbook.name],\n description: `Auto-created for one-off playbook run: ${playbook.name}`,\n })\n caseId = newCase.id\n console.log(`Created quick case: ${caseId}`)\n }\n\n // --- MCP CONNECTION ---\n const client = new Client({ name: 'chain-insights-playbook', version: PACKAGE_VERSION })\n await client.connect(\n new StreamableHTTPClientTransport(new URL(config.mcpEndpoint), { fetch: mcpFetch })\n )\n\n let evidenceCount = 0\n\n try {\n await validateStepTools(client, stepsToRun)\n\n // --- STEP LOOP ---\n for (const step of stepsToRun) {\n console.log(`Step ${step.index}/${totalSteps}: ${step.label}...`)\n\n let result: string\n try {\n result = await callWithRetry(client, step.tool, step.params)\n } catch (err) {\n if (isPaymentError(err)) {\n if (process.stdin.isTTY) {\n // Interactive: prompt user\n const { createInterface } = await import('node:readline')\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n const answer = await new Promise<string>(resolve => {\n rl.question(`Payment required for step ${step.index}. (retry/skip/abort): `, resolve)\n })\n rl.close()\n\n if (answer.trim().toLowerCase() === 'retry') {\n result = await callWithRetry(client, step.tool, step.params)\n } else if (answer.trim().toLowerCase() === 'skip') {\n console.log(`Step ${step.index} skipped.`)\n continue\n } else {\n throw new Error(`Aborted at step ${step.index} due to payment failure.`)\n }\n } else {\n // Non-TTY: abort\n throw new Error(\n `Payment required for step ${step.index} but no interactive terminal available. ` +\n `Configure wallet with \\`chain-insights wallet import <private-key>\\`, then run \\`chain-insights wallet ready\\`. Aborting.`\n )\n }\n } else {\n // Non-payment, non-timeout MCP error — stop and report\n const completedSteps = step.index - 1 - startIndex\n const completedMsg = completedSteps > 0\n ? `Completed: steps ${startIndex + 1}..${step.index - 1}.`\n : 'No steps completed before failure.'\n console.error(\n `Step ${step.index} failed: ${(err as Error).message}. ` +\n `${completedMsg} Run with --from ${step.index} to resume.`\n )\n throw err\n }\n }\n\n // --- STORE EVIDENCE ---\n await EvidenceStore.append(caseId, {\n source: step.tool,\n content: result,\n queryParams: JSON.stringify(step.params),\n })\n evidenceCount++\n console.log(` (${result.length} chars stored)`)\n }\n\n // --- AUTO-VIZ for trace-funds ---\n if (playbook.name === 'trace-funds') {\n try {\n const viz = await generateVisualization({ caseId })\n console.log(`Visualization generated: ${viz.htmlPath}`)\n } catch {\n console.log('No transaction data to visualize.')\n }\n }\n\n // --- FINAL SUMMARY ---\n console.log(`Playbook complete. Case: ${caseId}. Evidence: ${evidenceCount} entries.`)\n } finally {\n await client.close()\n }\n },\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  const require_version = require("./version-CO9Or_YV.cjs");
2
2
  const require_config = require("./config-BwVx19Og.cjs");
3
- const require_client = require("./client-DRJq31u_.cjs");
3
+ const require_client = require("./client-ByXzwNum.cjs");
4
4
  const require_viz = require("./viz-Da9YWN_I.cjs");
5
5
  const require_store = require("./store-DogLawSj.cjs");
6
6
  const require_evidence = require("./evidence-CvEesemA.cjs");
@@ -117,7 +117,7 @@ async run(playbook, opts) {
117
117
  console.log(`Step ${step.index} skipped.`);
118
118
  continue;
119
119
  } else throw new Error(`Aborted at step ${step.index} due to payment failure.`);
120
- } else throw new Error(`Payment required for step ${step.index} but no interactive terminal available. Configure wallet with \`chain-insights config set walletPrivateKey <key>\`. Aborting.`);
120
+ } else throw new Error(`Payment required for step ${step.index} but no interactive terminal available. Configure wallet with \`chain-insights wallet import <private-key>\`, then run \`chain-insights wallet ready\`. Aborting.`);
121
121
  else {
122
122
  const completedMsg = step.index - 1 - startIndex > 0 ? `Completed: steps ${startIndex + 1}..${step.index - 1}.` : "No steps completed before failure.";
123
123
  console.error(`Step ${step.index} failed: ${err.message}. ${completedMsg} Run with --from ${step.index} to resume.`);
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-DakpK96I.cjs");
2
- const require_wallet = require("./wallet-TAlNMvIM.cjs");
2
+ const require_wallet = require("./wallet-gC2jxh7j.cjs");
3
3
  let viem_accounts = require("viem/accounts");
4
4
  let viem = require("viem");
5
5
  let viem_chains = require("viem/chains");
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { i as normalizeWalletPrivateKey, t as decryptKey } from "./wallet-D8IqFRKY.mjs";
2
+ import { i as normalizeWalletPrivateKey, t as decryptKey } from "./wallet-BL0fJC29.mjs";
3
3
  import { privateKeyToAccount } from "viem/accounts";
4
4
  import { createPublicClient, createWalletClient, formatEther, formatUnits, http, parseUnits } from "viem";
5
5
  import { base } from "viem/chains";
@@ -295,4 +295,4 @@ function buildTopupInfo(address, topupUrl) {
295
295
  //#endregion
296
296
  export { getWalletAccount as a, tools_exports as c, getBalanceUsdc as i, formatWalletBalance as n, getWalletBalanceText as o, getBalanceEth as r, prepareWalletForPaidCalls as s, buildTopupInfo as t };
297
297
 
298
- //# sourceMappingURL=tools-6emZlUwg.mjs.map
298
+ //# sourceMappingURL=tools-v6kcdojg.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools-6emZlUwg.mjs","names":[],"sources":["../src/wallet/tools.ts"],"sourcesContent":["import { createPublicClient, createWalletClient, formatEther, formatUnits, http, parseUnits, type Address, type Hex } from 'viem'\nimport { base } from 'viem/chains'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport { decryptKey, normalizeWalletPrivateKey } from './index.js'\n\nexport const BASE_CHAIN_ID = 8453\nexport const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as const\nexport const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' as const\nexport const DEFAULT_BASE_RPC_URL = 'https://mainnet.base.org'\nexport const DEFAULT_PAYMENT_APPROVAL_UNITS = 1_000_000n\nexport const PUBLIC_BASE_RPC_URLS = [\n DEFAULT_BASE_RPC_URL,\n 'https://base-rpc.publicnode.com',\n 'https://base.drpc.org',\n 'https://1rpc.io/base',\n] as const\n\nconst USDC_ABI = [\n {\n type: 'function',\n name: 'balanceOf',\n stateMutability: 'view',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'allowance',\n stateMutability: 'view',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'approve',\n stateMutability: 'nonpayable',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n },\n] as const\n\nexport interface PaymentWalletAccount {\n address: Address\n privateKey: Hex\n}\n\nexport interface TopupInfo {\n wallet_address: string\n network: 'Base'\n chain_id: typeof BASE_CHAIN_ID\n token: 'USDC'\n token_contract: typeof USDC_ADDRESS\n topup_url?: string\n}\n\nexport interface WalletReadiness {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUsdc: string\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n hasUsdc: boolean | null\n hasGas: boolean | null\n hasPaymentApproval: boolean\n needsPaymentApproval: boolean\n ready: boolean\n nextSteps: string[]\n}\n\nexport interface PaymentApprovalResult {\n status: 'already_ready' | 'approved'\n txHash?: Hex\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n}\n\nexport interface PrepareWalletResult {\n readiness: WalletReadiness\n approval?: PaymentApprovalResult\n}\n\nexport interface PrepareWalletOptions {\n account?: PaymentWalletAccount\n minimumApprovalUnits?: bigint\n approve?: boolean\n rpcUrl?: string\n}\n\nexport async function getWalletAccount(): Promise<PaymentWalletAccount> {\n const privateKey = normalizeWalletPrivateKey(await decryptKey()) as Hex\n const account = privateKeyToAccount(privateKey)\n return { address: account.address, privateKey }\n}\n\nfunction baseRpcUrls(rpcUrl = process.env['BASE_RPC_URL']): string[] {\n return [\n ...(rpcUrl ? [rpcUrl] : []),\n ...PUBLIC_BASE_RPC_URLS.filter((fallbackUrl) => fallbackUrl !== rpcUrl),\n ]\n}\n\nexport async function getBalanceUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'balanceOf',\n args: [address as Address],\n })\n return formatUnits(balance, 6)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getBalanceEth(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.getBalance({ address: address as Address })\n return formatEther(balance)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getPaymentApprovalUnits(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<bigint | null> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n return await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'allowance',\n args: [address as Address, PERMIT2_ADDRESS],\n })\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return null\n}\n\nexport async function getPaymentApprovalUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n const allowance = await getPaymentApprovalUnits(address, rpcUrl)\n return allowance === null ? 'unknown' : formatUnits(allowance, 6)\n}\n\nexport function parsePaymentApprovalUnits(amountUsdc: string): bigint {\n const trimmed = amountUsdc.trim()\n if (!/^\\d+(\\.\\d{1,6})?$/.test(trimmed) || !isPositiveDecimal(trimmed)) {\n throw new Error('Payment setup amount must be a positive USDC value with up to 6 decimals.')\n }\n return parseUnits(trimmed, 6)\n}\n\nfunction isPositiveDecimal(value: string): boolean {\n if (value === 'unknown') return false\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) && parsed > 0\n}\n\nfunction decimalStatus(value: string): boolean | null {\n return value === 'unknown' ? null : isPositiveDecimal(value)\n}\n\nfunction readinessNextSteps(readiness: Pick<WalletReadiness, 'hasUsdc' | 'hasGas' | 'needsPaymentApproval'>): string[] {\n const nextSteps: string[] = []\n if (readiness.hasUsdc === false) {\n nextSteps.push('Run `chain-insights wallet topup` and send USDC on Base to this wallet.')\n }\n if (readiness.hasUsdc === null) {\n nextSteps.push('Base USDC balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas === false) {\n nextSteps.push('Add a small amount of ETH on Base for the one-time payment setup gas.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas !== false) {\n nextSteps.push('Run `chain-insights wallet ready` to finish the one-time payment setup.')\n }\n if (readiness.hasGas === null) {\n nextSteps.push('Base ETH gas balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n return nextSteps\n}\n\nfunction buildWalletReadiness(params: {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUnits: bigint | null\n minimumApprovalUnits: bigint\n}): WalletReadiness {\n const paymentApprovalUnits = params.paymentApprovalUnits ?? 0n\n const hasUsdc = decimalStatus(params.balanceUsdc)\n const hasGas = decimalStatus(params.balanceEth)\n const hasPaymentApproval = paymentApprovalUnits >= params.minimumApprovalUnits\n const needsPaymentApproval = !hasPaymentApproval\n const ready = hasUsdc !== false && hasPaymentApproval\n const readiness = {\n address: params.address,\n balanceUsdc: params.balanceUsdc,\n balanceEth: params.balanceEth,\n paymentApprovalUsdc: params.paymentApprovalUnits === null ? 'unknown' : formatUnits(paymentApprovalUnits, 6),\n paymentApprovalUnits,\n minimumApprovalUnits: params.minimumApprovalUnits,\n hasUsdc,\n hasGas,\n hasPaymentApproval,\n needsPaymentApproval,\n ready,\n nextSteps: [],\n }\n return {\n ...readiness,\n nextSteps: readinessNextSteps(readiness),\n }\n}\n\nexport async function getWalletReadiness(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n): Promise<WalletReadiness> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth, paymentApprovalUnits] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n getPaymentApprovalUnits(wallet.address),\n ])\n return buildWalletReadiness({\n address: wallet.address,\n balanceUsdc,\n balanceEth,\n paymentApprovalUnits,\n minimumApprovalUnits,\n })\n}\n\nexport function formatWalletReadiness(readiness: WalletReadiness, approval?: PaymentApprovalResult): string {\n const status = readiness.ready ? 'Ready for paid GraphRAG MCP calls' : 'Action needed before paid GraphRAG MCP calls'\n const setup = readiness.needsPaymentApproval\n ? `Payment setup: needs one-time setup for up to ${formatUnits(readiness.minimumApprovalUnits, 6)} USDC of paid calls`\n : 'Payment setup: ready'\n const setupCompletedLine = approval?.status === 'approved'\n ? 'Payment setup completed.'\n : undefined\n return [\n status,\n `Balance: ${readiness.balanceUsdc} USDC`,\n `Gas: ${readiness.balanceEth} ETH on Base`,\n setup,\n setupCompletedLine,\n 'Network: Base',\n `Address: ${readiness.address}`,\n ...readiness.nextSteps.map((step) => `Next: ${step}`),\n ].filter(Boolean).join('\\n')\n}\n\nexport async function approvePaymentAllowance(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<PaymentApprovalResult> {\n const wallet = account ?? await getWalletAccount()\n const initialApprovalUnits = await getPaymentApprovalUnits(wallet.address, rpcUrl)\n if (initialApprovalUnits !== null && initialApprovalUnits >= minimumApprovalUnits) {\n return {\n status: 'already_ready',\n paymentApprovalUnits: initialApprovalUnits,\n minimumApprovalUnits,\n }\n }\n\n const clientAccount = privateKeyToAccount(wallet.privateKey)\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const publicClient = createPublicClient({ chain: base, transport: http(url) })\n const walletClient = createWalletClient({\n account: clientAccount,\n chain: base,\n transport: http(url),\n })\n const txHash = await walletClient.writeContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'approve',\n args: [PERMIT2_ADDRESS, minimumApprovalUnits],\n })\n const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash })\n if (receipt.status === 'reverted') {\n throw new Error(`Payment setup transaction reverted: ${txHash}`)\n }\n const paymentApprovalUnits = await getPaymentApprovalUnits(wallet.address, url)\n return {\n status: 'approved',\n txHash,\n paymentApprovalUnits: paymentApprovalUnits ?? minimumApprovalUnits,\n minimumApprovalUnits,\n }\n } catch (err) {\n if (url === baseRpcUrls(rpcUrl).at(-1)) throw err\n }\n }\n\n throw new Error('Unable to submit payment setup transaction on Base.')\n}\n\nexport async function prepareWalletForPaidCalls(options: PrepareWalletOptions = {}): Promise<PrepareWalletResult> {\n const minimumApprovalUnits = options.minimumApprovalUnits ?? DEFAULT_PAYMENT_APPROVAL_UNITS\n const wallet = options.account ?? await getWalletAccount()\n const readiness = await getWalletReadiness(wallet, minimumApprovalUnits)\n\n if (!readiness.needsPaymentApproval) {\n return {\n readiness,\n approval: {\n status: 'already_ready',\n paymentApprovalUnits: readiness.paymentApprovalUnits,\n minimumApprovalUnits,\n },\n }\n }\n if (options.approve === false || readiness.hasGas === false) {\n return { readiness }\n }\n\n const approval = await approvePaymentAllowance(wallet, minimumApprovalUnits, options.rpcUrl)\n const updatedReadiness = buildWalletReadiness({\n address: wallet.address,\n balanceUsdc: readiness.balanceUsdc,\n balanceEth: readiness.balanceEth,\n paymentApprovalUnits: approval.paymentApprovalUnits,\n minimumApprovalUnits,\n })\n return { readiness: updatedReadiness, approval }\n}\n\nexport function formatWalletBalance(address: string, balanceUsdc: string, balanceEth?: string): string {\n return [\n `Balance: ${balanceUsdc} USDC`,\n balanceEth === undefined ? undefined : `Gas: ${balanceEth} ETH on Base`,\n 'Network: Base',\n 'Base ETH is used only for one-time payment setup gas.',\n `Address: ${address}`,\n ].filter(Boolean).join('\\n')\n}\n\nexport async function getWalletBalanceText(account?: PaymentWalletAccount): Promise<string> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n ])\n return formatWalletBalance(wallet.address, balanceUsdc, balanceEth)\n}\n\nexport function buildTopupInfo(address: string, topupUrl?: string): TopupInfo {\n return {\n wallet_address: address,\n network: 'Base',\n chain_id: BASE_CHAIN_ID,\n token: 'USDC',\n token_contract: USDC_ADDRESS,\n ...(topupUrl ? { topup_url: topupUrl } : {}),\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tools-v6kcdojg.mjs","names":[],"sources":["../src/wallet/tools.ts"],"sourcesContent":["import { createPublicClient, createWalletClient, formatEther, formatUnits, http, parseUnits, type Address, type Hex } from 'viem'\nimport { base } from 'viem/chains'\nimport { privateKeyToAccount } from 'viem/accounts'\nimport { decryptKey, normalizeWalletPrivateKey } from './index.js'\n\nexport const BASE_CHAIN_ID = 8453\nexport const USDC_ADDRESS = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as const\nexport const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' as const\nexport const DEFAULT_BASE_RPC_URL = 'https://mainnet.base.org'\nexport const DEFAULT_PAYMENT_APPROVAL_UNITS = 1_000_000n\nexport const PUBLIC_BASE_RPC_URLS = [\n DEFAULT_BASE_RPC_URL,\n 'https://base-rpc.publicnode.com',\n 'https://base.drpc.org',\n 'https://1rpc.io/base',\n] as const\n\nconst USDC_ABI = [\n {\n type: 'function',\n name: 'balanceOf',\n stateMutability: 'view',\n inputs: [{ name: 'account', type: 'address' }],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'allowance',\n stateMutability: 'view',\n inputs: [\n { name: 'owner', type: 'address' },\n { name: 'spender', type: 'address' },\n ],\n outputs: [{ name: '', type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'approve',\n stateMutability: 'nonpayable',\n inputs: [\n { name: 'spender', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ name: '', type: 'bool' }],\n },\n] as const\n\nexport interface PaymentWalletAccount {\n address: Address\n privateKey: Hex\n}\n\nexport interface TopupInfo {\n wallet_address: string\n network: 'Base'\n chain_id: typeof BASE_CHAIN_ID\n token: 'USDC'\n token_contract: typeof USDC_ADDRESS\n topup_url?: string\n}\n\nexport interface WalletReadiness {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUsdc: string\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n hasUsdc: boolean | null\n hasGas: boolean | null\n hasPaymentApproval: boolean\n needsPaymentApproval: boolean\n ready: boolean\n nextSteps: string[]\n}\n\nexport interface PaymentApprovalResult {\n status: 'already_ready' | 'approved'\n txHash?: Hex\n paymentApprovalUnits: bigint\n minimumApprovalUnits: bigint\n}\n\nexport interface PrepareWalletResult {\n readiness: WalletReadiness\n approval?: PaymentApprovalResult\n}\n\nexport interface PrepareWalletOptions {\n account?: PaymentWalletAccount\n minimumApprovalUnits?: bigint\n approve?: boolean\n rpcUrl?: string\n}\n\nexport async function getWalletAccount(): Promise<PaymentWalletAccount> {\n const privateKey = normalizeWalletPrivateKey(await decryptKey()) as Hex\n const account = privateKeyToAccount(privateKey)\n return { address: account.address, privateKey }\n}\n\nfunction baseRpcUrls(rpcUrl = process.env['BASE_RPC_URL']): string[] {\n return [\n ...(rpcUrl ? [rpcUrl] : []),\n ...PUBLIC_BASE_RPC_URLS.filter((fallbackUrl) => fallbackUrl !== rpcUrl),\n ]\n}\n\nexport async function getBalanceUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'balanceOf',\n args: [address as Address],\n })\n return formatUnits(balance, 6)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getBalanceEth(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n const balance = await client.getBalance({ address: address as Address })\n return formatEther(balance)\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return 'unknown'\n}\n\nexport async function getPaymentApprovalUnits(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<bigint | null> {\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const client = createPublicClient({\n chain: base,\n transport: http(url),\n })\n return await client.readContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'allowance',\n args: [address as Address, PERMIT2_ADDRESS],\n })\n } catch {\n // Try the next public Base RPC endpoint.\n }\n }\n\n return null\n}\n\nexport async function getPaymentApprovalUsdc(\n address: Address | string,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<string> {\n const allowance = await getPaymentApprovalUnits(address, rpcUrl)\n return allowance === null ? 'unknown' : formatUnits(allowance, 6)\n}\n\nexport function parsePaymentApprovalUnits(amountUsdc: string): bigint {\n const trimmed = amountUsdc.trim()\n if (!/^\\d+(\\.\\d{1,6})?$/.test(trimmed) || !isPositiveDecimal(trimmed)) {\n throw new Error('Payment setup amount must be a positive USDC value with up to 6 decimals.')\n }\n return parseUnits(trimmed, 6)\n}\n\nfunction isPositiveDecimal(value: string): boolean {\n if (value === 'unknown') return false\n const parsed = Number.parseFloat(value)\n return Number.isFinite(parsed) && parsed > 0\n}\n\nfunction decimalStatus(value: string): boolean | null {\n return value === 'unknown' ? null : isPositiveDecimal(value)\n}\n\nfunction readinessNextSteps(readiness: Pick<WalletReadiness, 'hasUsdc' | 'hasGas' | 'needsPaymentApproval'>): string[] {\n const nextSteps: string[] = []\n if (readiness.hasUsdc === false) {\n nextSteps.push('Run `chain-insights wallet topup` and send USDC on Base to this wallet.')\n }\n if (readiness.hasUsdc === null) {\n nextSteps.push('Base USDC balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas === false) {\n nextSteps.push('Add a small amount of ETH on Base for the one-time payment setup gas.')\n }\n if (readiness.needsPaymentApproval && readiness.hasGas !== false) {\n nextSteps.push('Run `chain-insights wallet ready` to finish the one-time payment setup.')\n }\n if (readiness.hasGas === null) {\n nextSteps.push('Base ETH gas balance could not be confirmed; retry or set BASE_RPC_URL to a working Base RPC endpoint.')\n }\n return nextSteps\n}\n\nfunction buildWalletReadiness(params: {\n address: Address\n balanceUsdc: string\n balanceEth: string\n paymentApprovalUnits: bigint | null\n minimumApprovalUnits: bigint\n}): WalletReadiness {\n const paymentApprovalUnits = params.paymentApprovalUnits ?? 0n\n const hasUsdc = decimalStatus(params.balanceUsdc)\n const hasGas = decimalStatus(params.balanceEth)\n const hasPaymentApproval = paymentApprovalUnits >= params.minimumApprovalUnits\n const needsPaymentApproval = !hasPaymentApproval\n const ready = hasUsdc !== false && hasPaymentApproval\n const readiness = {\n address: params.address,\n balanceUsdc: params.balanceUsdc,\n balanceEth: params.balanceEth,\n paymentApprovalUsdc: params.paymentApprovalUnits === null ? 'unknown' : formatUnits(paymentApprovalUnits, 6),\n paymentApprovalUnits,\n minimumApprovalUnits: params.minimumApprovalUnits,\n hasUsdc,\n hasGas,\n hasPaymentApproval,\n needsPaymentApproval,\n ready,\n nextSteps: [],\n }\n return {\n ...readiness,\n nextSteps: readinessNextSteps(readiness),\n }\n}\n\nexport async function getWalletReadiness(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n): Promise<WalletReadiness> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth, paymentApprovalUnits] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n getPaymentApprovalUnits(wallet.address),\n ])\n return buildWalletReadiness({\n address: wallet.address,\n balanceUsdc,\n balanceEth,\n paymentApprovalUnits,\n minimumApprovalUnits,\n })\n}\n\nexport function formatWalletReadiness(readiness: WalletReadiness, approval?: PaymentApprovalResult): string {\n const status = readiness.ready ? 'Ready for paid GraphRAG MCP calls' : 'Action needed before paid GraphRAG MCP calls'\n const setup = readiness.needsPaymentApproval\n ? `Payment setup: needs one-time setup for up to ${formatUnits(readiness.minimumApprovalUnits, 6)} USDC of paid calls`\n : 'Payment setup: ready'\n const setupCompletedLine = approval?.status === 'approved'\n ? 'Payment setup completed.'\n : undefined\n return [\n status,\n `Balance: ${readiness.balanceUsdc} USDC`,\n `Gas: ${readiness.balanceEth} ETH on Base`,\n setup,\n setupCompletedLine,\n 'Network: Base',\n `Address: ${readiness.address}`,\n ...readiness.nextSteps.map((step) => `Next: ${step}`),\n ].filter(Boolean).join('\\n')\n}\n\nexport async function approvePaymentAllowance(\n account?: PaymentWalletAccount,\n minimumApprovalUnits = DEFAULT_PAYMENT_APPROVAL_UNITS,\n rpcUrl = process.env['BASE_RPC_URL'],\n): Promise<PaymentApprovalResult> {\n const wallet = account ?? await getWalletAccount()\n const initialApprovalUnits = await getPaymentApprovalUnits(wallet.address, rpcUrl)\n if (initialApprovalUnits !== null && initialApprovalUnits >= minimumApprovalUnits) {\n return {\n status: 'already_ready',\n paymentApprovalUnits: initialApprovalUnits,\n minimumApprovalUnits,\n }\n }\n\n const clientAccount = privateKeyToAccount(wallet.privateKey)\n for (const url of baseRpcUrls(rpcUrl)) {\n try {\n const publicClient = createPublicClient({ chain: base, transport: http(url) })\n const walletClient = createWalletClient({\n account: clientAccount,\n chain: base,\n transport: http(url),\n })\n const txHash = await walletClient.writeContract({\n address: USDC_ADDRESS,\n abi: USDC_ABI,\n functionName: 'approve',\n args: [PERMIT2_ADDRESS, minimumApprovalUnits],\n })\n const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash })\n if (receipt.status === 'reverted') {\n throw new Error(`Payment setup transaction reverted: ${txHash}`)\n }\n const paymentApprovalUnits = await getPaymentApprovalUnits(wallet.address, url)\n return {\n status: 'approved',\n txHash,\n paymentApprovalUnits: paymentApprovalUnits ?? minimumApprovalUnits,\n minimumApprovalUnits,\n }\n } catch (err) {\n if (url === baseRpcUrls(rpcUrl).at(-1)) throw err\n }\n }\n\n throw new Error('Unable to submit payment setup transaction on Base.')\n}\n\nexport async function prepareWalletForPaidCalls(options: PrepareWalletOptions = {}): Promise<PrepareWalletResult> {\n const minimumApprovalUnits = options.minimumApprovalUnits ?? DEFAULT_PAYMENT_APPROVAL_UNITS\n const wallet = options.account ?? await getWalletAccount()\n const readiness = await getWalletReadiness(wallet, minimumApprovalUnits)\n\n if (!readiness.needsPaymentApproval) {\n return {\n readiness,\n approval: {\n status: 'already_ready',\n paymentApprovalUnits: readiness.paymentApprovalUnits,\n minimumApprovalUnits,\n },\n }\n }\n if (options.approve === false || readiness.hasGas === false) {\n return { readiness }\n }\n\n const approval = await approvePaymentAllowance(wallet, minimumApprovalUnits, options.rpcUrl)\n const updatedReadiness = buildWalletReadiness({\n address: wallet.address,\n balanceUsdc: readiness.balanceUsdc,\n balanceEth: readiness.balanceEth,\n paymentApprovalUnits: approval.paymentApprovalUnits,\n minimumApprovalUnits,\n })\n return { readiness: updatedReadiness, approval }\n}\n\nexport function formatWalletBalance(address: string, balanceUsdc: string, balanceEth?: string): string {\n return [\n `Balance: ${balanceUsdc} USDC`,\n balanceEth === undefined ? undefined : `Gas: ${balanceEth} ETH on Base`,\n 'Network: Base',\n 'Base ETH is used only for one-time payment setup gas.',\n `Address: ${address}`,\n ].filter(Boolean).join('\\n')\n}\n\nexport async function getWalletBalanceText(account?: PaymentWalletAccount): Promise<string> {\n const wallet = account ?? await getWalletAccount()\n const [balanceUsdc, balanceEth] = await Promise.all([\n getBalanceUsdc(wallet.address),\n getBalanceEth(wallet.address),\n ])\n return formatWalletBalance(wallet.address, balanceUsdc, balanceEth)\n}\n\nexport function buildTopupInfo(address: string, topupUrl?: string): TopupInfo {\n return {\n wallet_address: address,\n network: 'Base',\n chain_id: BASE_CHAIN_ID,\n token: 'USDC',\n token_contract: USDC_ADDRESS,\n ...(topupUrl ? { topup_url: topupUrl } : {}),\n }\n}\n"],"mappings":"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"}
@@ -69,7 +69,7 @@ async function decryptKey() {
69
69
  try {
70
70
  raw = await readFile(walletPath(), "utf8");
71
71
  } catch (err) {
72
- if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights config set walletPrivateKey <key>` to enable paid MCP calls");
72
+ if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights wallet import <private-key>`, then `chain-insights wallet ready`.");
73
73
  throw err;
74
74
  }
75
75
  try {
@@ -82,7 +82,7 @@ async function decryptKey() {
82
82
  decipher.setAuthTag(tag);
83
83
  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
84
84
  } catch {
85
- throw new Error("Wallet decryption failed. If you changed your hostname or username, re-configure with `chain-insights config set walletPrivateKey <key>`.");
85
+ throw new Error("Wallet decryption failed. If you changed your hostname or username, re-import it with `chain-insights wallet import <private-key>`.");
86
86
  }
87
87
  }
88
88
  /**
@@ -101,4 +101,4 @@ async function isWalletConfigured() {
101
101
  //#endregion
102
102
  export { setWalletPrivateKey as a, normalizeWalletPrivateKey as i, encryptKey as n, walletAddressFromPrivateKey as o, isWalletConfigured as r, wallet_exports as s, decryptKey as t };
103
103
 
104
- //# sourceMappingURL=wallet-D8IqFRKY.mjs.map
104
+ //# sourceMappingURL=wallet-BL0fJC29.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-D8IqFRKY.mjs","names":["nodeErr"],"sources":["../src/wallet/index.ts"],"sourcesContent":["import crypto from 'node:crypto'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { readFile, writeFile, mkdir, stat } from 'node:fs/promises'\nimport type { Address, Hex } from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\n// Path derived at call time so tests can override HOME.\nexport function walletPath(): string {\n return path.join(os.homedir(), '.chain-insights', 'wallet.json')\n}\n\n// Derive a 32-byte key from the machine identity (hostname + username) and a\n// random per-wallet salt. The salt prevents precomputation attacks across wallets.\nfunction deriveKey(salt: Buffer): Buffer {\n return crypto.scryptSync(\n `${os.hostname()}:${os.userInfo().username}`,\n salt,\n 32,\n )\n}\n\ninterface WalletData {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nexport function normalizeWalletPrivateKey(value: string): Hex {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error('Stored wallet private key is not a valid 0x-prefixed EVM private key')\n }\n return value as Hex\n}\n\nexport function walletAddressFromPrivateKey(privateKey: string): Address {\n return privateKeyToAccount(normalizeWalletPrivateKey(privateKey)).address\n}\n\n/**\n * Encrypts a private key and writes it to ~/.chain-insights/wallet.json.\n * Uses AES-256-GCM with a machine-identity-derived key and a random per-wallet salt.\n * File is written with 0o600 permissions (owner read/write only).\n *\n * @param privateKey - The EVM private key to encrypt (0x-prefixed)\n */\nexport async function encryptKey(privateKey: string): Promise<void> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const salt = crypto.randomBytes(16)\n const key = deriveKey(salt)\n const iv = crypto.randomBytes(12)\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)\n\n const encrypted = Buffer.concat([\n cipher.update(normalizedPrivateKey, 'utf8'),\n cipher.final(),\n ])\n\n // getAuthTag() MUST be called after final()\n const tag = cipher.getAuthTag()\n\n const walletData: WalletData = {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data: encrypted.toString('hex'),\n }\n\n const p = walletPath()\n await mkdir(path.dirname(p), { recursive: true })\n await writeFile(p, JSON.stringify(walletData, null, 2) + '\\n', { mode: 0o600 })\n}\n\nexport async function setWalletPrivateKey(privateKey: string): Promise<Address> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const address = walletAddressFromPrivateKey(normalizedPrivateKey)\n await encryptKey(normalizedPrivateKey)\n return address\n}\n\n/**\n * Reads and decrypts the private key from ~/.chain-insights/wallet.json.\n * Throws a human-readable error if wallet is absent or decryption fails.\n *\n * @returns The decrypted EVM private key string\n */\nexport async function decryptKey(): Promise<string> {\n let raw: string\n try {\n raw = await readFile(walletPath(), 'utf8')\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') {\n throw new Error(\n 'Wallet not configured. Run `chain-insights config set walletPrivateKey <key>` to enable paid MCP calls',\n )\n }\n throw err\n }\n\n try {\n const stored = JSON.parse(raw) as WalletData\n const salt = Buffer.from(stored.salt, 'hex')\n const key = deriveKey(salt)\n const iv = Buffer.from(stored.iv, 'hex')\n const tag = Buffer.from(stored.tag, 'hex')\n const encrypted = Buffer.from(stored.data, 'hex')\n\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)\n // setAuthTag() MUST be called before update()\n decipher.setAuthTag(tag)\n\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ])\n\n return decrypted.toString('utf8')\n } catch {\n throw new Error(\n 'Wallet decryption failed. If you changed your hostname or username, re-configure with `chain-insights config set walletPrivateKey <key>`.',\n )\n }\n}\n\n/**\n * Returns true if wallet.json exists, false if absent.\n * Does not validate the wallet contents.\n */\nexport async function isWalletConfigured(): Promise<boolean> {\n try {\n await stat(walletPath())\n return true\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return false\n throw err\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,SAAgB,aAAqB;CACnC,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,mBAAmB,aAAa;AACjE;AAIA,SAAS,UAAU,MAAsB;CACvC,OAAO,OAAO,WACZ,GAAG,GAAG,SAAS,EAAE,GAAG,GAAG,SAAS,EAAE,YAClC,MACA,EACF;AACF;AASA,SAAgB,0BAA0B,OAAoB;CAC5D,IAAI,CAAC,sBAAsB,KAAK,KAAK,GACnC,MAAM,IAAI,MAAM,sEAAsE;CAExF,OAAO;AACT;AAEA,SAAgB,4BAA4B,YAA6B;CACvE,OAAO,oBAAoB,0BAA0B,UAAU,CAAC,EAAE;AACpE;;;;;;;;AASA,eAAsB,WAAW,YAAmC;CAClE,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,OAAO,OAAO,YAAY,EAAE;CAClC,MAAM,MAAM,UAAU,IAAI;CAC1B,MAAM,KAAK,OAAO,YAAY,EAAE;CAChC,MAAM,SAAS,OAAO,eAAe,eAAe,KAAK,EAAE;CAE3D,MAAM,YAAY,OAAO,OAAO,CAC9B,OAAO,OAAO,sBAAsB,MAAM,GAC1C,OAAO,MAAM,CACf,CAAC;CAGD,MAAM,MAAM,OAAO,WAAW;CAE9B,MAAM,aAAyB;EAC7B,MAAM,KAAK,SAAS,KAAK;EACzB,IAAI,GAAG,SAAS,KAAK;EACrB,KAAK,IAAI,SAAS,KAAK;EACvB,MAAM,UAAU,SAAS,KAAK;CAChC;CAEA,MAAM,IAAI,WAAW;CACrB,MAAM,MAAM,KAAK,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,MAAM,UAAU,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAChF;AAEA,eAAsB,oBAAoB,YAAsC;CAC9E,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,UAAU,4BAA4B,oBAAoB;CAChE,MAAM,WAAW,oBAAoB;CACrC,OAAO;AACT;;;;;;;AAQA,eAAsB,aAA8B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,WAAW,GAAG,MAAM;CAC3C,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UACnB,MAAM,IAAI,MACR,wGACF;EAEF,MAAM;CACR;CAEA,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,MAAM,MAAM,UADC,OAAO,KAAK,OAAO,MAAM,KACb,CAAC;EAC1B,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK;EACvC,MAAM,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK;EACzC,MAAM,YAAY,OAAO,KAAK,OAAO,MAAM,KAAK;EAEhD,MAAM,WAAW,OAAO,iBAAiB,eAAe,KAAK,EAAE;EAE/D,SAAS,WAAW,GAAG;EAOvB,OALkB,OAAO,OAAO,CAC9B,SAAS,OAAO,SAAS,GACzB,SAAS,MAAM,CACjB,CAEe,EAAE,SAAS,MAAM;CAClC,QAAQ;EACN,MAAM,IAAI,MACR,2IACF;CACF;AACF;;;;;AAMA,eAAsB,qBAAuC;CAC3D,IAAI;EACF,MAAM,KAAK,WAAW,CAAC;EACvB,OAAO;CACT,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UAAU,OAAO;EACtC,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"wallet-BL0fJC29.mjs","names":["nodeErr"],"sources":["../src/wallet/index.ts"],"sourcesContent":["import crypto from 'node:crypto'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { readFile, writeFile, mkdir, stat } from 'node:fs/promises'\nimport type { Address, Hex } from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\n// Path derived at call time so tests can override HOME.\nexport function walletPath(): string {\n return path.join(os.homedir(), '.chain-insights', 'wallet.json')\n}\n\n// Derive a 32-byte key from the machine identity (hostname + username) and a\n// random per-wallet salt. The salt prevents precomputation attacks across wallets.\nfunction deriveKey(salt: Buffer): Buffer {\n return crypto.scryptSync(\n `${os.hostname()}:${os.userInfo().username}`,\n salt,\n 32,\n )\n}\n\ninterface WalletData {\n salt: string\n iv: string\n tag: string\n data: string\n}\n\nexport function normalizeWalletPrivateKey(value: string): Hex {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error('Stored wallet private key is not a valid 0x-prefixed EVM private key')\n }\n return value as Hex\n}\n\nexport function walletAddressFromPrivateKey(privateKey: string): Address {\n return privateKeyToAccount(normalizeWalletPrivateKey(privateKey)).address\n}\n\n/**\n * Encrypts a private key and writes it to ~/.chain-insights/wallet.json.\n * Uses AES-256-GCM with a machine-identity-derived key and a random per-wallet salt.\n * File is written with 0o600 permissions (owner read/write only).\n *\n * @param privateKey - The EVM private key to encrypt (0x-prefixed)\n */\nexport async function encryptKey(privateKey: string): Promise<void> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const salt = crypto.randomBytes(16)\n const key = deriveKey(salt)\n const iv = crypto.randomBytes(12)\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv)\n\n const encrypted = Buffer.concat([\n cipher.update(normalizedPrivateKey, 'utf8'),\n cipher.final(),\n ])\n\n // getAuthTag() MUST be called after final()\n const tag = cipher.getAuthTag()\n\n const walletData: WalletData = {\n salt: salt.toString('hex'),\n iv: iv.toString('hex'),\n tag: tag.toString('hex'),\n data: encrypted.toString('hex'),\n }\n\n const p = walletPath()\n await mkdir(path.dirname(p), { recursive: true })\n await writeFile(p, JSON.stringify(walletData, null, 2) + '\\n', { mode: 0o600 })\n}\n\nexport async function setWalletPrivateKey(privateKey: string): Promise<Address> {\n const normalizedPrivateKey = normalizeWalletPrivateKey(privateKey)\n const address = walletAddressFromPrivateKey(normalizedPrivateKey)\n await encryptKey(normalizedPrivateKey)\n return address\n}\n\n/**\n * Reads and decrypts the private key from ~/.chain-insights/wallet.json.\n * Throws a human-readable error if wallet is absent or decryption fails.\n *\n * @returns The decrypted EVM private key string\n */\nexport async function decryptKey(): Promise<string> {\n let raw: string\n try {\n raw = await readFile(walletPath(), 'utf8')\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') {\n throw new Error(\n 'Wallet not configured. Run `chain-insights wallet import <private-key>`, then `chain-insights wallet ready`.',\n )\n }\n throw err\n }\n\n try {\n const stored = JSON.parse(raw) as WalletData\n const salt = Buffer.from(stored.salt, 'hex')\n const key = deriveKey(salt)\n const iv = Buffer.from(stored.iv, 'hex')\n const tag = Buffer.from(stored.tag, 'hex')\n const encrypted = Buffer.from(stored.data, 'hex')\n\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv)\n // setAuthTag() MUST be called before update()\n decipher.setAuthTag(tag)\n\n const decrypted = Buffer.concat([\n decipher.update(encrypted),\n decipher.final(),\n ])\n\n return decrypted.toString('utf8')\n } catch {\n throw new Error(\n 'Wallet decryption failed. If you changed your hostname or username, re-import it with `chain-insights wallet import <private-key>`.',\n )\n }\n}\n\n/**\n * Returns true if wallet.json exists, false if absent.\n * Does not validate the wallet contents.\n */\nexport async function isWalletConfigured(): Promise<boolean> {\n try {\n await stat(walletPath())\n return true\n } catch (err: unknown) {\n const nodeErr = err as NodeJS.ErrnoException\n if (nodeErr.code === 'ENOENT') return false\n throw err\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAQA,SAAgB,aAAqB;CACnC,OAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,mBAAmB,aAAa;AACjE;AAIA,SAAS,UAAU,MAAsB;CACvC,OAAO,OAAO,WACZ,GAAG,GAAG,SAAS,EAAE,GAAG,GAAG,SAAS,EAAE,YAClC,MACA,EACF;AACF;AASA,SAAgB,0BAA0B,OAAoB;CAC5D,IAAI,CAAC,sBAAsB,KAAK,KAAK,GACnC,MAAM,IAAI,MAAM,sEAAsE;CAExF,OAAO;AACT;AAEA,SAAgB,4BAA4B,YAA6B;CACvE,OAAO,oBAAoB,0BAA0B,UAAU,CAAC,EAAE;AACpE;;;;;;;;AASA,eAAsB,WAAW,YAAmC;CAClE,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,OAAO,OAAO,YAAY,EAAE;CAClC,MAAM,MAAM,UAAU,IAAI;CAC1B,MAAM,KAAK,OAAO,YAAY,EAAE;CAChC,MAAM,SAAS,OAAO,eAAe,eAAe,KAAK,EAAE;CAE3D,MAAM,YAAY,OAAO,OAAO,CAC9B,OAAO,OAAO,sBAAsB,MAAM,GAC1C,OAAO,MAAM,CACf,CAAC;CAGD,MAAM,MAAM,OAAO,WAAW;CAE9B,MAAM,aAAyB;EAC7B,MAAM,KAAK,SAAS,KAAK;EACzB,IAAI,GAAG,SAAS,KAAK;EACrB,KAAK,IAAI,SAAS,KAAK;EACvB,MAAM,UAAU,SAAS,KAAK;CAChC;CAEA,MAAM,IAAI,WAAW;CACrB,MAAM,MAAM,KAAK,QAAQ,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CAChD,MAAM,UAAU,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAChF;AAEA,eAAsB,oBAAoB,YAAsC;CAC9E,MAAM,uBAAuB,0BAA0B,UAAU;CACjE,MAAM,UAAU,4BAA4B,oBAAoB;CAChE,MAAM,WAAW,oBAAoB;CACrC,OAAO;AACT;;;;;;;AAQA,eAAsB,aAA8B;CAClD,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,WAAW,GAAG,MAAM;CAC3C,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UACnB,MAAM,IAAI,MACR,8GACF;EAEF,MAAM;CACR;CAEA,IAAI;EACF,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,MAAM,MAAM,UADC,OAAO,KAAK,OAAO,MAAM,KACb,CAAC;EAC1B,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,KAAK;EACvC,MAAM,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK;EACzC,MAAM,YAAY,OAAO,KAAK,OAAO,MAAM,KAAK;EAEhD,MAAM,WAAW,OAAO,iBAAiB,eAAe,KAAK,EAAE;EAE/D,SAAS,WAAW,GAAG;EAOvB,OALkB,OAAO,OAAO,CAC9B,SAAS,OAAO,SAAS,GACzB,SAAS,MAAM,CACjB,CAEe,EAAE,SAAS,MAAM;CAClC,QAAQ;EACN,MAAM,IAAI,MACR,qIACF;CACF;AACF;;;;;AAMA,eAAsB,qBAAuC;CAC3D,IAAI;EACF,MAAM,KAAK,WAAW,CAAC;EACvB,OAAO;CACT,SAAS,KAAc;EAErB,IAAIA,IAAQ,SAAS,UAAU,OAAO;EACtC,MAAM;CACR;AACF"}
@@ -72,7 +72,7 @@ async function decryptKey() {
72
72
  try {
73
73
  raw = await (0, node_fs_promises.readFile)(walletPath(), "utf8");
74
74
  } catch (err) {
75
- if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights config set walletPrivateKey <key>` to enable paid MCP calls");
75
+ if (err.code === "ENOENT") throw new Error("Wallet not configured. Run `chain-insights wallet import <private-key>`, then `chain-insights wallet ready`.");
76
76
  throw err;
77
77
  }
78
78
  try {
@@ -85,7 +85,7 @@ async function decryptKey() {
85
85
  decipher.setAuthTag(tag);
86
86
  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
87
87
  } catch {
88
- throw new Error("Wallet decryption failed. If you changed your hostname or username, re-configure with `chain-insights config set walletPrivateKey <key>`.");
88
+ throw new Error("Wallet decryption failed. If you changed your hostname or username, re-import it with `chain-insights wallet import <private-key>`.");
89
89
  }
90
90
  }
91
91
  /**
package/docs/mcp-proxy.md CHANGED
@@ -119,7 +119,7 @@ Paid x402 mode:
119
119
  ```bash
120
120
  chain-insights config set graphMcpEndpoint https://staging-mcp.chain-insights.ai/mcp
121
121
  chain-insights debug off
122
- chain-insights config set walletPrivateKey 0xYOUR_EVM_PRIVATE_KEY
122
+ chain-insights wallet import 0xYOUR_EVM_PRIVATE_KEY
123
123
  chain-insights wallet ready
124
124
  ```
125
125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chain-insights",
3
- "version": "0.2.27",
3
+ "version": "0.2.28",
4
4
  "description": "AML investigation CLI and MCP proxy for blockchain risk, fund-flow tracing, case reports, and GraphRAG MCP access",
5
5
  "homepage": "https://chain-insights.ai",
6
6
  "repository": {