chain-insights 0.2.18 → 0.2.20
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.
- package/README.md +38 -0
- package/bin/cli.js +2 -3
- package/bin/install.cjs +0 -1
- package/dist/{app-DxlQE_P5.cjs → app-BxojXjtB.cjs} +1 -1
- package/dist/{app-DdWQF_zb.mjs → app-CRd39JJ8.mjs} +2 -2
- package/dist/{app-DdWQF_zb.mjs.map → app-CRd39JJ8.mjs.map} +1 -1
- package/dist/{artifact-server-4DiMvwhC.mjs → artifact-server-CP6LXQ9d.mjs} +2 -2
- package/dist/{artifact-server-4DiMvwhC.mjs.map → artifact-server-CP6LXQ9d.mjs.map} +1 -1
- package/dist/{artifact-server-B-3ho4bk.cjs → artifact-server-XbN16DwU.cjs} +1 -1
- package/dist/cli.cjs +66 -25
- package/dist/cli.mjs +66 -25
- package/dist/cli.mjs.map +1 -1
- package/dist/{config-BhYbhLDI.cjs → config-BwVx19Og.cjs} +48 -15
- package/dist/config-Drgc2HuF.mjs +77 -0
- package/dist/config-Drgc2HuF.mjs.map +1 -0
- package/dist/frontmatter-D0ccQnUM.mjs.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{init-CZbZegIW.mjs → init-4tn7jfhN.mjs} +3 -2
- package/dist/init-4tn7jfhN.mjs.map +1 -0
- package/dist/{init-BvpZtFiT.cjs → init-TCQY5RDJ.cjs} +2 -1
- package/dist/mcp-endpoint-BaV8h_lq.cjs +60 -0
- package/dist/mcp-endpoint-DHs1cRFH.mjs +39 -0
- package/dist/mcp-endpoint-DHs1cRFH.mjs.map +1 -0
- package/dist/mcp-proxy.cjs +108 -9
- package/dist/mcp-proxy.d.cts.map +1 -1
- package/dist/mcp-proxy.d.mts.map +1 -1
- package/dist/mcp-proxy.mjs +108 -9
- package/dist/mcp-proxy.mjs.map +1 -1
- package/dist/{public-tools-D6Q5MTcO.mjs → public-tools-B13J0MJZ.mjs} +465 -70
- package/dist/public-tools-B13J0MJZ.mjs.map +1 -0
- package/dist/{public-tools-V7ON7goq.cjs → public-tools-BC1fi0DV.cjs} +464 -68
- package/dist/resolver-D7VBb0uB.mjs.map +1 -1
- package/dist/{runner-BatyCxv7.mjs → runner-DIs04IhN.mjs} +2 -2
- package/dist/{runner-BatyCxv7.mjs.map → runner-DIs04IhN.mjs.map} +1 -1
- package/dist/{runner-CCA7SJ7X.cjs → runner-ZYowxCVl.cjs} +1 -1
- package/dist/schema-BFEWhzg7.mjs +60 -0
- package/dist/schema-BFEWhzg7.mjs.map +1 -0
- package/dist/{schema-DN-KLkYN.cjs → schema-Vl9yuOFO.cjs} +31 -8
- package/dist/{server-BDlbmGbL.mjs → server-BXLX2j_A.mjs} +2 -2
- package/dist/{server-BDlbmGbL.mjs.map → server-BXLX2j_A.mjs.map} +1 -1
- package/dist/{server-C3y1gQmZ.cjs → server-BqVdWath.cjs} +1 -1
- package/dist/{topup-server-6MH7q73X.mjs → topup-server-BJgVw6Jt.mjs} +100 -42
- package/dist/topup-server-BJgVw6Jt.mjs.map +1 -0
- package/dist/{topup-server-DjUjhNjv.cjs → topup-server-yAaXYkJP.cjs} +98 -40
- package/docs/contributing.md +1 -0
- package/docs/debugging.md +10 -14
- package/docs/graph-tools.md +60 -2
- package/docs/mcp-proxy.md +3 -0
- package/package.json +1 -1
- package/skills/chain-insights-developer-experience/SKILL.md +4 -2
- package/skills/chain-insights-investigation/SKILL.md +1 -1
- package/skills/test-chain-insights-graphrag-mcp/SKILL.md +4 -5
- package/skills/test-chain-insights-graphrag-mcp/scripts/run-uat.sh +5 -24
- package/dist/config-9KYXaAv-.mjs +0 -44
- package/dist/config-9KYXaAv-.mjs.map +0 -1
- package/dist/init-CZbZegIW.mjs.map +0 -1
- package/dist/public-tools-D6Q5MTcO.mjs.map +0 -1
- package/dist/schema-BbQVXp36.mjs +0 -37
- package/dist/schema-BbQVXp36.mjs.map +0 -1
- package/dist/topup-server-6MH7q73X.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ evidence pointers, dossiers, and reports.
|
|
|
16
16
|
| Tool | Use it for |
|
|
17
17
|
| --- | --- |
|
|
18
18
|
| `address_risk` | Screen one address for risk, behavior, neighborhood context, and exchange exposure |
|
|
19
|
+
| `stake_insights` | Explain Bittensor staking relationships, net stake movement, and counterparties |
|
|
19
20
|
| `track_funds` | Trace victim/source funds through intermediaries to exchange deposit candidates |
|
|
20
21
|
| `scam_topology` | Expand a known victim incident into reviewable scam infrastructure and label candidates |
|
|
21
22
|
| `graph_query` | Run one read-only GQL/Cypher query against a GraphRAG MCP graph layer |
|
|
@@ -52,6 +53,40 @@ cd ./chain-insights-investigations
|
|
|
52
53
|
cia init .
|
|
53
54
|
```
|
|
54
55
|
|
|
56
|
+
## Configure MCP server address
|
|
57
|
+
|
|
58
|
+
`cia` uses `graphMcpEndpoint` for all GraphRAG MCP calls. Configure it explicitly per environment.
|
|
59
|
+
|
|
60
|
+
1. Local GraphRAG MCP (loopback HTTP allowed):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cia config set graphMcpEndpoint http://127.0.0.1:8012/mcp
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. Hosted staging/production GraphRAG MCP (HTTPS required):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
cia config set graphMcpEndpoint https://staging-mcp.chain-insights.ai/mcp
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
3. Optional one-shot override from environment (highest precedence for that process):
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
export CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT=https://prod-mcp.example.com/mcp
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Validation rules:
|
|
79
|
+
|
|
80
|
+
- `http://` is accepted only for `localhost` / loopback addresses.
|
|
81
|
+
- Remote hosts must use `https://`.
|
|
82
|
+
- Endpoint URLs with credentials, query strings, or fragments are rejected.
|
|
83
|
+
|
|
84
|
+
Configuration precedence for `graphMcpEndpoint`:
|
|
85
|
+
|
|
86
|
+
1. `CHAIN_INSIGHTS_GRAPH_MCP_ENDPOINT` env var (`GRAPH_MCP_ENDPOINT` legacy alias also supported)
|
|
87
|
+
2. `cia config set graphMcpEndpoint ...` saved value
|
|
88
|
+
3. Local default `http://127.0.0.1:8012/mcp`
|
|
89
|
+
|
|
55
90
|
Check the configured endpoint and current GraphRAG MCP capabilities:
|
|
56
91
|
|
|
57
92
|
```bash
|
|
@@ -149,6 +184,9 @@ and local case state:
|
|
|
149
184
|
|
|
150
185
|
- `address_risk` starts a single-address screen with risk, behavior,
|
|
151
186
|
neighborhood context, and exchange exposure.
|
|
187
|
+
- `stake_insights` explains Bittensor coldkey-hotkey-netuid staking
|
|
188
|
+
relationships, aggregate stake movement amounts, top counterparties, first
|
|
189
|
+
and last activity, and source backend evidence.
|
|
152
190
|
- `track_funds` traces trusted victim/source funds through intermediaries to
|
|
153
191
|
exchange deposit candidates.
|
|
154
192
|
- `scam_topology` expands from a known victim incident into reviewable
|
package/bin/cli.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
// CJS shim
|
|
5
|
-
//
|
|
6
|
-
// (see references/get-shit-done/bin/gsd-sdk.js for the GSD precedent).
|
|
4
|
+
// CJS shim: bridges the npm bin entry to the ESM dist built by tsdown.
|
|
5
|
+
// Dynamic import() is the correct bridge pattern from CommonJS to ESM.
|
|
7
6
|
import('../dist/cli.mjs').catch((err) => {
|
|
8
7
|
console.error('Failed to load chain-insights:', err.message);
|
|
9
8
|
process.exit(1);
|
package/bin/install.cjs
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// Runs before node_modules exists; zero npm imports allowed.
|
|
6
6
|
// Extension is .cjs (not .js) because package.json has "type": "module" —
|
|
7
7
|
// a .js file would be treated as ESM and require() calls would crash.
|
|
8
|
-
// Adapted from GSD reference: references/get-shit-done/bin/install.js
|
|
9
8
|
|
|
10
9
|
const fs = require('fs');
|
|
11
10
|
const path = require('path');
|
|
@@ -100,7 +100,7 @@ function createApp() {
|
|
|
100
100
|
ts: Date.now()
|
|
101
101
|
}));
|
|
102
102
|
app.get("/status", async (c) => {
|
|
103
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
103
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
104
104
|
const config = await loadConfig();
|
|
105
105
|
return c.json({
|
|
106
106
|
dataDir: config.dataDir,
|
|
@@ -97,7 +97,7 @@ function createApp() {
|
|
|
97
97
|
ts: Date.now()
|
|
98
98
|
}));
|
|
99
99
|
app.get("/status", async (c) => {
|
|
100
|
-
const { loadConfig } = await import("./config-
|
|
100
|
+
const { loadConfig } = await import("./config-Drgc2HuF.mjs").then((n) => n.t);
|
|
101
101
|
const config = await loadConfig();
|
|
102
102
|
return c.json({
|
|
103
103
|
dataDir: config.dataDir,
|
|
@@ -152,4 +152,4 @@ function createApp() {
|
|
|
152
152
|
//#endregion
|
|
153
153
|
export { createApp as t };
|
|
154
154
|
|
|
155
|
-
//# sourceMappingURL=app-
|
|
155
|
+
//# sourceMappingURL=app-CRd39JJ8.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-DdWQF_zb.mjs","names":[],"sources":["../src/server/app.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport { lstat, readFile, readdir, realpath } from 'node:fs/promises'\nimport path from 'node:path'\nimport os from 'node:os'\n\nconst WORKSPACE_TREE_ROOTS = ['cases', 'reports', '.chain-insights/schema']\nconst WORKSPACE_TREE_MAX_DEPTH = 4\n\ninterface WorkspaceTreeEntry {\n path: string\n type: 'file' | 'directory' | 'symlink'\n size?: number\n}\n\nfunction withinRoot(root: string, target: string): boolean {\n const relative = path.relative(path.resolve(root), path.resolve(target))\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))\n}\n\nasync function realPathWithinRoot(root: string, target: string): Promise<boolean> {\n try {\n const [realRoot, realTarget] = await Promise.all([realpath(root), realpath(target)])\n return withinRoot(realRoot, realTarget)\n } catch {\n return false\n }\n}\n\nfunction toWorkspaceRelative(root: string, target: string): string {\n return path.relative(root, target).split(path.sep).join('/')\n}\n\nasync function listWorkspaceEntries(\n workspaceRoot: string,\n roots = WORKSPACE_TREE_ROOTS,\n maxDepth = WORKSPACE_TREE_MAX_DEPTH\n): Promise<WorkspaceTreeEntry[]> {\n const entries: WorkspaceTreeEntry[] = []\n const root = path.resolve(workspaceRoot)\n\n async function visit(target: string, depth: number): Promise<void> {\n const resolved = path.resolve(target)\n if (!withinRoot(root, resolved)) return\n\n let info: Awaited<ReturnType<typeof lstat>>\n try {\n info = await lstat(resolved)\n } catch {\n return\n }\n\n const type = info.isSymbolicLink() ? 'symlink' : info.isDirectory() ? 'directory' : info.isFile() ? 'file' : null\n if (!type) return\n\n const entry: WorkspaceTreeEntry = {\n path: toWorkspaceRelative(root, resolved),\n type,\n }\n if (type === 'file') entry.size = info.size\n entries.push(entry)\n\n if (type !== 'directory' || depth >= maxDepth) return\n if (!await realPathWithinRoot(root, resolved)) return\n\n let children: string[]\n try {\n children = await readdir(resolved)\n } catch {\n return\n }\n\n for (const child of children.sort()) {\n await visit(path.join(resolved, child), depth + 1)\n }\n }\n\n for (const rootName of roots) {\n const target = path.resolve(root, rootName)\n if (withinRoot(root, target)) await visit(target, 0)\n }\n\n return entries\n}\n\nasync function findVizHtml(vizId: string): Promise<string | null> {\n const home = os.homedir()\n const filename = `${vizId}.html`\n\n // 1. Check central standalone directory first (fast, single path)\n const centralPath = path.join(home, '.chain-insights', 'viz', filename)\n try {\n return await readFile(centralPath, 'utf-8')\n } catch { /* not found here, continue */ }\n\n // 2. Check per-case directory using vizId prefix (case-based vizs use <caseId>_<timestamp>)\n // The vizId for case-based vizs is formatted as <case-id>_<timestamp>,\n // so extract the case-id prefix to check its directory first.\n const underscoreIdx = vizId.lastIndexOf('_')\n if (underscoreIdx > 0) {\n const possibleCaseId = vizId.substring(0, underscoreIdx)\n const casePath = path.join(home, '.chain-insights', 'cases', possibleCaseId, 'viz', filename)\n try {\n return await readFile(casePath, 'utf-8')\n } catch { /* not found here, continue */ }\n }\n\n // 3. Fallback: scan all case directories (CONTEXT.md: ~/.chain-insights/cases/<case-id>/viz/)\n const casesDir = path.join(home, '.chain-insights', 'cases')\n try {\n const cases = await readdir(casesDir)\n for (const caseId of cases) {\n const casePath = path.join(casesDir, caseId, 'viz', filename)\n try {\n return await readFile(casePath, 'utf-8')\n } catch { /* not in this case dir */ }\n }\n } catch { /* cases dir doesn't exist */ }\n\n return null\n}\n\nfunction isSafeGraphReportFilename(filename: string): boolean {\n return (\n filename.endsWith('.graph.json') &&\n /^[A-Za-z0-9._-]+$/.test(filename) &&\n !filename.includes('..') &&\n !filename.includes('/') &&\n !filename.includes('\\\\')\n )\n}\n\nexport function createApp(): Hono {\n const app = new Hono()\n\n app.get('/health', (c) => c.json({ ok: true, ts: Date.now() }))\n\n app.get('/status', async (c) => {\n const { loadConfig } = await import('../config/index.js')\n const config = await loadConfig()\n return c.json({\n dataDir: config.dataDir,\n graphMcpMode: config.graphMcpMode,\n server: 'running',\n })\n })\n\n app.get('/viz/:id', async (c) => {\n const id = c.req.param('id')\n if (!/^[a-zA-Z0-9_-]+$/.test(id)) {\n return c.json({ error: 'Invalid visualization ID' }, 400)\n }\n const html = await findVizHtml(id)\n if (!html) {\n return c.json({ error: 'Visualization not found' }, 404)\n }\n return c.html(html)\n })\n\n app.get('/graph-reports/:filename', async (c) => {\n const filename = c.req.param('filename')\n if (!isSafeGraphReportFilename(filename)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const graphPath = path.resolve(paths.reportGraphsRoot, filename)\n if (!withinRoot(paths.reportGraphsRoot, graphPath)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n if (!await realPathWithinRoot(paths.reportGraphsRoot, graphPath)) {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n\n try {\n const graph = await readFile(graphPath, 'utf-8')\n return c.body(graph, 200, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n })\n } catch {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n })\n\n app.get('/graph-reports/*', (c) => {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n })\n\n app.get('/workspace/tree', async (c) => {\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const entries = await listWorkspaceEntries(paths.root, WORKSPACE_TREE_ROOTS)\n return c.json({\n schema: 'chain-insights.workspace-tree.v1',\n root: paths.root,\n entries,\n })\n })\n\n app.onError((err, c) => {\n console.error(err)\n return c.json({ error: 'Internal server error' }, 500)\n })\n\n return app\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app-CRd39JJ8.mjs","names":[],"sources":["../src/server/app.ts"],"sourcesContent":["import { Hono } from 'hono'\nimport { lstat, readFile, readdir, realpath } from 'node:fs/promises'\nimport path from 'node:path'\nimport os from 'node:os'\n\nconst WORKSPACE_TREE_ROOTS = ['cases', 'reports', '.chain-insights/schema']\nconst WORKSPACE_TREE_MAX_DEPTH = 4\n\ninterface WorkspaceTreeEntry {\n path: string\n type: 'file' | 'directory' | 'symlink'\n size?: number\n}\n\nfunction withinRoot(root: string, target: string): boolean {\n const relative = path.relative(path.resolve(root), path.resolve(target))\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))\n}\n\nasync function realPathWithinRoot(root: string, target: string): Promise<boolean> {\n try {\n const [realRoot, realTarget] = await Promise.all([realpath(root), realpath(target)])\n return withinRoot(realRoot, realTarget)\n } catch {\n return false\n }\n}\n\nfunction toWorkspaceRelative(root: string, target: string): string {\n return path.relative(root, target).split(path.sep).join('/')\n}\n\nasync function listWorkspaceEntries(\n workspaceRoot: string,\n roots = WORKSPACE_TREE_ROOTS,\n maxDepth = WORKSPACE_TREE_MAX_DEPTH\n): Promise<WorkspaceTreeEntry[]> {\n const entries: WorkspaceTreeEntry[] = []\n const root = path.resolve(workspaceRoot)\n\n async function visit(target: string, depth: number): Promise<void> {\n const resolved = path.resolve(target)\n if (!withinRoot(root, resolved)) return\n\n let info: Awaited<ReturnType<typeof lstat>>\n try {\n info = await lstat(resolved)\n } catch {\n return\n }\n\n const type = info.isSymbolicLink() ? 'symlink' : info.isDirectory() ? 'directory' : info.isFile() ? 'file' : null\n if (!type) return\n\n const entry: WorkspaceTreeEntry = {\n path: toWorkspaceRelative(root, resolved),\n type,\n }\n if (type === 'file') entry.size = info.size\n entries.push(entry)\n\n if (type !== 'directory' || depth >= maxDepth) return\n if (!await realPathWithinRoot(root, resolved)) return\n\n let children: string[]\n try {\n children = await readdir(resolved)\n } catch {\n return\n }\n\n for (const child of children.sort()) {\n await visit(path.join(resolved, child), depth + 1)\n }\n }\n\n for (const rootName of roots) {\n const target = path.resolve(root, rootName)\n if (withinRoot(root, target)) await visit(target, 0)\n }\n\n return entries\n}\n\nasync function findVizHtml(vizId: string): Promise<string | null> {\n const home = os.homedir()\n const filename = `${vizId}.html`\n\n // 1. Check central standalone directory first (fast, single path)\n const centralPath = path.join(home, '.chain-insights', 'viz', filename)\n try {\n return await readFile(centralPath, 'utf-8')\n } catch { /* not found here, continue */ }\n\n // 2. Check per-case directory using vizId prefix (case-based vizs use <caseId>_<timestamp>)\n // The vizId for case-based vizs is formatted as <case-id>_<timestamp>,\n // so extract the case-id prefix to check its directory first.\n const underscoreIdx = vizId.lastIndexOf('_')\n if (underscoreIdx > 0) {\n const possibleCaseId = vizId.substring(0, underscoreIdx)\n const casePath = path.join(home, '.chain-insights', 'cases', possibleCaseId, 'viz', filename)\n try {\n return await readFile(casePath, 'utf-8')\n } catch { /* not found here, continue */ }\n }\n\n // 3. Fallback: scan all case directories (CONTEXT.md: ~/.chain-insights/cases/<case-id>/viz/)\n const casesDir = path.join(home, '.chain-insights', 'cases')\n try {\n const cases = await readdir(casesDir)\n for (const caseId of cases) {\n const casePath = path.join(casesDir, caseId, 'viz', filename)\n try {\n return await readFile(casePath, 'utf-8')\n } catch { /* not in this case dir */ }\n }\n } catch { /* cases dir doesn't exist */ }\n\n return null\n}\n\nfunction isSafeGraphReportFilename(filename: string): boolean {\n return (\n filename.endsWith('.graph.json') &&\n /^[A-Za-z0-9._-]+$/.test(filename) &&\n !filename.includes('..') &&\n !filename.includes('/') &&\n !filename.includes('\\\\')\n )\n}\n\nexport function createApp(): Hono {\n const app = new Hono()\n\n app.get('/health', (c) => c.json({ ok: true, ts: Date.now() }))\n\n app.get('/status', async (c) => {\n const { loadConfig } = await import('../config/index.js')\n const config = await loadConfig()\n return c.json({\n dataDir: config.dataDir,\n graphMcpMode: config.graphMcpMode,\n server: 'running',\n })\n })\n\n app.get('/viz/:id', async (c) => {\n const id = c.req.param('id')\n if (!/^[a-zA-Z0-9_-]+$/.test(id)) {\n return c.json({ error: 'Invalid visualization ID' }, 400)\n }\n const html = await findVizHtml(id)\n if (!html) {\n return c.json({ error: 'Visualization not found' }, 404)\n }\n return c.html(html)\n })\n\n app.get('/graph-reports/:filename', async (c) => {\n const filename = c.req.param('filename')\n if (!isSafeGraphReportFilename(filename)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const graphPath = path.resolve(paths.reportGraphsRoot, filename)\n if (!withinRoot(paths.reportGraphsRoot, graphPath)) {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n }\n if (!await realPathWithinRoot(paths.reportGraphsRoot, graphPath)) {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n\n try {\n const graph = await readFile(graphPath, 'utf-8')\n return c.body(graph, 200, {\n 'Content-Type': 'application/json',\n 'Access-Control-Allow-Origin': '*',\n })\n } catch {\n return c.json({ error: 'Graph report not found' }, 404)\n }\n })\n\n app.get('/graph-reports/*', (c) => {\n return c.json({ error: 'Invalid graph report filename' }, 400)\n })\n\n app.get('/workspace/tree', async (c) => {\n const { workspaceOutputPaths } = await import('../workspace/output-root.js')\n const paths = workspaceOutputPaths()\n const entries = await listWorkspaceEntries(paths.root, WORKSPACE_TREE_ROOTS)\n return c.json({\n schema: 'chain-insights.workspace-tree.v1',\n root: paths.root,\n entries,\n })\n })\n\n app.onError((err, c) => {\n console.error(err)\n return c.json({ error: 'Internal server error' }, 500)\n })\n\n return app\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createApp } from "./app-
|
|
1
|
+
import { t as createApp } from "./app-CRd39JJ8.mjs";
|
|
2
2
|
import { serve } from "@hono/node-server";
|
|
3
3
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
4
4
|
//#region src/mcp/artifact-server.ts
|
|
@@ -45,4 +45,4 @@ async function ensureArtifactServer(port) {
|
|
|
45
45
|
//#endregion
|
|
46
46
|
export { ensureArtifactServer };
|
|
47
47
|
|
|
48
|
-
//# sourceMappingURL=artifact-server-
|
|
48
|
+
//# sourceMappingURL=artifact-server-CP6LXQ9d.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-server-
|
|
1
|
+
{"version":3,"file":"artifact-server-CP6LXQ9d.mjs","names":["delay"],"sources":["../src/mcp/artifact-server.ts"],"sourcesContent":["import { serve } from '@hono/node-server'\nimport { setTimeout as delay } from 'node:timers/promises'\nimport { createApp } from '../server/app.js'\n\ntype ArtifactServer = ReturnType<typeof serve>\n\nconst servers = new Map<number, ArtifactServer>()\n\nasync function isHealthy(port: number): Promise<boolean> {\n const controller = new AbortController()\n const timeout = setTimeout(() => controller.abort(), 500)\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n })\n return response.ok\n } catch {\n return false\n } finally {\n clearTimeout(timeout)\n }\n}\n\nasync function waitUntilHealthy(port: number): Promise<void> {\n for (let attempt = 0; attempt < 20; attempt += 1) {\n if (await isHealthy(port)) return\n await delay(50)\n }\n throw new Error(`Graph report server did not become healthy on 127.0.0.1:${port}`)\n}\n\nexport async function ensureArtifactServer(port: number): Promise<void> {\n if (servers.has(port)) return\n if (await isHealthy(port)) return\n\n const app = createApp()\n const server = serve({\n fetch: app.fetch,\n hostname: '127.0.0.1',\n port,\n })\n servers.set(port, server)\n server.on('error', (err) => {\n servers.delete(port)\n process.stderr.write(`Chain Insights graph report server failed on 127.0.0.1:${port}: ${(err as Error).message}\\n`)\n })\n\n try {\n await waitUntilHealthy(port)\n } catch (err) {\n servers.delete(port)\n server.close()\n throw err\n }\n}\n\nexport function closeArtifactServers(): void {\n for (const [port, server] of servers.entries()) {\n server.close()\n servers.delete(port)\n }\n}\n"],"mappings":";;;;AAMA,MAAM,0BAAU,IAAI,IAA4B;AAEhD,eAAe,UAAU,MAAgC;CACvD,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,UAAU,iBAAiB,WAAW,MAAM,GAAG,GAAG;CACxD,IAAI;EAIF,QAAO,MAHgB,MAAM,oBAAoB,KAAK,UAAU,EAC9D,QAAQ,WAAW,OACrB,CAAC,GACe;CAClB,QAAQ;EACN,OAAO;CACT,UAAU;EACR,aAAa,OAAO;CACtB;AACF;AAEA,eAAe,iBAAiB,MAA6B;CAC3D,KAAK,IAAI,UAAU,GAAG,UAAU,IAAI,WAAW,GAAG;EAChD,IAAI,MAAM,UAAU,IAAI,GAAG;EAC3B,MAAMA,aAAM,EAAE;CAChB;CACA,MAAM,IAAI,MAAM,2DAA2D,MAAM;AACnF;AAEA,eAAsB,qBAAqB,MAA6B;CACtE,IAAI,QAAQ,IAAI,IAAI,GAAG;CACvB,IAAI,MAAM,UAAU,IAAI,GAAG;CAG3B,MAAM,SAAS,MAAM;EACnB,OAFU,UAED,EAAE;EACX,UAAU;EACV;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,MAAM;CACxB,OAAO,GAAG,UAAU,QAAQ;EAC1B,QAAQ,OAAO,IAAI;EACnB,QAAQ,OAAO,MAAM,0DAA0D,KAAK,IAAK,IAAc,QAAQ,GAAG;CACpH,CAAC;CAED,IAAI;EACF,MAAM,iBAAiB,IAAI;CAC7B,SAAS,KAAK;EACZ,QAAQ,OAAO,IAAI;EACnB,OAAO,MAAM;EACb,MAAM;CACR;AACF"}
|
package/dist/cli.cjs
CHANGED
|
@@ -71,7 +71,7 @@ function optionalScamTopologyActivityPolicy(value) {
|
|
|
71
71
|
throw new Error("activity_policy must be one of: node_relative_only, global_incident_only");
|
|
72
72
|
}
|
|
73
73
|
async function withGraphMcpClient(name, fn) {
|
|
74
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
74
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
75
75
|
const config = await loadConfig();
|
|
76
76
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-DPc2eyVN.cjs")).then((n) => n.client_exports);
|
|
77
77
|
const paymentFetch = await createConfiguredGraphMcpFetch(config);
|
|
@@ -92,7 +92,7 @@ function printMcpTextContent(result) {
|
|
|
92
92
|
for (const item of result.content ?? []) if (item.type === "text") console.log(item.text);
|
|
93
93
|
}
|
|
94
94
|
async function printNetworkCapabilities(opts) {
|
|
95
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
95
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
96
96
|
const { fetchNetworkCapabilities, formatNetworkCapabilities } = await Promise.resolve().then(() => require("./capabilities-Bm0JDbV7.cjs"));
|
|
97
97
|
const document = await fetchNetworkCapabilities(await loadConfig());
|
|
98
98
|
if (opts.json) console.log(JSON.stringify(document, null, 2));
|
|
@@ -110,7 +110,7 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
110
110
|
try {
|
|
111
111
|
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
|
|
112
112
|
const workspaceRoot = requireWorkspaceRoot();
|
|
113
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
113
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-BqVdWath.cjs")).then((n) => n.server_exports);
|
|
114
114
|
console.log(`Workspace: ${workspaceRoot}`);
|
|
115
115
|
startServer(parseInt(opts.port, 10));
|
|
116
116
|
} catch (err) {
|
|
@@ -119,7 +119,7 @@ program.command("serve").description("Start local visualization server").option(
|
|
|
119
119
|
}
|
|
120
120
|
});
|
|
121
121
|
program.command("status").description("Show toolkit status and configuration").action(async () => {
|
|
122
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
122
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
123
123
|
const { findActiveWorkspace, activeDataDir } = await Promise.resolve().then(() => require("./active-BVr55kvW.cjs")).then((n) => n.active_exports);
|
|
124
124
|
const config = await loadConfig();
|
|
125
125
|
const workspace = findActiveWorkspace();
|
|
@@ -132,7 +132,7 @@ program.command("status").description("Show toolkit status and configuration").a
|
|
|
132
132
|
});
|
|
133
133
|
program.command("debug").description("Configure Graph MCP debug mode").addCommand(new commander.Command("on").description("Enable Graph MCP debug mode without x402 payments").requiredOption("--token <token>", "Debug bearer token").option("--endpoint <url>", "Graph MCP endpoint").action(async (opts) => {
|
|
134
134
|
try {
|
|
135
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
135
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
136
136
|
await saveConfig({
|
|
137
137
|
graphMcpMode: "debug",
|
|
138
138
|
graphMcpAuthToken: opts.token,
|
|
@@ -147,7 +147,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
147
147
|
}
|
|
148
148
|
})).addCommand(new commander.Command("off").description("Disable Graph MCP debug mode and use paid x402 calls").action(async () => {
|
|
149
149
|
try {
|
|
150
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
150
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
151
151
|
await saveConfig({
|
|
152
152
|
graphMcpMode: "paid",
|
|
153
153
|
graphMcpAuthToken: ""
|
|
@@ -160,7 +160,7 @@ program.command("debug").description("Configure Graph MCP debug mode").addComman
|
|
|
160
160
|
}
|
|
161
161
|
})).addCommand(new commander.Command("status").description("Show Graph MCP payment/debug mode").action(async () => {
|
|
162
162
|
try {
|
|
163
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
163
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
164
164
|
const config = await loadConfig();
|
|
165
165
|
console.log(`Graph MCP mode: ${config.graphMcpMode}`);
|
|
166
166
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
@@ -175,7 +175,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
175
175
|
try {
|
|
176
176
|
const normalizedKey = key.trim();
|
|
177
177
|
if (!normalizedKey) throw new Error("Test access key is required");
|
|
178
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
178
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
179
179
|
await saveConfig({
|
|
180
180
|
graphMcpMode: "debug",
|
|
181
181
|
graphMcpAuthToken: normalizedKey,
|
|
@@ -190,7 +190,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
190
190
|
}
|
|
191
191
|
})).addCommand(new commander.Command("clear").description("Remove the Graph MCP test access key and use paid x402 calls").action(async () => {
|
|
192
192
|
try {
|
|
193
|
-
const { saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
193
|
+
const { saveConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
194
194
|
await saveConfig({
|
|
195
195
|
graphMcpMode: "paid",
|
|
196
196
|
graphMcpAuthToken: ""
|
|
@@ -203,7 +203,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
203
203
|
}
|
|
204
204
|
})).addCommand(new commander.Command("status").description("Show Graph MCP test access key status").action(async () => {
|
|
205
205
|
try {
|
|
206
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
206
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
207
207
|
const config = await loadConfig();
|
|
208
208
|
console.log(`Graph endpoint: ${config.graphMcpEndpoint}`);
|
|
209
209
|
console.log(`Access key: ${config.graphMcpAuthToken?.trim() ? "configured" : "not configured"}`);
|
|
@@ -215,7 +215,7 @@ program.command("access-key").description("Configure Graph MCP test access key m
|
|
|
215
215
|
}));
|
|
216
216
|
program.command("init").description("Initialize an investigation workspace").argument("[dir]", "Workspace directory to initialize", ".").option("--force", "Overwrite existing workspace files").action(async (dir, opts) => {
|
|
217
217
|
try {
|
|
218
|
-
const { initWorkspace } = await Promise.resolve().then(() => require("./init-
|
|
218
|
+
const { initWorkspace } = await Promise.resolve().then(() => require("./init-TCQY5RDJ.cjs"));
|
|
219
219
|
const result = await initWorkspace({
|
|
220
220
|
targetDir: dir,
|
|
221
221
|
force: opts.force
|
|
@@ -250,8 +250,8 @@ program.command("setup").description("Configure external MCP clients").addComman
|
|
|
250
250
|
}
|
|
251
251
|
}));
|
|
252
252
|
program.command("config").description("Read or write configuration values").addCommand(new commander.Command("get").argument("<key>", "Config key to read").action(async (key) => {
|
|
253
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
254
|
-
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-
|
|
253
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
254
|
+
const { CONFIG_KEYS } = await Promise.resolve().then(() => require("./schema-Vl9yuOFO.cjs")).then((n) => n.schema_exports);
|
|
255
255
|
if (!CONFIG_KEYS.includes(key)) {
|
|
256
256
|
console.error(`Unknown config key: ${key}`);
|
|
257
257
|
process.exit(1);
|
|
@@ -271,8 +271,8 @@ program.command("config").description("Read or write configuration values").addC
|
|
|
271
271
|
}
|
|
272
272
|
return;
|
|
273
273
|
}
|
|
274
|
-
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-
|
|
275
|
-
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-
|
|
274
|
+
const { loadConfig, saveConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
275
|
+
const { CONFIG_KEYS, DEFAULT_CONFIG } = await Promise.resolve().then(() => require("./schema-Vl9yuOFO.cjs")).then((n) => n.schema_exports);
|
|
276
276
|
const current = await loadConfig();
|
|
277
277
|
if (!CONFIG_KEYS.includes(key)) {
|
|
278
278
|
console.error(`Unknown config key: ${key}`);
|
|
@@ -305,7 +305,7 @@ program.command("wallet").description("Manage the local Base USDC payment wallet
|
|
|
305
305
|
})).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) => {
|
|
306
306
|
try {
|
|
307
307
|
const { buildTopupInfo, getWalletAccount } = await Promise.resolve().then(() => require("./tools-DY8h0WbE.cjs")).then((n) => n.tools_exports);
|
|
308
|
-
const { startTopupServer } = await Promise.resolve().then(() => require("./topup-server-
|
|
308
|
+
const { startTopupServer } = await Promise.resolve().then(() => require("./topup-server-yAaXYkJP.cjs")).then((n) => n.topup_server_exports);
|
|
309
309
|
const account = await getWalletAccount();
|
|
310
310
|
const url = await startTopupServer(account);
|
|
311
311
|
const info = buildTopupInfo(account.address, url);
|
|
@@ -338,7 +338,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
338
338
|
const { loadSchema, saveSchema } = await Promise.resolve().then(() => require("./schema-cache-CJk1EL3L.cjs"));
|
|
339
339
|
const { formatToolsTable } = await Promise.resolve().then(() => require("./format-9NLBykEL.cjs"));
|
|
340
340
|
const { visibleRemoteTools } = await Promise.resolve().then(() => require("./tool-visibility-iAVQV3t0.cjs")).then((n) => n.tool_visibility_exports);
|
|
341
|
-
const { loadConfig } = await Promise.resolve().then(() => require("./config-
|
|
341
|
+
const { loadConfig } = await Promise.resolve().then(() => require("./config-BwVx19Og.cjs")).then((n) => n.config_exports);
|
|
342
342
|
const { createConfiguredGraphMcpFetch, resolveGraphMcpEndpoint } = await Promise.resolve().then(() => require("./client-DPc2eyVN.cjs")).then((n) => n.client_exports);
|
|
343
343
|
const config = await loadConfig();
|
|
344
344
|
const graphMcpEndpoint = resolveGraphMcpEndpoint(config);
|
|
@@ -378,7 +378,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
378
378
|
}));
|
|
379
379
|
return;
|
|
380
380
|
}
|
|
381
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
381
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
382
382
|
const result = await addressRisk(client, {
|
|
383
383
|
address: opts.address,
|
|
384
384
|
network: opts.network,
|
|
@@ -406,7 +406,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
406
406
|
}));
|
|
407
407
|
return;
|
|
408
408
|
}
|
|
409
|
-
const { trackFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
409
|
+
const { trackFunds } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
410
410
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
411
411
|
const result = await trackFunds(client, config, {
|
|
412
412
|
trustedAddresses: opts.trustedAddresses,
|
|
@@ -429,7 +429,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
429
429
|
const { requireWorkspaceRoot } = await Promise.resolve().then(() => require("./output-root-YIbl6PwF.cjs")).then((n) => n.output_root_exports);
|
|
430
430
|
requireWorkspaceRoot();
|
|
431
431
|
await withGraphMcpClient("chain-insights-cli-scam-topology", async (client, config) => {
|
|
432
|
-
const { scamTopology } = await Promise.resolve().then(() => require("./public-tools-
|
|
432
|
+
const { scamTopology } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
433
433
|
const incidentTimestampMs = optionalNumber(opts.incidentTimestampMs);
|
|
434
434
|
if (incidentTimestampMs === void 0) throw new Error("incident-timestamp-ms is required");
|
|
435
435
|
const caseId = opts.case ? await resolveCaseSelector(opts.case) : void 0;
|
|
@@ -448,6 +448,29 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
448
448
|
console.error(err.message);
|
|
449
449
|
process.exit(1);
|
|
450
450
|
}
|
|
451
|
+
})).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) => {
|
|
452
|
+
try {
|
|
453
|
+
await withGraphMcpClient("chain-insights-cli-stake-insights", async (client) => {
|
|
454
|
+
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
455
|
+
const result = await stakeInsights(client, {
|
|
456
|
+
network: opts.network,
|
|
457
|
+
address: opts.address,
|
|
458
|
+
coldkey: opts.coldkey,
|
|
459
|
+
hotkey: opts.hotkey,
|
|
460
|
+
netuid: optionalNumber(opts.netuid),
|
|
461
|
+
startTimestampMs: optionalNumber(opts.startTimestampMs),
|
|
462
|
+
endTimestampMs: optionalNumber(opts.endTimestampMs),
|
|
463
|
+
startBlock: optionalNumber(opts.startBlock),
|
|
464
|
+
endBlock: optionalNumber(opts.endBlock),
|
|
465
|
+
depth: optionalNumber(opts.depth)
|
|
466
|
+
});
|
|
467
|
+
console.log(result.summaryText);
|
|
468
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
469
|
+
});
|
|
470
|
+
} catch (err) {
|
|
471
|
+
console.error(err.message);
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
451
474
|
})).addCommand(new commander.Command("call").description("Call an MCP tool directly (debug)").argument("<tool>", "Tool name to call").argument("[args...]", "Key=value arguments (e.g. address=0x1234 chain=ethereum)").action(async (tool, rawArgs) => {
|
|
452
475
|
try {
|
|
453
476
|
const { parseMcpCallArgs } = await Promise.resolve().then(() => require("./call-args-CcUV6gFS.cjs"));
|
|
@@ -456,7 +479,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
456
479
|
assertPublicMcpToolName(tool);
|
|
457
480
|
await withGraphMcpClient("chain-insights-cli-call", async (client, config) => {
|
|
458
481
|
if (tool === "address_risk") {
|
|
459
|
-
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-
|
|
482
|
+
const { addressRisk } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
460
483
|
const result = await addressRisk(client, {
|
|
461
484
|
address: String(args["address"] ?? ""),
|
|
462
485
|
network: String(args["network"] ?? ""),
|
|
@@ -466,7 +489,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
466
489
|
return;
|
|
467
490
|
}
|
|
468
491
|
if (tool === "track_funds") {
|
|
469
|
-
const { trackFunds } = await Promise.resolve().then(() => require("./public-tools-
|
|
492
|
+
const { trackFunds } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
470
493
|
const result = await trackFunds(client, config, {
|
|
471
494
|
trustedAddresses: args["trusted_addresses"] ?? "",
|
|
472
495
|
untrustedAddresses: args["untrusted_addresses"],
|
|
@@ -481,7 +504,7 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
481
504
|
return;
|
|
482
505
|
}
|
|
483
506
|
if (tool === "scam_topology") {
|
|
484
|
-
const { scamTopology } = await Promise.resolve().then(() => require("./public-tools-
|
|
507
|
+
const { scamTopology } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
485
508
|
const victimAddress = String(args["victim_address"] ?? "").trim();
|
|
486
509
|
if (!victimAddress) throw new Error("victim_address is required");
|
|
487
510
|
const incidentTimestampMs = optionalNumberArg(args["incident_timestamp_ms"], "incident_timestamp_ms");
|
|
@@ -498,6 +521,24 @@ program.command("mcp").description("Interact with the Chain Insights MCP endpoin
|
|
|
498
521
|
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
499
522
|
return;
|
|
500
523
|
}
|
|
524
|
+
if (tool === "stake_insights") {
|
|
525
|
+
const { stakeInsights } = await Promise.resolve().then(() => require("./public-tools-BC1fi0DV.cjs"));
|
|
526
|
+
const result = await stakeInsights(client, {
|
|
527
|
+
network: String(args["network"] ?? ""),
|
|
528
|
+
address: args["address"] === void 0 ? void 0 : String(args["address"]),
|
|
529
|
+
coldkey: args["coldkey"] === void 0 ? void 0 : String(args["coldkey"]),
|
|
530
|
+
hotkey: args["hotkey"] === void 0 ? void 0 : String(args["hotkey"]),
|
|
531
|
+
netuid: optionalNumberArg(args["netuid"], "netuid"),
|
|
532
|
+
startTimestampMs: optionalNumberArg(args["start_timestamp_ms"], "start_timestamp_ms"),
|
|
533
|
+
endTimestampMs: optionalNumberArg(args["end_timestamp_ms"], "end_timestamp_ms"),
|
|
534
|
+
startBlock: optionalNumberArg(args["start_block"], "start_block"),
|
|
535
|
+
endBlock: optionalNumberArg(args["end_block"], "end_block"),
|
|
536
|
+
depth: optionalNumberArg(args["depth"] ?? args["max_hops"], "depth")
|
|
537
|
+
});
|
|
538
|
+
console.log(result.summaryText);
|
|
539
|
+
console.log(JSON.stringify(result.structuredContent, null, 2));
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
501
542
|
printMcpTextContent(await client.callTool({
|
|
502
543
|
name: tool,
|
|
503
544
|
arguments: args
|
|
@@ -681,7 +722,7 @@ program.command("playbook").description("Run and manage investigation playbooks"
|
|
|
681
722
|
console.error(`Invalid --from value: "${opts.from}". Must be a positive integer.`);
|
|
682
723
|
process.exit(1);
|
|
683
724
|
}
|
|
684
|
-
const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-
|
|
725
|
+
const { PlaybookRunner } = await Promise.resolve().then(() => require("./runner-ZYowxCVl.cjs"));
|
|
685
726
|
await PlaybookRunner.run(definition, {
|
|
686
727
|
caseId: opts.case,
|
|
687
728
|
from: fromN,
|
|
@@ -736,7 +777,7 @@ program.command("viz").description("Generate money flow visualization").argument
|
|
|
736
777
|
caseId,
|
|
737
778
|
dataFile: opts.data
|
|
738
779
|
});
|
|
739
|
-
const { startServer } = await Promise.resolve().then(() => require("./server-
|
|
780
|
+
const { startServer } = await Promise.resolve().then(() => require("./server-BqVdWath.cjs")).then((n) => n.server_exports);
|
|
740
781
|
const port = parseInt(opts.port, 10);
|
|
741
782
|
startServer(port);
|
|
742
783
|
const url = `http://127.0.0.1:${port}/viz/${result.vizId}`;
|