chain-insights 0.3.6 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +18 -13
  2. package/dist/{capabilities-BC3Y5EOi.mjs → capabilities-BCvkTkIu.mjs} +3 -6
  3. package/dist/capabilities-BCvkTkIu.mjs.map +1 -0
  4. package/dist/{capabilities-D5PSx9Hj.cjs → capabilities-DOa6EFO-.cjs} +2 -5
  5. package/dist/cli.cjs +41 -14
  6. package/dist/cli.mjs +41 -14
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/{client-D4JE7fFF.mjs → client-BgmHjBHQ.mjs} +15 -7
  9. package/dist/client-BgmHjBHQ.mjs.map +1 -0
  10. package/dist/{client-Db6IV1tv.cjs → client-Y_zqKqJT.cjs} +19 -5
  11. package/dist/index.cjs +1 -1
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.mts.map +1 -1
  14. package/dist/index.mjs +1 -1
  15. package/dist/mcp-proxy.cjs +442 -408
  16. package/dist/mcp-proxy.d.cts +3 -1
  17. package/dist/mcp-proxy.d.cts.map +1 -1
  18. package/dist/mcp-proxy.d.mts +3 -1
  19. package/dist/mcp-proxy.d.mts.map +1 -1
  20. package/dist/mcp-proxy.mjs +442 -409
  21. package/dist/mcp-proxy.mjs.map +1 -1
  22. package/dist/{public-tools-xfVNz9NE.cjs → public-tools-BY3PTw6x.cjs} +59 -31
  23. package/dist/{public-tools-CyUZEz9B.mjs → public-tools-CvlZcysd.mjs} +60 -32
  24. package/dist/public-tools-CvlZcysd.mjs.map +1 -0
  25. package/dist/{runner-DWuSy1Se.mjs → runner-CVnjpqc-.mjs} +2 -2
  26. package/dist/{runner-DWuSy1Se.mjs.map → runner-CVnjpqc-.mjs.map} +1 -1
  27. package/dist/{runner-CVo41fjz.cjs → runner-bLy0pTr_.cjs} +1 -1
  28. package/dist/update-BJoXYucO.cjs +145 -0
  29. package/dist/update-CJUfGCxs.mjs +145 -0
  30. package/dist/update-CJUfGCxs.mjs.map +1 -0
  31. package/docs/graph-tools.md +8 -8
  32. package/docs/mcp-proxy.md +14 -14
  33. package/package.json +1 -1
  34. package/dist/capabilities-BC3Y5EOi.mjs.map +0 -1
  35. package/dist/client-D4JE7fFF.mjs.map +0 -1
  36. package/dist/public-tools-CyUZEz9B.mjs.map +0 -1
package/README.md CHANGED
@@ -19,7 +19,7 @@ MCP endpoint for development; hosted endpoints are set explicitly with
19
19
  | `trace_victim_funds` | Trace victim/source funds forward to exchange deposit candidates |
20
20
  | `trace_deposit_sources` | Trace backward from suspected deposit/cashout addresses to upstream sources and convergence |
21
21
  | `trace_suspect_funds` | Trace suspected scammer, mule, operator, or laundering-ring funds forward to cashout topology |
22
- | `usage_status` | Check the caller's public free graph query quota for today |
22
+ | `usage_status` | Check the caller's daily free-tier graph query allowance |
23
23
  | `graph_query` | Run one read-only GQL/Cypher query against a GraphRAG MCP graph layer |
24
24
  | `graph_query_batch` | Run related read-only graph queries as one MCP call |
25
25
 
@@ -35,8 +35,13 @@ Check the CLI:
35
35
 
36
36
  ```bash
37
37
  cia --version
38
+ cia update --check
38
39
  ```
39
40
 
41
+ Run `cia update` to update a global npm install from the public npmjs registry.
42
+ `cia init` also checks for a newer npm release in interactive terminals and
43
+ prompts before updating.
44
+
40
45
  From a local checkout:
41
46
 
42
47
  ```bash
@@ -117,14 +122,14 @@ If network or tool discovery fails, check the endpoint and access mode first.
117
122
  The CLI can still initialize workspaces and manage cases without a reachable
118
123
  GraphRAG MCP endpoint.
119
124
 
120
- Hosted GraphRAG MCP lets new users try `graph_query` with a small public free
121
- quota before setting up paid access. The default public free graph_query quota
122
- is 10 execution seconds per IP per UTC day. Use `usage_status` to see the
123
- current caller quota. Prepared wallet users receive the daily public grant
124
- first, then paid access continues automatically after the grant is exhausted.
125
+ Hosted GraphRAG MCP includes a small public free tier for `graph_query` before
126
+ paid access is required. The default public free tier is 10 execution seconds
127
+ per IP per UTC day. Use `usage_status` to see the current caller allowance.
128
+ Prepared wallet users receive the daily free tier first, then paid access
129
+ continues automatically after the allowance is exhausted.
125
130
  If you do not have a prepared wallet yet, use bounded single `graph_query`
126
- calls for the demo, then prepare a wallet or use an invited tester access key
127
- when the quota is exhausted.
131
+ calls within the free tier, then prepare a wallet or use an invited tester
132
+ access key when the allowance is exhausted.
128
133
 
129
134
  Open a case and run a small investigation:
130
135
 
@@ -162,12 +167,12 @@ The export writes Markdown notes, `manifest.chain-insights.json`,
162
167
  for Codex, Claude Code, and ChatGPT under `published/<case-slug>/`.
163
168
 
164
169
  Private exports may include full addresses. Use `--mode partner` for controlled
165
- handoff after review. Use `--mode public` only for shareable demos; public mode
170
+ handoff after review. Use `--mode public` only for shareable examples; public mode
166
171
  aliases addresses and removes secrets by default. Vault workflow guidance lives
167
172
  in [Obsidian vault workflow](docs/obsidian-vault.md); export bundle details
168
173
  live in [Knowledge exports](docs/knowledge-exports.md).
169
174
 
170
- ## Demo
175
+ ## Examples
171
176
 
172
177
  Run a direct live topology query:
173
178
 
@@ -185,9 +190,9 @@ cia mcp call graph_query_batch \
185
190
  'queries=[{"id":"count","query":"USE live_topology MATCH (n) RETURN count(n) AS count LIMIT 1"},{"id":"archive_flows","query":"USE archive_topology MATCH (src:Address)-[f:FLOWS_TO]->(dst:Address) RETURN f.period_granularity AS granularity, src.address AS source, dst.address AS target LIMIT 3"},{"id":"facts_sample","query":"USE facts MATCH (a:Address)-[:HAS_FEATURE]->(f:AddressFeature) RETURN a.address AS address, f.sent_count AS sent_count LIMIT 3"}]'
186
191
  ```
187
192
 
188
- For no-wallet public demos, prefer the single-query example first. Batch calls
189
- reserve worst-case execution time and can ask for paid access even when a small
190
- free balance remains.
193
+ For no-wallet public free-tier usage, prefer the single-query example first.
194
+ Batch calls reserve worst-case execution time and can ask for paid access even
195
+ when a small free allowance remains.
191
196
 
192
197
  Run suspect topology without requiring an incident timestamp:
193
198
 
@@ -1,4 +1,4 @@
1
- import { a as resolveGraphMcpEndpoint } from "./client-D4JE7fFF.mjs";
1
+ import { n as applyMcpAuthHeaders, o as resolveGraphMcpEndpoint } from "./client-BgmHjBHQ.mjs";
2
2
  //#region src/mcp/capabilities.ts
3
3
  function metadataNetworksUrl(endpoint) {
4
4
  const url = new URL(endpoint);
@@ -11,10 +11,7 @@ async function fetchNetworkCapabilities(config) {
11
11
  const request = metadataNetworksUrl(resolveGraphMcpEndpoint(config));
12
12
  const headers = new Headers();
13
13
  const token = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim();
14
- if (token) {
15
- headers.set("X-MCP-Debug-Token", token);
16
- headers.set("Authorization", `Bearer ${token}`);
17
- }
14
+ if (token) applyMcpAuthHeaders(headers, token);
18
15
  let response;
19
16
  try {
20
17
  response = await fetch(request, { headers });
@@ -81,4 +78,4 @@ function formatNetworkCapabilities(document) {
81
78
  //#endregion
82
79
  export { fetchNetworkCapabilities, formatNetworkCapabilities };
83
80
 
84
- //# sourceMappingURL=capabilities-BC3Y5EOi.mjs.map
81
+ //# sourceMappingURL=capabilities-BCvkTkIu.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities-BCvkTkIu.mjs","names":[],"sources":["../src/mcp/capabilities.ts"],"sourcesContent":["import type { InvestigatorConfig } from '../config/schema.js'\nimport { applyMcpAuthHeaders, 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 applyMcpAuthHeaders(headers, token)\n }\n let response: Response\n try {\n response = await fetch(request, { headers })\n } catch (err) {\n throw new Error(`network capabilities unavailable at ${request}: ${(err as Error).message}`)\n }\n if (!response.ok) {\n throw new Error(`network capabilities unavailable at ${request}: HTTP ${response.status}`)\n }\n const parsed = await response.json() as NetworkCapabilitiesDocument\n if (parsed.schema !== 'chain-insights.network-capabilities.v1' || !Array.isArray(parsed.networks)) {\n throw new Error('network capabilities response has unsupported schema')\n }\n return 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,OACF,oBAAoB,SAAS,KAAK;CAEpC,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,MAAM,SAAS,EAAE,QAAQ,CAAC;CAC7C,SAAS,KAAK;EACZ,MAAM,IAAI,MAAM,uCAAuC,QAAQ,IAAK,IAAc,SAAS;CAC7F;CACA,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,uCAAuC,QAAQ,SAAS,SAAS,QAAQ;CAE3F,MAAM,SAAS,MAAM,SAAS,KAAK;CACnC,IAAI,OAAO,WAAW,4CAA4C,CAAC,MAAM,QAAQ,OAAO,QAAQ,GAC9F,MAAM,IAAI,MAAM,sDAAsD;CAExE,OAAO;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,4 +1,4 @@
1
- const require_client = require("./client-Db6IV1tv.cjs");
1
+ const require_client = require("./client-Y_zqKqJT.cjs");
2
2
  //#region src/mcp/capabilities.ts
3
3
  function metadataNetworksUrl(endpoint) {
4
4
  const url = new URL(endpoint);
@@ -11,10 +11,7 @@ async function fetchNetworkCapabilities(config) {
11
11
  const request = metadataNetworksUrl(require_client.resolveGraphMcpEndpoint(config));
12
12
  const headers = new Headers();
13
13
  const token = config.graphMcpAuthToken?.trim() || config.mcpAuthToken?.trim();
14
- if (token) {
15
- headers.set("X-MCP-Debug-Token", token);
16
- headers.set("Authorization", `Bearer ${token}`);
17
- }
14
+ if (token) require_client.applyMcpAuthHeaders(headers, token);
18
15
  let response;
19
16
  try {
20
17
  response = await fetch(request, { headers });
package/dist/cli.cjs CHANGED
@@ -72,7 +72,7 @@ function optionalNumberArg(value, name) {
72
72
  async function withGraphMcpClient(name, fn) {
73
73
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
74
74
  const config = await loadConfig();
75
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Db6IV1tv.cjs")).then((n) => n.client_exports);
75
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Y_zqKqJT.cjs")).then((n) => n.client_exports);
76
76
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
77
77
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
78
78
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -92,7 +92,7 @@ function printMcpTextContent(result) {
92
92
  }
93
93
  async function printNetworkCapabilities(opts) {
94
94
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
95
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-D5PSx9Hj.cjs"));
95
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-DOa6EFO-.cjs"));
96
96
  const document = await fetchNetworkCapabilities(await loadConfig());
97
97
  if (opts.json) console.log(JSON.stringify(document, null, 2));
98
98
  else console.log(formatNetworkCapabilities(document));
@@ -129,6 +129,31 @@ program.command("status").description("Show toolkit status and configuration").a
129
129
  console.log("Graph MCP:", graphMcpStatus);
130
130
  console.log("Graph endpoint:", config.graphMcpEndpoint);
131
131
  });
132
+ program.command("update").description("Check npmjs for a newer Chain Insights release and update this CLI").option("--check", "Only check for a newer release").option("--dry-run", "Print the update command without running it").action(async (opts) => {
133
+ try {
134
+ const { checkForUpdate, runPackageUpdate } = await Promise.resolve().then(() => require("./update-BJoXYucO.cjs"));
135
+ const result = await checkForUpdate();
136
+ if (result.error) throw new Error(`Could not check npmjs for updates: ${result.error}`);
137
+ if (!result.updateAvailable || !result.latestVersion) {
138
+ console.log(`Chain Insights is up to date (${result.currentVersion}).`);
139
+ return;
140
+ }
141
+ console.log(`Chain Insights ${result.latestVersion} is available (current ${result.currentVersion}).`);
142
+ if (opts.check) {
143
+ console.log(`Run: ${result.updateCommand}`);
144
+ return;
145
+ }
146
+ if (opts.dryRun) {
147
+ console.log(`Would run: ${result.updateCommand}`);
148
+ return;
149
+ }
150
+ console.log(`Running: ${result.updateCommand}`);
151
+ runPackageUpdate(result.packageName);
152
+ } catch (err) {
153
+ console.error(err.message);
154
+ process.exit(1);
155
+ }
156
+ });
132
157
  program.command("obsidian").description("Manage the local Obsidian investigation vault").addCommand(new commander.Command("open").description("Open the current Chain Insights vault in Obsidian").argument("[path]", "Workspace path to open as an Obsidian vault").action(async (workspacePath) => {
133
158
  try {
134
159
  const { findActiveWorkspace } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
@@ -240,6 +265,8 @@ program.command("init").description("Initialize an investigation workspace").arg
240
265
  });
241
266
  console.log(`Workspace initialized: ${result.workspaceRoot}`);
242
267
  console.log(`Files written: ${result.filesWritten.length}`);
268
+ const { maybePromptForUpdate } = await Promise.resolve().then(() => require("./update-BJoXYucO.cjs"));
269
+ await maybePromptForUpdate();
243
270
  } catch (err) {
244
271
  console.error(err.message);
245
272
  process.exit(1);
@@ -383,7 +410,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
383
410
  const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
384
411
  const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-Buq7YdUZ.cjs")).then((n) => n.tool_visibility_exports);
385
412
  const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
386
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Db6IV1tv.cjs")).then((n) => n.client_exports);
413
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-Y_zqKqJT.cjs")).then((n) => n.client_exports);
387
414
  const config = await loadConfig();
388
415
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
389
416
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -422,7 +449,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
422
449
  }));
423
450
  return;
424
451
  }
425
- const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
452
+ const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
426
453
  const result = await addressRisk(client, {
427
454
  address: opts.address,
428
455
  network: opts.network,
@@ -450,7 +477,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
450
477
  }));
451
478
  return;
452
479
  }
453
- const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
480
+ const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
454
481
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
455
482
  const result = await traceVictimFunds(client, config, {
456
483
  victimAddresses: opts.victimAddresses,
@@ -474,7 +501,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
474
501
  const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
475
502
  requireWorkspaceRoot();
476
503
  await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
477
- const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
504
+ const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
478
505
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
479
506
  const result = await traceSuspectFunds(client, config, {
480
507
  suspectAddresses: opts.suspectAddresses,
@@ -497,7 +524,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
497
524
  const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
498
525
  requireWorkspaceRoot();
499
526
  await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
500
- const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
527
+ const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
501
528
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
502
529
  const result = await traceDepositSources(client, config, {
503
530
  depositAddresses: opts.depositAddresses,
@@ -515,7 +542,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
515
542
  })).addCommand(new commander.Command("stake-insights").description("Explain Bittensor staking behavior around an address, coldkey, or hotkey").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--address <address>", "Full Bittensor address to inspect as either coldkey or hotkey").option("--coldkey <address>", "Full Bittensor coldkey address to inspect").option("--hotkey <address>", "Full Bittensor hotkey address to inspect").option("--netuid <number>", "Optional subnet netuid filter").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--start-block <number>", "Optional start block. Current stake graph parity may require timestamp windows instead.").option("--end-block <number>", "Optional end block. Current stake graph parity may require timestamp windows instead.").option("--depth <number>", "Optional expansion depth limit, default 1, max 3").action(async (opts) => {
516
543
  try {
517
544
  await withGraphMcpClient("chain-insights-cli-stake-insights", async (client) => {
518
- const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
545
+ const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
519
546
  const result = await stakeInsights(client, {
520
547
  network: opts.network,
521
548
  address: opts.address,
@@ -543,7 +570,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
543
570
  assertPublicMcpToolName(tool);
544
571
  await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
545
572
  if (tool === "address_risk") {
546
- const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
573
+ const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
547
574
  const result = await addressRisk(client, {
548
575
  address: String(args["address"] ?? ""),
549
576
  network: String(args["network"] ?? ""),
@@ -553,7 +580,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
553
580
  return;
554
581
  }
555
582
  if (tool === "trace_victim_funds") {
556
- const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
583
+ const { traceVictimFunds } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
557
584
  const result = await traceVictimFunds(client, config, {
558
585
  victimAddresses: args["victim_addresses"] ?? "",
559
586
  knownSuspectAddresses: args["known_suspect_addresses"],
@@ -569,7 +596,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
569
596
  return;
570
597
  }
571
598
  if (tool === "trace_suspect_funds") {
572
- const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
599
+ const { traceSuspectFunds } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
573
600
  const result = await traceSuspectFunds(client, config, {
574
601
  suspectAddresses: args["suspect_addresses"] ?? "",
575
602
  network: String(args["network"] ?? ""),
@@ -584,7 +611,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
584
611
  return;
585
612
  }
586
613
  if (tool === "trace_deposit_sources") {
587
- const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
614
+ const { traceDepositSources } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
588
615
  const result = await traceDepositSources(client, config, {
589
616
  depositAddresses: args["deposit_addresses"] ?? "",
590
617
  network: String(args["network"] ?? ""),
@@ -596,7 +623,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
596
623
  return;
597
624
  }
598
625
  if (tool === "stake_insights") {
599
- const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-xfVNz9NE.cjs"));
626
+ const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BY3PTw6x.cjs"));
600
627
  const result = await stakeInsights(client, {
601
628
  network: String(args["network"] ?? ""),
602
629
  address: args["address"] === void 0 ? void 0 : String(args["address"]),
@@ -850,7 +877,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
850
877
  console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
851
878
  process.exit(1);
852
879
  }
853
- const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-CVo41fjz.cjs"));
880
+ const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-bLy0pTr_.cjs"));
854
881
  await PlaybookRunner.run(definition, {
855
882
  caseId: opts.case,
856
883
  from: fromN,
package/dist/cli.mjs CHANGED
@@ -70,7 +70,7 @@ function optionalNumberArg(value, name) {
70
70
  async function withGraphMcpClient(name, fn) {
71
71
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
72
72
  const config = await loadConfig();
73
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4JE7fFF.mjs").then((n) => n.n);
73
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-BgmHjBHQ.mjs").then((n) => n.r);
74
74
  const paymentFetch = await createConfiguredGraphMcpFetch(config);
75
75
  const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
76
76
  const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
@@ -90,7 +90,7 @@ function printMcpTextContent(result) {
90
90
  }
91
91
  async function printNetworkCapabilities(opts) {
92
92
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
93
- const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BC3Y5EOi.mjs");
93
+ const { fetchNetworkCapabilities, formatNetworkCapabilities } = await import("./capabilities-BCvkTkIu.mjs");
94
94
  const document = await fetchNetworkCapabilities(await loadConfig());
95
95
  if (opts.json) console.log(JSON.stringify(document, null, 2));
96
96
  else console.log(formatNetworkCapabilities(document));
@@ -127,6 +127,31 @@ program.command("status").description("Show toolkit status and configuration").a
127
127
  console.log("Graph MCP:", graphMcpStatus);
128
128
  console.log("Graph endpoint:", config.graphMcpEndpoint);
129
129
  });
130
+ program.command("update").description("Check npmjs for a newer Chain Insights release and update this CLI").option("--check", "Only check for a newer release").option("--dry-run", "Print the update command without running it").action(async (opts) => {
131
+ try {
132
+ const { checkForUpdate, runPackageUpdate } = await import("./update-CJUfGCxs.mjs");
133
+ const result = await checkForUpdate();
134
+ if (result.error) throw new Error(`Could not check npmjs for updates: ${result.error}`);
135
+ if (!result.updateAvailable || !result.latestVersion) {
136
+ console.log(`Chain Insights is up to date (${result.currentVersion}).`);
137
+ return;
138
+ }
139
+ console.log(`Chain Insights ${result.latestVersion} is available (current ${result.currentVersion}).`);
140
+ if (opts.check) {
141
+ console.log(`Run: ${result.updateCommand}`);
142
+ return;
143
+ }
144
+ if (opts.dryRun) {
145
+ console.log(`Would run: ${result.updateCommand}`);
146
+ return;
147
+ }
148
+ console.log(`Running: ${result.updateCommand}`);
149
+ runPackageUpdate(result.packageName);
150
+ } catch (err) {
151
+ console.error(err.message);
152
+ process.exit(1);
153
+ }
154
+ });
130
155
  program.command("obsidian").description("Manage the local Obsidian investigation vault").addCommand(new Command("open").description("Open the current Chain Insights vault in Obsidian").argument("[path]", "Workspace path to open as an Obsidian vault").action(async (workspacePath) => {
131
156
  try {
132
157
  const { findActiveWorkspace } = await import("./active-ByNgjuAg.mjs").then((n) => n.n);
@@ -238,6 +263,8 @@ program.command("init").description("Initialize an investigation workspace").arg
238
263
  });
239
264
  console.log(`Workspace initialized: ${result.workspaceRoot}`);
240
265
  console.log(`Files written: ${result.filesWritten.length}`);
266
+ const { maybePromptForUpdate } = await import("./update-CJUfGCxs.mjs");
267
+ await maybePromptForUpdate();
241
268
  } catch (err) {
242
269
  console.error(err.message);
243
270
  process.exit(1);
@@ -381,7 +408,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
381
408
  const { formatToolsTable } = await import("./format-Bq94jSyw.mjs");
382
409
  const { visibleRemoteTools } = await import("./tool-visibility-BpyZHRBi.mjs").then((n) => n.n);
383
410
  const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
384
- const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-D4JE7fFF.mjs").then((n) => n.n);
411
+ const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await import("./client-BgmHjBHQ.mjs").then((n) => n.r);
385
412
  const config = await loadConfig();
386
413
  const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
387
414
  let tools = opts.refresh ? null : await loadSchema(graphMcpEndpoint);
@@ -420,7 +447,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
420
447
  }));
421
448
  return;
422
449
  }
423
- const { addressRisk } = await import("./public-tools-CyUZEz9B.mjs");
450
+ const { addressRisk } = await import("./public-tools-CvlZcysd.mjs");
424
451
  const result = await addressRisk(client, {
425
452
  address: opts.address,
426
453
  network: opts.network,
@@ -448,7 +475,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
448
475
  }));
449
476
  return;
450
477
  }
451
- const { traceVictimFunds } = await import("./public-tools-CyUZEz9B.mjs");
478
+ const { traceVictimFunds } = await import("./public-tools-CvlZcysd.mjs");
452
479
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
453
480
  const result = await traceVictimFunds(client, config, {
454
481
  victimAddresses: opts.victimAddresses,
@@ -472,7 +499,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
472
499
  const { requireWorkspaceRoot } = await import("./output-root-BRhzhhXZ.mjs").then((n) => n.t);
473
500
  requireWorkspaceRoot();
474
501
  await withGraphMcpClient("chain-insights-cli-trace-suspect-funds", async (client, config) => {
475
- const { traceSuspectFunds } = await import("./public-tools-CyUZEz9B.mjs");
502
+ const { traceSuspectFunds } = await import("./public-tools-CvlZcysd.mjs");
476
503
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
477
504
  const result = await traceSuspectFunds(client, config, {
478
505
  suspectAddresses: opts.suspectAddresses,
@@ -495,7 +522,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
495
522
  const { requireWorkspaceRoot } = await import("./output-root-BRhzhhXZ.mjs").then((n) => n.t);
496
523
  requireWorkspaceRoot();
497
524
  await withGraphMcpClient("chain-insights-cli-trace-deposit-sources", async (client, config) => {
498
- const { traceDepositSources } = await import("./public-tools-CyUZEz9B.mjs");
525
+ const { traceDepositSources } = await import("./public-tools-CvlZcysd.mjs");
499
526
  const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
500
527
  const result = await traceDepositSources(client, config, {
501
528
  depositAddresses: opts.depositAddresses,
@@ -513,7 +540,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
513
540
  })).addCommand(new Command("stake-insights").description("Explain Bittensor staking behavior around an address, coldkey, or hotkey").requiredOption("--network <network>", "Network to query. Run `cia mcp networks` for supported networks.").option("--address <address>", "Full Bittensor address to inspect as either coldkey or hotkey").option("--coldkey <address>", "Full Bittensor coldkey address to inspect").option("--hotkey <address>", "Full Bittensor hotkey address to inspect").option("--netuid <number>", "Optional subnet netuid filter").option("--start-timestamp-ms <milliseconds>", "Optional inclusive lower activity timestamp bound").option("--end-timestamp-ms <milliseconds>", "Optional inclusive upper activity timestamp bound").option("--start-block <number>", "Optional start block. Current stake graph parity may require timestamp windows instead.").option("--end-block <number>", "Optional end block. Current stake graph parity may require timestamp windows instead.").option("--depth <number>", "Optional expansion depth limit, default 1, max 3").action(async (opts) => {
514
541
  try {
515
542
  await withGraphMcpClient("chain-insights-cli-stake-insights", async (client) => {
516
- const { stakeInsights } = await import("./public-tools-CyUZEz9B.mjs");
543
+ const { stakeInsights } = await import("./public-tools-CvlZcysd.mjs");
517
544
  const result = await stakeInsights(client, {
518
545
  network: opts.network,
519
546
  address: opts.address,
@@ -541,7 +568,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
541
568
  assertPublicMcpToolName(tool);
542
569
  await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
543
570
  if (tool === "address_risk") {
544
- const { addressRisk } = await import("./public-tools-CyUZEz9B.mjs");
571
+ const { addressRisk } = await import("./public-tools-CvlZcysd.mjs");
545
572
  const result = await addressRisk(client, {
546
573
  address: String(args["address"] ?? ""),
547
574
  network: String(args["network"] ?? ""),
@@ -551,7 +578,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
551
578
  return;
552
579
  }
553
580
  if (tool === "trace_victim_funds") {
554
- const { traceVictimFunds } = await import("./public-tools-CyUZEz9B.mjs");
581
+ const { traceVictimFunds } = await import("./public-tools-CvlZcysd.mjs");
555
582
  const result = await traceVictimFunds(client, config, {
556
583
  victimAddresses: args["victim_addresses"] ?? "",
557
584
  knownSuspectAddresses: args["known_suspect_addresses"],
@@ -567,7 +594,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
567
594
  return;
568
595
  }
569
596
  if (tool === "trace_suspect_funds") {
570
- const { traceSuspectFunds } = await import("./public-tools-CyUZEz9B.mjs");
597
+ const { traceSuspectFunds } = await import("./public-tools-CvlZcysd.mjs");
571
598
  const result = await traceSuspectFunds(client, config, {
572
599
  suspectAddresses: args["suspect_addresses"] ?? "",
573
600
  network: String(args["network"] ?? ""),
@@ -582,7 +609,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
582
609
  return;
583
610
  }
584
611
  if (tool === "trace_deposit_sources") {
585
- const { traceDepositSources } = await import("./public-tools-CyUZEz9B.mjs");
612
+ const { traceDepositSources } = await import("./public-tools-CvlZcysd.mjs");
586
613
  const result = await traceDepositSources(client, config, {
587
614
  depositAddresses: args["deposit_addresses"] ?? "",
588
615
  network: String(args["network"] ?? ""),
@@ -594,7 +621,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
594
621
  return;
595
622
  }
596
623
  if (tool === "stake_insights") {
597
- const { stakeInsights } = await import("./public-tools-CyUZEz9B.mjs");
624
+ const { stakeInsights } = await import("./public-tools-CvlZcysd.mjs");
598
625
  const result = await stakeInsights(client, {
599
626
  network: String(args["network"] ?? ""),
600
627
  address: args["address"] === void 0 ? void 0 : String(args["address"]),
@@ -848,7 +875,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
848
875
  console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
849
876
  process.exit(1);
850
877
  }
851
- const { PlaybookRunner } = await import("./runner-DWuSy1Se.mjs");
878
+ const { PlaybookRunner } = await import("./runner-CVnjpqc-.mjs");
852
879
  await PlaybookRunner.run(definition, {
853
880
  caseId: opts.case,
854
881
  from: fromN,